From 34404caeb6b159e9ad040d8213849a9eb6f908aa Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Mon, 12 Jul 2021 13:45:49 -0400
Subject: Revert "Schema view En-Hua — added ability to type strings in without
 quotes, as well as formatting reflecting nested containers"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/client/views/nodes/DocumentContentsView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index ecf4c0901..f0a54e4ac 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -8,7 +8,7 @@ import { emptyPath, OmitKeys, Without } from "../../../Utils";
 import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { CollectionSchemaView } from "../collections/schemaView/CollectionSchemaView";
+import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
 import { InkingStroke } from "../InkingStroke";
 import { PresElementBox } from "../presentationview/PresElementBox";
-- 
cgit v1.2.3-70-g09d2


From 21c5e8d623fccc4d750e202eba501587bc1a1f16 Mon Sep 17 00:00:00 2001
From: geireann <geireann_lindfield_roberts@brown.edu>
Date: Mon, 12 Jul 2021 13:57:08 -0400
Subject: Revert "Merge pull request #13 from
 brown-dash/revert-12-schema-view-En-Hua"

This reverts commit ac561d34fa56584a10c401900e76a8a2e06a0cf6, reversing
changes made to 0443cb9267d808513e181e3130d69dde8e73018e.
---
 .idea/.gitignore                                   |   3 +
 .idea/Dash-Web.iml                                 |   9 +
 .idea/modules.xml                                  |   8 +
 .idea/vcs.xml                                      |   6 +
 src/client/util/SelectionManager.ts                |   2 +-
 .../views/collections/CollectionSchemaCells.tsx    | 529 -----------------
 .../views/collections/CollectionSchemaHeaders.tsx  | 518 -----------------
 .../CollectionSchemaMovableTableHOC.tsx            | 258 ---------
 .../views/collections/CollectionSchemaView.scss    | 641 ---------------------
 .../views/collections/CollectionSchemaView.tsx     | 575 ------------------
 src/client/views/collections/CollectionView.tsx    |   2 +-
 src/client/views/collections/SchemaTable.tsx       | 599 -------------------
 .../schemaView/CollectionSchemaCells.tsx           | 585 +++++++++++++++++++
 .../schemaView/CollectionSchemaHeaders.tsx         | 518 +++++++++++++++++
 .../schemaView/CollectionSchemaMovableColumn.tsx   | 128 ++++
 .../schemaView/CollectionSchemaMovableRow.tsx      | 147 +++++
 .../schemaView/CollectionSchemaView.scss           | 552 ++++++++++++++++++
 .../schemaView/CollectionSchemaView.tsx            | 575 ++++++++++++++++++
 .../views/collections/schemaView/SchemaTable.tsx   | 601 +++++++++++++++++++
 src/client/views/nodes/DocumentContentsView.tsx    |   2 +-
 src/client/views/search/SearchBox.tsx              |   4 +-
 src/fields/SchemaHeaderField.ts                    |   2 +-
 22 files changed, 3138 insertions(+), 3126 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 .idea/Dash-Web.iml
 create mode 100644 .idea/modules.xml
 create mode 100644 .idea/vcs.xml
 delete mode 100644 src/client/views/collections/CollectionSchemaCells.tsx
 delete mode 100644 src/client/views/collections/CollectionSchemaHeaders.tsx
 delete mode 100644 src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
 delete mode 100644 src/client/views/collections/CollectionSchemaView.scss
 delete mode 100644 src/client/views/collections/CollectionSchemaView.tsx
 delete mode 100644 src/client/views/collections/SchemaTable.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaCells.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaView.scss
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaView.tsx
 create mode 100644 src/client/views/collections/schemaView/SchemaTable.tsx

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..26d33521a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/Dash-Web.iml b/.idea/Dash-Web.iml
new file mode 100644
index 000000000..d6ebd4805
--- /dev/null
+++ b/.idea/Dash-Web.iml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..35c51c015
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/Dash-Web.iml" filepath="$PROJECT_DIR$/.idea/Dash-Web.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index ca5ef75d2..a624d5b7c 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,7 +1,7 @@
 import { action, observable, ObservableMap } from "mobx";
 import { computedFn } from "mobx-utils";
 import { Doc, Opt } from "../../fields/Doc";
-import { CollectionSchemaView } from "../views/collections/CollectionSchemaView";
+import { CollectionSchemaView } from "../views/collections/schemaView/CollectionSchemaView";
 import { CollectionViewType } from "../views/collections/CollectionView";
 import { DocumentView } from "../views/nodes/DocumentView";
 
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
deleted file mode 100644
index 2e6186680..000000000
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ /dev/null
@@ -1,529 +0,0 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import { CellInfo } from "react-table";
-import "react-table/react-table.css";
-import { DateField } from "../../../fields/DateField";
-import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { ComputedField } from "../../../fields/ScriptField";
-import { BoolCast, Cast, DateCast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
-import { ImageField } from "../../../fields/URLField";
-import { Utils, emptyFunction } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager } from "../../util/DragManager";
-import { KeyCodes } from "../../util/KeyCodes";
-import { CompileScript } from "../../util/Scripting";
-import { SearchUtil } from "../../util/SearchUtil";
-import { SnappingManager } from "../../util/SnappingManager";
-import { undoBatch } from "../../util/UndoManager";
-import '../DocumentDecorations.scss';
-import { EditableView } from "../EditableView";
-import { MAX_ROW_HEIGHT } from '../globalCssVariables.scss';
-import { DocumentIconContainer } from "../nodes/DocumentIcon";
-import { OverlayView } from "../OverlayView";
-import "./CollectionSchemaView.scss";
-import { CollectionView } from "./CollectionView";
-const path = require('path');
-
-export interface CellProps {
-    row: number;
-    col: number;
-    rowProps: CellInfo;
-    CollectionView: Opt<CollectionView>;
-    ContainingCollection: Opt<CollectionView>;
-    Document: Doc;
-    fieldKey: string;
-    renderDepth: number;
-    addDocTab: (document: Doc, where: string) => boolean;
-    pinToPres: (document: Doc) => void;
-    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined,
-        addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    isFocused: boolean;
-    changeFocusedCellByIndex: (row: number, col: number) => void;
-    setIsEditing: (isEditing: boolean) => void;
-    isEditable: boolean;
-    setPreviewDoc: (doc: Doc) => void;
-    setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean;
-    getField: (row: number, col?: number) => void;
-    showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void;
-}
-
-@observer
-export class CollectionSchemaCell extends React.Component<CellProps> {
-    public static resolvedFieldKey(column: string, rowDoc: Doc) {
-        const fieldKey = column;
-        if (fieldKey.startsWith("*")) {
-            const rootKey = fieldKey.substring(1);
-            const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))];
-            const matchedKeys = allKeys.filter(key => key.includes(rootKey));
-            if (matchedKeys.length) return matchedKeys[0];
-        }
-        return fieldKey;
-    }
-    @observable protected _isEditing: boolean = false;
-    protected _focusRef = React.createRef<HTMLDivElement>();
-    protected _rowDoc = this.props.rowProps.original;
-    protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original);
-    protected _dropDisposer?: DragManager.DragDropDisposer;
-    @observable contents: string = "";
-
-    componentDidMount() { document.addEventListener("keydown", this.onKeyDown); }
-    componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); }
-
-    @action
-    onKeyDown = (e: KeyboardEvent): void => {
-        if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) {
-            document.removeEventListener("keydown", this.onKeyDown);
-            this._isEditing = true;
-            this.props.setIsEditing(true);
-        }
-    }
-
-    @action
-    isEditingCallback = (isEditing: boolean): void => {
-        document.removeEventListener("keydown", this.onKeyDown);
-        isEditing && document.addEventListener("keydown", this.onKeyDown);
-        this._isEditing = isEditing;
-        this.props.setIsEditing(isEditing);
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-    }
-
-    @action
-    onPointerDown = async (e: React.PointerEvent): Promise<void> => {
-        this.onItemDown(e);
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-        this.props.setPreviewDoc(this.props.rowProps.original);
-
-        let url: string;
-        if (url = StrCast(this.props.rowProps.row.href)) {
-            try {
-                new URL(url);
-                const temp = window.open(url)!;
-                temp.blur();
-                window.focus();
-            } catch { }
-        }
-
-        const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null);
-        doc && this.props.setPreviewDoc(doc);
-    }
-
-    @undoBatch
-    applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => {
-        const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) });
-        if (!res.success) return false;
-        doc[this.renderFieldKey] = res.result;
-        return true;
-    }
-
-    private drop = (e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.docDragData) {
-            if (de.complete.docDragData.draggedDocuments.length === 1) {
-                this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0];
-            }
-            else {
-                const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {});
-                this._rowDataDoc[this.renderFieldKey] = coll;
-            }
-            e.stopPropagation();
-        }
-    }
-
-    protected dropRef = (ele: HTMLElement | null) => {
-        this._dropDisposer?.();
-        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
-    }
-
-    returnHighlights(contents: string, positions?: number[]) {
-        if (positions) {
-            const results = [];
-            StrCast(this.props.Document._searchString);
-            const length = StrCast(this.props.Document._searchString).length;
-            const color = contents ? "black" : "grey";
-
-            results.push(<span key="-1" style={{ color }}>{contents?.slice(0, positions[0])}</span>);
-            positions.forEach((num, cur) => {
-                results.push(<span key={"start" + cur} style={{ backgroundColor: "#FFFF00", color }}>{contents?.slice(num, num + length)}</span>);
-                let end = 0;
-                cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
-                results.push(<span key={"end" + cur} style={{ color }}>{contents?.slice(num + length, end)}</span>);
-            }
-            );
-            return results;
-        }
-        return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
-    }
-
-    @computed get renderFieldKey() { return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); }
-    onItemDown = async (e: React.PointerEvent) => {
-        if (this.props.Document._searchDoc) {
-            const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
-            const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
-            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext,
-                undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc));
-        }
-    }
-    renderCellWithType(type: string | undefined) {
-        const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-
-        const fieldKey = this.renderFieldKey;
-        const field = this._rowDoc[fieldKey];
-
-        const onPointerEnter = (e: React.PointerEvent): void => {
-            if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
-                dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over";
-            }
-        };
-        const onPointerLeave = (e: React.PointerEvent): void => {
-            dragRef.current!.className = "collectionSchemaView-cellContainer";
-        };
-
-        let contents = Field.toString(field as Field);
-        contents = contents === "" ? "--" : contents;
-
-        let className = "collectionSchemaView-cellWrapper";
-        if (this._isEditing) className += " editing";
-        if (this.props.isFocused && this.props.isEditable) className += " focused";
-        if (this.props.isFocused && !this.props.isEditable) className += " inactive";
-
-        const positions = [];
-        if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
-            let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase();
-            const search = StrCast(this.props.Document._searchString).toLowerCase();
-            let start = term.indexOf(search);
-            let tally = 0;
-            if (start !== -1) {
-                positions.push(start);
-            }
-            while (start < contents?.length && start !== -1) {
-                term = term.slice(start + search.length + 1);
-                tally += start + search.length + 1;
-                start = term.indexOf(search);
-                positions.push(tally + start);
-            }
-            if (positions.length > 1) {
-                positions.pop();
-            }
-        }
-        const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
-        return (
-            <div className="collectionSchemaView-cellContainer" style={{ cursor: field instanceof Doc ? "grab" : "auto" }}
-                ref={dragRef} onPointerDown={this.onPointerDown} onClick={action(e => this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
-                <div className={className} ref={this._focusRef} tabIndex={-1}>
-                    <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null}>
-                        {!this.props.Document._searchDoc ?
-                            <EditableView
-                                editing={this._isEditing}
-                                isEditingCallback={this.isEditingCallback}
-                                display={"inline"}
-                                contents={contents}
-                                height={"auto"}
-                                maxHeight={Number(MAX_ROW_HEIGHT)}
-                                placeholder={placeholder}
-                                GetValue={() => {
-                                    const cfield = ComputedField.WithoutComputed(() => FieldValue(field));
-                                    const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
-                                    const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
-                                    return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
-                                        Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
-                                }}
-                                SetValue={action((value: string) => {
-                                    let retVal = false;
-                                    if (value.startsWith(":=") || value.startsWith("=:=")) {
-                                        const script = value.substring(value.startsWith("=:=") ? 3 : 2);
-                                        retVal = this.props.setComputed(script, value.startsWith(":=") ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col);
-                                    } else {
-                                        const inputscript = value.substring(value.startsWith("=") ? 1 : 0);
-                                        const script = CompileScript(inputscript, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
-                                        script.compiled && (retVal = this.applyToDoc(inputscript.length !== value.length ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
-                                    }
-                                    if (retVal) {
-                                        this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
-                                        this.props.setIsEditing(false);
-                                    }
-                                    return retVal;
-                                })}
-                                OnFillDown={async (value: string) => {
-                                    const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
-                                    script.compiled && DocListCast(this.props.Document[this.props.fieldKey]).
-                                        forEach((doc, i) => value.startsWith(":=") ?
-                                            this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) :
-                                            this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run));
-                                }}
-                            />
-                            :
-                            this.returnHighlights(contents, positions)
-                        }
-                    </div >
-                </div>
-            </div>
-        );
-    }
-
-    render() { return this.renderCellWithType(undefined); }
-}
-
-@observer
-export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } }
-
-@observer
-export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } }
-
-@observer
-export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } }
-
-@observer
-export class CollectionSchemaDateCell extends CollectionSchemaCell {
-    @computed get _date(): Opt<DateField> { return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; }
-
-    @action
-    handleChange = (date: any) => {
-        // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
-        // if (script.compiled) {
-        //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
-        // } else {
-        // ^ DateCast is always undefined for some reason, but that is what the field should be set to
-        this._rowDoc[this.renderFieldKey] = new DateField(date as Date);
-        //}
-    }
-
-    render() {
-        return !this.props.isFocused ? <span onPointerDown={this.onPointerDown}>{this._date ? Field.toString(this._date as Field) : "--"}</span> :
-            <DatePicker
-                selected={this._date?.date || new Date}
-                onSelect={date => this.handleChange(date)}
-                onChange={date => this.handleChange(date)}
-            />;
-    }
-}
-
-@observer
-export class CollectionSchemaDocCell extends CollectionSchemaCell {
-
-    _overlayDisposer?: () => void;
-
-    @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); }
-
-    @action
-    onSetValue = (value: string) => {
-        this._doc && (Doc.GetProto(this._doc).title = value);
-
-        const script = CompileScript(value, {
-            addReturn: true,
-            typecheck: false,
-            transformer: DocumentIconContainer.getTransformer()
-        });
-
-        const results = script.compiled && script.run();
-        if (results && results.success) {
-            this._rowDoc[this.renderFieldKey] = results.result;
-            return true;
-        }
-        return false;
-    }
-
-    componentWillUnmount() { this.onBlur(); }
-
-    onBlur = () => { this._overlayDisposer?.(); };
-    onFocus = () => {
-        this.onBlur();
-        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-    }
-
-    @action
-    isEditingCallback = (isEditing: boolean): void => {
-        document.removeEventListener("keydown", this.onKeyDown);
-        isEditing && document.addEventListener("keydown", this.onKeyDown);
-        this._isEditing = isEditing;
-        this.props.setIsEditing(isEditing);
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-    }
-
-    render() {
-        return !this._doc ? this.renderCellWithType("document") :
-            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1}
-                onPointerDown={this.onPointerDown}
-            >
-                <div className="collectionSchemaView-cellContents-document"
-                    style={{ padding: "5.9px" }}
-                    ref={this.dropRef}
-                    onFocus={this.onFocus}
-                    onBlur={this.onBlur}
-                >
-                    <EditableView
-                        editing={this._isEditing}
-                        isEditingCallback={this.isEditingCallback}
-                        display={"inline"}
-                        contents={this._doc.title || "--"}
-                        height={"auto"}
-                        maxHeight={Number(MAX_ROW_HEIGHT)}
-                        GetValue={() => StrCast(this._doc?.title)}
-                        SetValue={action((value: string) => {
-                            this.onSetValue(value);
-                            return true;
-                        })}
-                    />
-                </div >
-                <div onClick={() => this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton">
-                    <FontAwesomeIcon icon="external-link-alt" size="lg" />
-                </div>
-            </div>;
-    }
-}
-
-@observer
-export class CollectionSchemaImageCell extends CollectionSchemaCell {
-
-    choosePath(url: URL) {
-        if (url.protocol === "data") return url.href;
-        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
-        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here
-
-        const ext = path.extname(url.href);
-        return url.href.replace(ext, "_o" + path.extname(url.href));
-    }
-
-    render() {
-        const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
-        const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
-        const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
-        const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
-        const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
-
-        const aspect = Doc.NativeAspect(this._rowDoc);
-        let width = Math.min(75, this.props.rowProps.width);
-        const height = Math.min(75, width / aspect);
-        width = height * aspect;
-
-        const reference = React.createRef<HTMLDivElement>();
-        return <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-            <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
-                <img src={url[0]}
-                    width={paths.length ? width : "20px"}
-                    height={paths.length ? height : "20px"} />
-            </div >
-        </div>;
-    }
-}
-
-
-@observer
-export class CollectionSchemaListCell extends CollectionSchemaCell {
-    _overlayDisposer?: () => void;
-
-    @computed get _field() { return this._rowDoc[this.renderFieldKey]; }
-    @computed get _optionsList() { return this._field as List<any>; }
-    @observable private _opened = false;
-    @observable private _text = "select an item";
-    @observable private _selectedNum = 0;
-
-    @action
-    onSetValue = (value: string) => {
-        // change if its a document
-        this._optionsList[this._selectedNum] = this._text = value;
-
-        (this._field as List<any>).splice(this._selectedNum, 1, value);
-    }
-
-    @action
-    onSelected = (element: string, index: number) => {
-        this._text = element;
-        this._selectedNum = index;
-    }
-
-    onFocus = () => {
-        this._overlayDisposer?.();
-        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-    }
-
-    render() {
-        const link = false;
-        const reference = React.createRef<HTMLDivElement>();
-
-        if (this._optionsList?.length) {
-            const options = !this._opened ? (null) :
-                <div>
-                    {this._optionsList.map((element, index) => {
-                        const val = Field.toString(element);
-                        return <div className="collectionSchemaView-dropdownOption" key={index} style={{ padding: "6px" }} onPointerDown={(e) => this.onSelected(StrCast(element), index)} >
-                            {val}
-                        </div>;
-                    })}
-                </div>;
-
-            const plainText = <div style={{ padding: "5.9px" }}>{this._text}</div>;
-            const textarea = <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} style={{ padding: "5.9px" }} ref={this.dropRef} >
-                <EditableView
-                    editing={this._isEditing}
-                    isEditingCallback={this.isEditingCallback}
-                    display={"inline"}
-                    contents={this._text}
-                    height={"auto"}
-                    maxHeight={Number(MAX_ROW_HEIGHT)}
-                    GetValue={() => this._text}
-                    SetValue={action((value: string) => {
-                        // add special for params 
-                        this.onSetValue(value);
-                        return true;
-                    })}
-                />
-            </div >;
-
-            //☰
-            return (
-                <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                    <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
-                        <div className="collectionSchemaView-dropDownWrapper">
-                            <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: "length", position: "relative" }}
-                                onClick={action(e => this._opened = !this._opened)} >
-                                <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="sm" />
-                            </button>
-                            <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
-                        </div>
-                        {options}
-                    </div >
-                </div>
-            );
-        }
-        return this.renderCellWithType("list");
-    }
-}
-
-
-@observer
-export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
-    @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); }
-
-    render() {
-        const reference = React.createRef<HTMLDivElement>();
-        return (
-            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                <input type="checkbox" checked={this._isChecked} onChange={e => this._rowDoc[this.renderFieldKey] = e.target.checked} />
-            </div>
-        );
-    }
-}
-
-
-@observer
-export class CollectionSchemaButtons extends CollectionSchemaCell {
-    render() {
-        return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> :
-            <div style={{ paddingTop: 8, paddingLeft: 3 }} >
-                <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
-                    <FontAwesomeIcon icon="arrow-up" size="sm" />
-                </button>
-                <button style={{ padding: 2 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, false)} >
-                    <FontAwesomeIcon icon="arrow-down" size="sm" />
-                </button>
-            </div>;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
deleted file mode 100644
index 3b52e6408..000000000
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ /dev/null
@@ -1,518 +0,0 @@
-import React = require("react");
-import { IconProp, library } from "@fortawesome/fontawesome-svg-core";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, DocListCast, Opt } from "../../../fields/Doc";
-import { listSpec } from "../../../fields/Schema";
-import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { ScriptField } from "../../../fields/ScriptField";
-import { Cast, StrCast } from "../../../fields/Types";
-import { undoBatch } from "../../util/UndoManager";
-import { SearchBox } from "../search/SearchBox";
-import { ColumnType } from "./CollectionSchemaView";
-import "./CollectionSchemaView.scss";
-import { CollectionView } from "./CollectionView";
-
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
-
-
-export interface AddColumnHeaderProps {
-    createColumn: () => void;
-}
-
-@observer
-export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHeaderProps> {
-    render() {
-        return (
-            <button className="add-column" onClick={() => this.props.createColumn()}><FontAwesomeIcon icon="plus" size="sm" /></button>
-        );
-    }
-}
-
-
-export interface ColumnMenuProps {
-    columnField: SchemaHeaderField;
-    // keyValue: string;
-    possibleKeys: string[];
-    existingKeys: string[];
-    // keyType: ColumnType;
-    typeConst: boolean;
-    menuButtonContent: JSX.Element;
-    addNew: boolean;
-    onSelect: (oldKey: string, newKey: string, addnew: boolean) => void;
-    setIsEditing: (isEditing: boolean) => void;
-    deleteColumn: (column: string) => void;
-    onlyShowOptions: boolean;
-    setColumnType: (column: SchemaHeaderField, type: ColumnType) => void;
-    setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void;
-    anchorPoint?: any;
-    setColumnColor: (column: SchemaHeaderField, color: string) => void;
-}
-@observer
-export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps> {
-    @observable private _isOpen: boolean = false;
-    @observable private _node: HTMLDivElement | null = null;
-
-    componentDidMount() { document.addEventListener("pointerdown", this.detectClick); }
-
-    componentWillUnmount() { document.removeEventListener("pointerdown", this.detectClick); }
-
-    @action
-    detectClick = (e: PointerEvent) => {
-        !this._node?.contains(e.target as Node) && this.props.setIsEditing(this._isOpen = false);
-    }
-
-    @action
-    toggleIsOpen = (): void => {
-        this.props.setIsEditing(this._isOpen = !this._isOpen);
-    }
-
-    changeColumnType = (type: ColumnType) => {
-        this.props.setColumnType(this.props.columnField, type);
-    }
-
-    changeColumnSort = (desc: boolean | undefined) => {
-        this.props.setColumnSort(this.props.columnField, desc);
-    }
-
-    changeColumnColor = (color: string) => {
-        this.props.setColumnColor(this.props.columnField, color);
-    }
-
-    @action
-    setNode = (node: HTMLDivElement): void => {
-        if (node) {
-            this._node = node;
-        }
-    }
-
-    renderTypes = () => {
-        if (this.props.typeConst) return (null);
-
-        const type = this.props.columnField.type;
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Column type:</label>
-                <div className="columnMenu-types">
-                    <div className={"columnMenu-option" + (type === ColumnType.Any ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Any)}>
-                        <FontAwesomeIcon icon={"align-justify"} size="sm" />
-                        Any
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.Number ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Number)}>
-                        <FontAwesomeIcon icon={"hashtag"} size="sm" />
-                        Number
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.String ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.String)}>
-                        <FontAwesomeIcon icon={"font"} size="sm" />
-                        Text
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.Boolean ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Boolean)}>
-                        <FontAwesomeIcon icon={"check-square"} size="sm" />
-                        Checkbox
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.List ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.List)}>
-                        <FontAwesomeIcon icon={"list-ul"} size="sm" />
-                        List
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Doc)}>
-                        <FontAwesomeIcon icon={"file"} size="sm" />
-                        Document
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.Image ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Image)}>
-                        <FontAwesomeIcon icon={"image"} size="sm" />
-                        Image
-                    </div>
-                    <div className={"columnMenu-option" + (type === ColumnType.Date ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Date)}>
-                        <FontAwesomeIcon icon={"calendar"} size="sm" />
-                        Date
-                    </div>
-                </div>
-            </div >
-        );
-    }
-
-    renderSorting = () => {
-        const sort = this.props.columnField.desc;
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Sort by:</label>
-                <div className="columnMenu-sort">
-                    <div className={"columnMenu-option" + (sort === true ? " active" : "")} onClick={() => this.changeColumnSort(true)}>
-                        <FontAwesomeIcon icon="sort-amount-down" size="sm" />
-                        Sort descending
-                    </div>
-                    <div className={"columnMenu-option" + (sort === false ? " active" : "")} onClick={() => this.changeColumnSort(false)}>
-                        <FontAwesomeIcon icon="sort-amount-up" size="sm" />
-                        Sort ascending
-                    </div>
-                    <div className="columnMenu-option" onClick={() => this.changeColumnSort(undefined)}>
-                        <FontAwesomeIcon icon="times" size="sm" />
-                        Clear sorting
-                    </div>
-                </div>
-            </div>
-        );
-    }
-
-    renderColors = () => {
-        const selected = this.props.columnField.color;
-
-        const pink = PastelSchemaPalette.get("pink2");
-        const purple = PastelSchemaPalette.get("purple2");
-        const blue = PastelSchemaPalette.get("bluegreen1");
-        const yellow = PastelSchemaPalette.get("yellow4");
-        const red = PastelSchemaPalette.get("red2");
-        const gray = "#f1efeb";
-
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Color:</label>
-                <div className="columnMenu-colors">
-                    <div className={"columnMenu-colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div>
-                </div>
-            </div>
-        );
-    }
-
-    renderContent = () => {
-        return (
-            <div className="collectionSchema-header-menuOptions">
-                {this.props.onlyShowOptions ? <></> :
-                    <>
-                        {this.renderTypes()}
-                        {this.renderSorting()}
-                        {this.renderColors()}
-                        <div className="collectionSchema-headerMenu-group">
-                            <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Delete Column</button>
-                        </div>
-                    </>
-                }
-            </div>
-        );
-    }
-
-    render() {
-        return (
-            <div className="collectionSchema-header-menu" ref={this.setNode}>
-                <Flyout anchorPoint={this.props.anchorPoint ? this.props.anchorPoint : anchorPoints.TOP_CENTER} content={this.renderContent()}>
-                    <div className="collectionSchema-header-toggler" onClick={() => this.toggleIsOpen()}>{this.props.menuButtonContent}</div>
-                </ Flyout >
-            </div>
-        );
-    }
-}
-
-
-export interface KeysDropdownProps {
-    keyValue: string;
-    possibleKeys: string[];
-    existingKeys: string[];
-    canAddNew: boolean;
-    addNew: boolean;
-    onSelect: (oldKey: string, newKey: string, addnew: boolean, filter?: string) => void;
-    setIsEditing: (isEditing: boolean) => void;
-    width?: string;
-    docs?: Doc[];
-    Document: Doc;
-    dataDoc: Doc | undefined;
-    fieldKey: string;
-    ContainingCollectionDoc: Doc | undefined;
-    ContainingCollectionView: Opt<CollectionView>;
-    active?: (outsideReaction?: boolean) => boolean;
-    openHeader: (column: any, screenx: number, screeny: number) => void;
-    col: SchemaHeaderField;
-    icon: IconProp;
-}
-@observer
-export class KeysDropdown extends React.Component<KeysDropdownProps> {
-    @observable private _key: string = this.props.keyValue;
-    @observable private _searchTerm: string = this.props.keyValue;
-    @observable private _isOpen: boolean = false;
-    @observable private _node: HTMLDivElement | null = null;
-    @observable private _inputRef: React.RefObject<HTMLInputElement> = React.createRef();
-
-    @action setSearchTerm = (value: string): void => { this._searchTerm = value; };
-    @action setKey = (key: string): void => { this._key = key; };
-    @action setIsOpen = (isOpen: boolean): void => { this._isOpen = isOpen; };
-
-    @action
-    onSelect = (key: string): void => {
-        this.props.onSelect(this._key, key, this.props.addNew);
-        this.setKey(key);
-        this._isOpen = false;
-        this.props.setIsEditing(false);
-    }
-
-    @action
-    setNode = (node: HTMLDivElement): void => {
-        if (node) {
-            this._node = node;
-        }
-    }
-
-    componentDidMount() {
-        document.addEventListener("pointerdown", this.detectClick);
-        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
-        if (filters?.some(filter => filter.split(":")[0] === this._key)) {
-            runInAction(() => this.closeResultsVisibility = "contents");
-        }
-    }
-
-    @action
-    detectClick = (e: PointerEvent): void => {
-        if (this._node && this._node.contains(e.target as Node)) {
-        } else {
-            this._isOpen = false;
-            this.props.setIsEditing(false);
-        }
-    }
-
-    private tempfilter: string = "";
-    @undoBatch
-    onKeyDown = (e: React.KeyboardEvent): void => {
-        if (e.key === "Enter") {
-            if (this._searchTerm.includes(":")) {
-                const colpos = this._searchTerm.indexOf(":");
-                const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
-                if (temp === "") {
-                    Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
-                    this.updateFilter();
-                }
-                else {
-                    Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
-                    this.tempfilter = temp;
-                    Doc.setDocFilter(this.props.Document, this._key, temp, "check");
-                    this.props.col.setColor("green");
-                    this.closeResultsVisibility = "contents";
-                }
-            }
-            else {
-                Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
-                this.updateFilter();
-                if (this.showKeys.length) {
-                    this.onSelect(this.showKeys[0]);
-                } else if (this._searchTerm !== "" && this.props.canAddNew) {
-                    this.setSearchTerm(this._searchTerm || this._key);
-                    this.onSelect(this._searchTerm);
-                }
-            }
-        }
-    }
-
-    onChange = (val: string): void => {
-        this.setSearchTerm(val);
-    }
-
-    @action
-    onFocus = (e: React.FocusEvent): void => {
-        this._isOpen = true;
-        this.props.setIsEditing(true);
-    }
-
-    @computed get showKeys() {
-        const whitelistKeys = ["context", "author", "*lastModified", "text", "data", "tags", "creationDate"];
-        const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
-        const showKeys = new Set<string>();
-        [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.UserDoc().noviceMode ||
-            whitelistKeys.includes(key)
-            || ((!key.startsWith("_") && key[0] === key[0].toUpperCase()) || key[0] === "#")) ? showKeys.add(key) : null);
-        return Array.from(showKeys.keys()).filter(key => !this._searchTerm || key.includes(this._searchTerm));
-    }
-    @action
-    renderOptions = (): JSX.Element[] | JSX.Element => {
-        if (!this._isOpen) {
-            this.defaultMenuHeight = 0;
-            return <></>;
-        }
-        const options = this.showKeys.map(key => {
-            return <div key={key} className="key-option" style={{
-                border: "1px solid lightgray",
-                width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
-            }}
-                onPointerDown={e => {
-                    e.stopPropagation();
-                }}
-                onClick={() => {
-                    this.onSelect(key);
-                    this.setSearchTerm("");
-                }}>{key}</div>;
-        });
-
-        // if search term does not already exist as a group type, give option to create new group type
-
-        if (this._key !== this._searchTerm.slice(0, this._key.length)) {
-            if (this._searchTerm !== "" && this.props.canAddNew) {
-                options.push(<div key={""} className="key-option" style={{
-                    border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
-                }}
-                    onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
-                    Create "{this._searchTerm}" key</div>);
-            }
-        }
-
-        if (options.length === 0) {
-            this.defaultMenuHeight = 0;
-        }
-        else {
-            if (this.props.docs) {
-                const panesize = this.props.docs.length * 30;
-                options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
-            }
-            else {
-                options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
-            }
-        }
-        return options;
-    }
-
-    docSafe: Doc[] = [];
-
-    @action
-    renderFilterOptions = (): JSX.Element[] | JSX.Element => {
-        if (!this._isOpen || !this.props.dataDoc) {
-            this.defaultMenuHeight = 0;
-            return <></>;
-        }
-        const keyOptions: string[] = [];
-        const colpos = this._searchTerm.indexOf(":");
-        const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
-        if (this.docSafe.length === 0) {
-            this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
-        }
-        const docs = this.docSafe;
-        docs.forEach((doc) => {
-            const key = StrCast(doc[this._key]);
-            if (keyOptions.includes(key) === false && key.includes(temp) && key !== "") {
-                keyOptions.push(key);
-            }
-        });
-
-        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
-        if (filters === undefined || filters.length === 0 || filters.some(filter => filter.split(":")[0] === this._key) === false) {
-            this.props.col.setColor("rgb(241, 239, 235)");
-            this.closeResultsVisibility = "none";
-        }
-        for (let i = 0; i < (filters?.length ?? 0) - 1; i++) {
-            if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i].split(":")[1]) === false) {
-                keyOptions.push(filters![i + 1]);
-            }
-        }
-        const options = keyOptions.map(key => {
-            let bool = false;
-            if (filters !== undefined) {
-                const ind = filters.findIndex(filter => filter.split(":")[0] === key);
-                const fields = ind === -1 ? undefined : filters[ind].split(":");
-                bool = fields ? fields[1] === "check" : false;
-            }
-            return <div key={key} className="key-option" style={{
-                border: "1px solid lightgray", paddingLeft: 5, textAlign: "left",
-                width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
-            }}
-            >
-                <input type="checkbox"
-                    onPointerDown={e => e.stopPropagation()}
-                    onClick={e => e.stopPropagation()}
-                    onChange={(e) => {
-                        e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, "remove");
-                        e.target.checked === true ? this.closeResultsVisibility = "contents" : console.log("");
-                        e.target.checked === true ? this.props.col.setColor("green") : this.updateFilter();
-                        e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove");
-                    }}
-                    checked={bool}
-                />
-                <span style={{ paddingLeft: 4 }}>
-                    {key}
-                </span>
-
-            </div>;
-        });
-        if (options.length === 0) {
-            this.defaultMenuHeight = 0;
-        }
-        else {
-            if (this.props.docs) {
-                const panesize = this.props.docs.length * 30;
-                options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
-            }
-            else {
-                options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
-            }
-
-        }
-        return options;
-    }
-
-    @observable defaultMenuHeight = 0;
-
-
-    updateFilter() {
-        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
-        if (filters === undefined || filters.length === 0 || filters.some(filter => filter.split(":")[0] === this._key) === false) {
-            this.props.col.setColor("rgb(241, 239, 235)");
-            this.closeResultsVisibility = "none";
-        }
-    }
-
-    @computed get scriptField() {
-        const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
-        const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
-        return script ? () => script : undefined;
-    }
-    filterBackground = () => "rgba(105, 105, 105, 0.432)";
-    @observable filterOpen: boolean | undefined = undefined;
-    closeResultsVisibility: string = "none";
-
-    removeFilters = (e: React.PointerEvent): void => {
-        const keyOptions: string[] = [];
-        if (this.docSafe.length === 0 && this.props.dataDoc) {
-            this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
-        }
-        const docs = this.docSafe;
-        docs.forEach((doc) => {
-            const key = StrCast(doc[this._key]);
-            if (keyOptions.includes(key) === false) {
-                keyOptions.push(key);
-            }
-        });
-
-        Doc.setDocFilter(this.props.Document, this._key, "", "remove");
-        this.props.col.setColor("rgb(241, 239, 235)");
-        this.closeResultsVisibility = "none";
-    }
-    render() {
-        return (
-            <div style={{ display: "flex" }} ref={this.setNode}>
-                <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
-
-                {/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
-                    runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
-                }} /> */}
-
-                <div className="keys-dropdown" style={{ zIndex: 1, width: this.props.width, maxWidth: this.props.width }}>
-                    <input className="keys-search" style={{ width: "100%" }}
-                        ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
-                        onChange={e => this.onChange(e.target.value)}
-                        onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }}
-                        onFocus={this.onFocus} ></input>
-                    <div style={{ display: this.closeResultsVisibility }}>
-                        <FontAwesomeIcon onPointerDown={this.removeFilters} icon={"times-circle"} size="lg"
-                            style={{ cursor: "hand", color: "grey", padding: 2, left: -20, top: -1, height: 15, position: "relative" }} />
-                    </div>
-                    {!this._isOpen ? (null) : <div className="keys-options-wrapper" style={{
-                        width: this.props.width, maxWidth: this.props.width, height: "auto",
-                    }}>
-                        {this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()}
-                    </div>}
-                </div >
-            </div>
-        );
-    }
-}
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
deleted file mode 100644
index 881246bd4..000000000
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action } from "mobx";
-import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
-import { Doc } from "../../../fields/Doc";
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { Cast, FieldValue, StrCast } from "../../../fields/Types";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { ContextMenu } from "../ContextMenu";
-import "./CollectionSchemaView.scss";
-
-export interface MovableColumnProps {
-    columnRenderer: TableCellRenderer;
-    columnValue: SchemaHeaderField;
-    allColumns: SchemaHeaderField[];
-    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
-    ScreenToLocalTransform: () => Transform;
-}
-export class MovableColumn extends React.Component<MovableColumnProps> {
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private _colDropDisposer?: DragManager.DragDropDisposer;
-    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
-    private _sensitivity: number = 16;
-    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-
-    onPointerEnter = (e: React.PointerEvent): void => {
-        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
-            this._header!.current!.className = "collectionSchema-col-wrapper";
-            document.addEventListener("pointermove", this.onDragMove, true);
-        }
-    }
-    onPointerLeave = (e: React.PointerEvent): void => {
-        this._header!.current!.className = "collectionSchema-col-wrapper";
-        document.removeEventListener("pointermove", this.onDragMove, true);
-        !e.buttons && document.removeEventListener("pointermove", this.onPointerMove);
-    }
-    onDragMove = (e: PointerEvent): void => {
-        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top);
-        const before = x[0] < bounds[0];
-        this._header!.current!.className = "collectionSchema-col-wrapper";
-        if (before) this._header!.current!.className += " col-before";
-        if (!before) this._header!.current!.className += " col-after";
-        e.stopPropagation();
-    }
-
-    createColDropTarget = (ele: HTMLDivElement) => {
-        this._colDropDisposer?.();
-        if (ele) {
-            this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
-        }
-    }
-
-    colDrop = (e: Event, de: DragManager.DropEvent) => {
-        document.removeEventListener("pointermove", this.onDragMove, true);
-        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top);
-        const before = x[0] < bounds[0];
-        const colDragData = de.complete.columnDragData;
-        if (colDragData) {
-            e.stopPropagation();
-            this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns);
-            return true;
-        }
-        return false;
-    }
-
-    onPointerMove = (e: PointerEvent) => {
-        const onRowMove = (e: PointerEvent) => {
-            e.stopPropagation();
-            e.preventDefault();
-
-            document.removeEventListener("pointermove", onRowMove);
-            document.removeEventListener('pointerup', onRowUp);
-            const dragData = new DragManager.ColumnDragData(this.props.columnValue);
-            DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y);
-        };
-        const onRowUp = (): void => {
-            document.removeEventListener("pointermove", onRowMove);
-            document.removeEventListener('pointerup', onRowUp);
-        };
-        if (e.buttons === 1) {
-            const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
-            if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
-                document.removeEventListener("pointermove", this.onPointerMove);
-                e.stopPropagation();
-
-                document.addEventListener("pointermove", onRowMove);
-                document.addEventListener("pointerup", onRowUp);
-            }
-        }
-    }
-
-    onPointerUp = (e: React.PointerEvent) => {
-        document.removeEventListener("pointermove", this.onPointerMove);
-    }
-
-    @action
-    onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => {
-        this._dragRef = ref;
-        const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY);
-        if (!(e.target as any)?.tagName.includes("INPUT")) {
-            this._startDragPosition = { x: dx, y: dy };
-            document.addEventListener("pointermove", this.onPointerMove);
-        }
-    }
-
-
-    render() {
-        const reference = React.createRef<HTMLDivElement>();
-
-        return (
-            <div className="collectionSchema-col" ref={this.createColDropTarget}>
-                <div className="collectionSchema-col-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    <div className="col-dragger" ref={reference} onPointerDown={e => this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}>
-                        {this.props.columnRenderer}
-                    </div>
-                </div>
-            </div>
-        );
-    }
-}
-
-export interface MovableRowProps {
-    rowInfo: RowInfo;
-    ScreenToLocalTransform: () => Transform;
-    addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
-    removeDoc: (doc: Doc | Doc[]) => boolean;
-    rowFocused: boolean;
-    textWrapRow: (doc: Doc) => void;
-    rowWrapped: boolean;
-    dropAction: string;
-    addDocTab: any;
-}
-
-export class MovableRow extends React.Component<MovableRowProps> {
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private _rowDropDisposer?: DragManager.DragDropDisposer;
-
-    onPointerEnter = (e: React.PointerEvent): void => {
-        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
-            this._header!.current!.className = "collectionSchema-row-wrapper";
-            document.addEventListener("pointermove", this.onDragMove, true);
-        }
-    }
-    onPointerLeave = (e: React.PointerEvent): void => {
-        this._header!.current!.className = "collectionSchema-row-wrapper";
-        document.removeEventListener("pointermove", this.onDragMove, true);
-    }
-    onDragMove = (e: PointerEvent): void => {
-        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
-        const before = x[1] < bounds[1];
-        this._header!.current!.className = "collectionSchema-row-wrapper";
-        if (before) this._header!.current!.className += " row-above";
-        if (!before) this._header!.current!.className += " row-below";
-        e.stopPropagation();
-    }
-    componentWillUnmount() {
-
-        this._rowDropDisposer?.();
-    }
-
-    createRowDropTarget = (ele: HTMLDivElement) => {
-        this._rowDropDisposer?.();
-        if (ele) {
-            this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
-        }
-    }
-
-    rowDrop = (e: Event, de: DragManager.DropEvent) => {
-        this.onPointerLeave(e as any);
-        const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc));
-        if (!rowDoc) return false;
-
-        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
-        const before = x[1] < bounds[1];
-
-        const docDragData = de.complete.docDragData;
-        if (docDragData) {
-            e.stopPropagation();
-            if (docDragData.draggedDocuments[0] === rowDoc) return true;
-            const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before);
-            const movedDocs = docDragData.draggedDocuments;
-            return (docDragData.dropAction || docDragData.userDropAction) ?
-                docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false)
-                : (docDragData.moveDocument) ?
-                    movedDocs.reduce((added: boolean, d) => docDragData.moveDocument?.(d, rowDoc, addDocument) || added, false)
-                    : docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before), false);
-        }
-        return false;
-    }
-
-    onRowContextMenu = (e: React.MouseEvent): void => {
-        e.preventDefault();
-        const description = this.props.rowWrapped ? "Unwrap text on row" : "Text wrap row";
-        ContextMenu.Instance.addItem({ description: description, event: () => this.props.textWrapRow(this.props.rowInfo.original), icon: "file-pdf" });
-    }
-
-    @undoBatch
-    @action
-    move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => {
-        const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection);
-        return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
-    }
-
-    @action
-    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
-        console.log("yes");
-        if (e.key === "Backspace" || e.key === "Delete") {
-            undoBatch(() => this.props.removeDoc(this.props.rowInfo.original));
-        }
-    }
-
-    render() {
-        const { children = null, rowInfo } = this.props;
-
-        if (!rowInfo) {
-            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
-        }
-
-        const { original } = rowInfo;
-        const doc = FieldValue(Cast(original, Doc));
-
-        if (!doc) return (null);
-
-        const reference = React.createRef<HTMLDivElement>();
-        const onItemDown = SetupDrag(reference, () => doc, this.move, StrCast(this.props.dropAction) as dropActionType);
-
-        let className = "collectionSchema-row";
-        if (this.props.rowFocused) className += " row-focused";
-        if (this.props.rowWrapped) className += " row-wrapped";
-
-        return (
-            <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
-                <div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    <ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown} >
-                        <div className="row-dragger">
-                            <div className="row-option" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
-                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
-                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
-                        </div>
-                        {children}
-                    </ReactTableDefaults.TrComponent>
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
deleted file mode 100644
index 2bdd280ec..000000000
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ /dev/null
@@ -1,641 +0,0 @@
-@import "../globalCssVariables";
-
-.collectionSchemaView-container {
-    border-width: $COLLECTION_BORDER_WIDTH;
-    border-color: $intermediate-color;
-    border-style: solid;
-    border-radius: $border-radius;
-    box-sizing: border-box;
-    position: relative;
-    top: 0;
-    width: 100%;
-    height: 100%;
-    margin-top: 0;
-    transition: top 0.5s;
-    display: flex;
-    justify-content: space-between;
-    flex-wrap: nowrap;
-    touch-action: none;
-
-    div {
-        touch-action: none;
-    }
-
-
-    .collectionSchemaView-tableContainer {
-        width: 100%;
-        height: 100%;
-    }
-
-    .collectionSchemaView-dividerDragger {
-        position: relative;
-        height: 100%;
-        width: $SCHEMA_DIVIDER_WIDTH;
-        z-index: 20;
-        right: 0;
-        top: 0;
-        background: gray;
-        cursor: col-resize;
-    }
-
-    // .documentView-node:first-child {
-    //     background: $light-color;
-    // }
-}
-
-.collectionSchemaView-searchContainer {
-    border-width: $COLLECTION_BORDER_WIDTH;
-    border-color: $intermediate-color;
-    border-style: solid;
-    border-radius: $border-radius;
-    box-sizing: border-box;
-    position: relative;
-    top: 0;
-    width: 100%;
-    height: 100%;
-    margin-top: 0;
-    transition: top 0.5s;
-    display: flex;
-    justify-content: space-between;
-    flex-wrap: nowrap;
-    touch-action: none;
-    padding: 2px;
-
-    div {
-        touch-action: none;
-    }
-
-
-    .collectionSchemaView-tableContainer {
-        width: 100%;
-        height: 100%;
-    }
-
-    .collectionSchemaView-dividerDragger {
-        position: relative;
-        height: 100%;
-        width: 20px;
-        z-index: 20;
-        right: 0;
-        top: 0;
-        background: gray;
-        cursor: col-resize;
-    }
-
-    // .documentView-node:first-child {
-    //     background: $light-color;
-    // }
-}
-
-.ReactTable {
-    width: 100%;
-    background: white;
-    box-sizing: border-box;
-    border: none !important;
-    float: none !important;
-
-    .rt-table {
-        height: 100%;
-        display: -webkit-inline-box;
-        direction: ltr;
-        overflow: visible;
-    }
-    .rt-noData {
-        display: none;
-    }
-
-    .rt-thead {
-        width: 100%;
-        z-index: 100;
-        overflow-y: visible;
-
-        &.-header {
-            font-size: 12px;
-            height: 30px;
-            box-shadow: none;
-            z-index: 100;
-            overflow-y: visible;
-        }
-
-        .rt-resizable-header-content {
-            height: 100%;
-            overflow: visible;
-        }
-
-        .rt-th {
-            padding: 0;
-            border: solid lightgray;
-            border-width: 0 1px;
-            border-bottom: 2px solid lightgray;
-        }
-    }
-
-    .rt-th {
-        font-size: 13px;
-        text-align: center;
-
-        &:last-child {
-            overflow: visible;
-        }
-    }
-
-    .rt-tbody {
-        width: 100%;
-        direction: rtl;
-        overflow: visible;
-
-        .rt-td {
-            border-right: 1px solid rgba(0, 0, 0, 0.2);
-        }
-    }
-
-    .rt-tr-group {
-        direction: ltr;
-        flex: 0 1 auto;
-        min-height: 30px;
-        border: 0 !important;
-    }
-
-    .rt-tr {
-        width: 100%;
-        min-height: 30px;
-    }
-
-    .rt-td {
-        padding: 0;
-        font-size: 13px;
-        text-align: center;
-        white-space: nowrap;
-        display: flex;
-        align-items: center;
-
-        .imageBox-cont {
-            position: relative;
-            max-height: 100%;
-        }
-
-        .imageBox-cont img {
-            object-fit: contain;
-            max-width: 100%;
-            height: 100%;
-        }
-
-        .videoBox-cont {
-            object-fit: contain;
-            width: auto;
-            height: 100%;
-        }
-    }
-    .rt-td.rt-expandable {
-        display: flex;
-        align-items: center;
-        height: inherit;
-    }
-
-    .rt-resizer {
-        width: 8px;
-        right: -4px;
-    }
-
-    .rt-resizable-header {
-        padding: 0;
-        height: 30px;
-    }
-
-    .rt-resizable-header:last-child {
-        overflow: visible;
-
-        .rt-resizer {
-            width: 5px !important;
-        }
-    }
-}
-
-.documentView-node-topmost {
-    text-align: left;
-    transform-origin: center top;
-    display: inline-block;
-}
-
-.collectionSchema-col {
-    height: 100%;
-}
-
-
-.collectionSchema-header-menu {
-    height: auto;
-    z-index: 100;
-    position: absolute;
-    background: white;
-    padding: 5px;
-    position: fixed;
-    background: white;
-    border: black 1px solid;
-
-    .collectionSchema-header-toggler {
-        z-index: 100;
-        width: 100%;
-        height: 100%;
-        padding: 4px;
-        letter-spacing: 2px;
-        text-transform: uppercase;
-
-        svg {
-            margin-right: 4px;
-        }
-    }
-}
-
-.collectionSchemaView-header {
-    height: 100%;
-    color: gray;
-    z-index: 100;
-    overflow-y: visible;
-    display: flex;
-    justify-content: space-between;
-    flex-wrap: wrap;
-}
-
-button.add-column {
-    width: 28px;
-}
-
-.collectionSchema-header-menuOptions {
-    color: black;
-    width: 180px;
-    text-align: left;
-
-    .collectionSchema-headerMenu-group {
-        padding: 7px 0;
-        border-bottom: 1px solid lightgray;
-        cursor: pointer;
-
-        &:first-child {
-            padding-top: 0;
-        }
-
-        &:last-child {
-            border: none;
-            text-align: center;
-            padding: 12px 0 0 0;
-        }
-    }
-
-    label {
-        color: $main-accent;
-        font-weight: normal;
-        letter-spacing: 2px;
-        text-transform: uppercase;
-    }
-
-    input {
-        color: black;
-        width: 100%;
-    }
-
-    .columnMenu-option {
-        cursor: pointer;
-        padding: 3px;
-        background-color: white;
-        transition: background-color 0.2s;
-
-        &:hover {
-            background-color: $light-color-secondary;
-        }
-
-        &.active {
-            font-weight: bold;
-            border: 2px solid $light-color-secondary;
-        }
-
-        svg {
-            color: gray;
-            margin-right: 5px;
-            width: 10px;
-        }
-    }
-
-    .keys-dropdown {
-        position: relative;
-        //width: 100%;
-        background-color: white;
-
-        input {
-            border: 2px solid $light-color-secondary;
-            padding: 3px;
-            height: 28px;
-            font-weight: bold;
-            letter-spacing: "2px";
-            text-transform: "uppercase";
-
-            &:focus {
-                font-weight: normal;
-            }
-        }
-
-        .keys-options-wrapper {
-            width: 100%;
-            max-height: 150px;
-            overflow-y: scroll;
-            position: absolute;
-            top: 28px;
-            box-shadow: 0 10px 16px rgba(0, 0, 0, 0.1);
-            background-color: white;
-
-            .key-option {
-                background-color: white;
-                border: 1px solid lightgray;
-                padding: 2px 3px;
-
-                &:not(:first-child) {
-                    border-top: 0;
-                }
-
-                &:hover {
-                    background-color: $light-color-secondary;
-                }
-            }
-        }
-    }
-
-    .columnMenu-colors {
-        display: flex;
-        justify-content: space-between;
-        flex-wrap: wrap;
-
-        .columnMenu-colorPicker {
-            cursor: pointer;
-            width: 20px;
-            height: 20px;
-            border-radius: 10px;
-
-            &.active {
-                border: 2px solid white;
-                box-shadow: 0 0 0 2px lightgray;
-            }
-        }
-    }
-}
-
-.collectionSchema-row {
-    height: 100%;
-    background-color: white;
-
-    &.row-focused .rt-td {
-        background-color: #bfffc0; //$light-color-secondary;
-    }
-
-    &.row-wrapped {
-        .rt-td {
-            white-space: normal;
-        }
-    }
-
-    .row-dragger {
-        display: flex;
-        justify-content: space-around;
-        //flex: 50 0 auto;
-        width: 0;
-        max-width: 50px;
-        //height: 100%;
-        min-height: 30px;
-        align-items: center;
-        color: lightgray;
-        background-color: white;
-        transition: color 0.1s ease;
-
-        .row-option {
-            // padding: 5px;
-            cursor: pointer;
-            position: absolute;
-            transition: color 0.1s ease;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            z-index: 2;
-
-            &:hover {
-                color: gray;
-            }
-        }
-    }
-
-    .collectionSchema-row-wrapper {
-
-        &.row-above {
-            border-top: 1px solid red;
-        }
-
-        &.row-below {
-            border-bottom: 1px solid red;
-        }
-
-        &.row-inside {
-            border: 1px solid red;
-        }
-
-        .row-dragging {
-            background-color: blue;
-        }
-    }
-}
-
-.collectionSchemaView-cellContainer {
-    width: 100%;
-    height: unset;
-}
-
-.collectionSchemaView-cellWrapper {
-    height: 100%;
-    padding: 4px;
-    text-align: left;
-    padding-left: 19px;
-
-    position: relative;
-
-    &:focus {
-        outline: none;
-    }
-
-    &.editing {
-        padding: 0;
-
-        input {
-            outline: 0;
-            border: none;
-            background-color: rgb(255, 217, 217);
-            width: 100%;
-            height: 100%;
-            padding: 2px 3px;
-            min-height: 26px;
-        }
-    }
-
-    &.focused {
-
-        &.inactive {
-            border: none;
-        }
-    }
-
-    p {
-        width: 100%;
-        height: 100%;
-    }
-
-    &:hover .collectionSchemaView-cellContents-docExpander {
-        display: block;
-    }
-
-
-    .collectionSchemaView-cellContents-document {
-        display: inline-block;
-    }
-
-    .collectionSchemaView-cellContents-docButton {
-        float: right;
-        width: "15px";
-        height: "15px";
-    }
-
-    .collectionSchemaView-dropdownWrapper {
-
-        border: grey;
-        border-style: solid;
-        border-width: 1px;
-        height: 30px;
-
-        .collectionSchemaView-dropdownButton {
-
-            //display: inline-block;
-            float: left;
-            height: 100%;
-
-
-        }
-
-        .collectionSchemaView-dropdownText {
-            display: inline-block;
-            //float: right;
-            height: 100%;
-            display: "flex";
-            font-size: 13;
-            justify-content: "center";
-            align-items: "center";
-        }
-
-    }
-
-    .collectionSchemaView-dropdownContainer {
-        position: absolute;
-        border: 1px solid rgba(0, 0, 0, 0.04);
-        box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14);
-
-        .collectionSchemaView-dropdownOption:hover {
-            background-color: rgba(0, 0, 0, 0.14);
-            cursor: pointer;
-        }
-    }
-}
-
-.collectionSchemaView-cellContents-docExpander {
-    height: 30px;
-    width: 30px;
-    display: none;
-    position: absolute;
-    top: 0;
-    right: 0;
-    background-color: lightgray;
-
-}
-
-.doc-drag-over {
-    background-color: red;
-}
-
-.collectionSchemaView-toolbar {
-    z-index: 100;
-}
-
-.collectionSchemaView-toolbar {
-    height: 30px;
-    display: flex;
-    justify-content: flex-end;
-    padding: 0 10px;
-    border-bottom: 2px solid gray;
-
-    .collectionSchemaView-toolbar-item {
-        display: flex;
-        flex-direction: column;
-        justify-content: center;
-    }
-}
-
-#preview-schema-checkbox-div {
-    margin-left: 20px;
-    font-size: 12px;
-}
-
-.collectionSchemaView-table {
-    width: 100%;
-    height: 100%;
-    overflow: auto;
-    padding: 3px;
-}
-
-.rt-td.rt-expandable {
-    overflow: visible;
-    position: relative;
-    height:100%;
-    z-index: 1;
-}
-.reactTable-sub {
-    background-color: rgb(252, 252, 252);
-    width: 100%;
-
-    .rt-thead {
-        display: none;
-    }
-
-    .row-dragger {
-        background-color: rgb(252, 252, 252);
-    }
-
-    .rt-table {
-        background-color: rgb(252, 252, 252);
-    }
-
-    .collectionSchemaView-table {
-        width: 100%; 
-        border: solid 1px;
-        overflow: visible;
-        padding: 0px;
-    }
-}
-
-.collectionSchemaView-expander {
-    height: 100%;
-    min-height: 30px;
-    position: absolute;
-    color: gray;
-    width: 20;
-    height: auto;
-    left: 55;
-
-    svg {
-        position: absolute;
-        top: 50%;
-        left: 10;
-        transform: translate(-50%, -50%);
-    }
-}
-
-.collectionSchemaView-addRow {
-    color: gray;
-    letter-spacing: 2px;
-    text-transform: uppercase;
-    cursor: pointer;
-    font-size: 10.5px;
-    margin-left: 50px;
-    margin-top: 10px;
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
deleted file mode 100644
index b33c437a9..000000000
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ /dev/null
@@ -1,575 +0,0 @@
-import React = require("react");
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, untracked } from "mobx";
-import { observer } from "mobx-react";
-import Measure from "react-measure";
-import { Resize } from "react-table";
-import "react-table/react-table.css";
-import { Doc, Opt } from "../../../fields/Doc";
-import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
-import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { Cast, NumCast } from "../../../fields/Types";
-import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, emptyPath, returnFalse, setupMoveUpEvents, returnEmptyDoclist, returnTrue } from "../../../Utils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/globalCssVariables.scss';
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import '../DocumentDecorations.scss';
-import { DocumentView } from "../nodes/DocumentView";
-import { DefaultStyleProvider } from "../StyleProvider";
-import "./CollectionSchemaView.scss";
-import { CollectionSubView } from "./CollectionSubView";
-import { SchemaTable } from "./SchemaTable";
-import { DocUtils } from "../../documents/Documents";
-// bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
-
-export enum ColumnType {
-    Any,
-    Number,
-    String,
-    Boolean,
-    Doc,
-    Image,
-    List,
-    Date
-}
-// this map should be used for keys that should have a const type of value
-const columnTypes: Map<string, ColumnType> = new Map([
-    ["title", ColumnType.String],
-    ["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
-    ["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
-    ["_curPage", ColumnType.Number], ["_currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
-]);
-
-@observer
-export class CollectionSchemaView extends CollectionSubView(doc => doc) {
-    private _previewCont?: HTMLDivElement;
-
-    @observable _previewDoc: Doc | undefined = undefined;
-    @observable _focusedTable: Doc = this.props.Document;
-    @observable _col: any = "";
-    @observable _menuWidth = 0;
-    @observable _headerOpen = false;
-    @observable _headerIsEditing = false;
-    @observable _menuHeight = 0;
-    @observable _pointerX = 0;
-    @observable _pointerY = 0;
-    @observable _openTypes: boolean = false;
-
-    @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
-    @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; }
-    @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); }
-    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
-    @computed get scale() { return this.props.ScreenToLocalTransform().Scale; }
-    @computed get columns() { return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); }
-    set columns(columns: SchemaHeaderField[]) { this.props.Document._schemaHeaders = new List<SchemaHeaderField>(columns); }
-
-    @computed get menuCoordinates() {
-        let searchx = 0;
-        let searchy = 0;
-        if (this.props.Document._searchDoc) {
-            const el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0];
-            if (el !== undefined) {
-                const rect = el.getBoundingClientRect();
-                searchx = rect.x;
-                searchy = rect.y;
-            }
-        }
-        const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
-        const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
-        return this.props.ScreenToLocalTransform().transformPoint(x, y);
-    }
-
-    get documentKeys() {
-        const docs = this.childDocs;
-        const keys: { [key: string]: boolean } = {};
-        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
-        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
-        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
-        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
-        //  is displayed (unlikely) it won't show up until something else changes.
-        //TODO Types
-        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false))));
-
-        this.columns.forEach(key => keys[key.heading] = true);
-        return Array.from(Object.keys(keys));
-    }
-
-    @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
-
-    @undoBatch
-    setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => {
-        this._openTypes = false;
-        if (columnTypes.get(columnField.heading)) return;
-
-        const columns = this.columns;
-        const index = columns.indexOf(columnField);
-        if (index > -1) {
-            columnField.setType(NumCast(type));
-            columns[index] = columnField;
-            this.columns = columns;
-        }
-    });
-
-    @undoBatch
-    setColumnColor = (columnField: SchemaHeaderField, color: string): void => {
-        const columns = this.columns;
-        const index = columns.indexOf(columnField);
-        if (index > -1) {
-            columnField.setColor(color);
-            columns[index] = columnField;
-            this.columns = columns; // need to set the columns to trigger rerender
-        }
-    }
-
-    @undoBatch
-    @action
-    setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => {
-        const columns = this.columns;
-        columns.forEach(col => col.setDesc(undefined));
-
-        const index = columns.findIndex(c => c.heading === columnField.heading);
-        const column = columns[index];
-        column.setDesc(descending);
-        columns[index] = column;
-        this.columns = columns;
-    }
-
-    renderTypes = (col: any) => {
-        if (columnTypes.get(col.heading)) return (null);
-
-        const type = col.type;
-
-        const anyType = <div className={"columnMenu-option" + (type === ColumnType.Any ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Any)}>
-            <FontAwesomeIcon icon={"align-justify"} size="sm" />
-                Any
-            </div>;
-
-        const numType = <div className={"columnMenu-option" + (type === ColumnType.Number ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Number)}>
-            <FontAwesomeIcon icon={"hashtag"} size="sm" />
-                Number
-            </div>;
-
-        const textType = <div className={"columnMenu-option" + (type === ColumnType.String ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.String)}>
-            <FontAwesomeIcon icon={"font"} size="sm" />
-            Text
-            </div>;
-
-        const boolType = <div className={"columnMenu-option" + (type === ColumnType.Boolean ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Boolean)}>
-            <FontAwesomeIcon icon={"check-square"} size="sm" />
-            Checkbox
-            </div>;
-
-        const listType = <div className={"columnMenu-option" + (type === ColumnType.List ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.List)}>
-            <FontAwesomeIcon icon={"list-ul"} size="sm" />
-            List
-            </div>;
-
-        const docType = <div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Doc)}>
-            <FontAwesomeIcon icon={"file"} size="sm" />
-            Document
-            </div>;
-
-        const imageType = <div className={"columnMenu-option" + (type === ColumnType.Image ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Image)}>
-            <FontAwesomeIcon icon={"image"} size="sm" />
-            Image
-            </div>;
-
-        const dateType = <div className={"columnMenu-option" + (type === ColumnType.Date ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Date)}>
-            <FontAwesomeIcon icon={"calendar"} size="sm" />
-                Date
-                </div>;
-
-
-        const allColumnTypes = <div className="columnMenu-types">
-            {anyType}
-            {numType}
-            {textType}
-            {boolType}
-            {listType}
-            {docType}
-            {imageType}
-            {dateType}
-        </div>;
-
-        const justColType = type === ColumnType.Any ? anyType : type === ColumnType.Number ? numType :
-            type === ColumnType.String ? textType : type === ColumnType.Boolean ? boolType :
-                type === ColumnType.List ? listType : type === ColumnType.Doc ? docType :
-                    type === ColumnType.Date ? dateType : imageType;
-
-        return (
-            <div className="collectionSchema-headerMenu-group" onClick={action(() => this._openTypes = !this._openTypes)}>
-                <div>
-                    <label style={{ cursor: "pointer" }}>Column type:</label>
-                    <FontAwesomeIcon icon={"caret-down"} size="lg" style={{ float: "right", transform: `rotate(${this._openTypes ? "180deg" : 0})`, transition: "0.2s all ease" }} />
-                </div>
-                {this._openTypes ? allColumnTypes : justColType}
-            </div >
-        );
-    }
-
-    renderSorting = (col: any) => {
-        const sort = col.desc;
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Sort by:</label>
-                <div className="columnMenu-sort">
-                    <div className={"columnMenu-option" + (sort === true ? " active" : "")} onClick={() => this.setColumnSort(col, true)}>
-                        <FontAwesomeIcon icon="sort-amount-down" size="sm" />
-                        Sort descending
-                    </div>
-                    <div className={"columnMenu-option" + (sort === false ? " active" : "")} onClick={() => this.setColumnSort(col, false)}>
-                        <FontAwesomeIcon icon="sort-amount-up" size="sm" />
-                        Sort ascending
-                    </div>
-                    <div className="columnMenu-option" onClick={() => this.setColumnSort(col, undefined)}>
-                        <FontAwesomeIcon icon="times" size="sm" />
-                        Clear sorting
-                    </div>
-                </div>
-            </div>
-        );
-    }
-
-    renderColors = (col: any) => {
-        const selected = col.color;
-
-        const pink = PastelSchemaPalette.get("pink2");
-        const purple = PastelSchemaPalette.get("purple2");
-        const blue = PastelSchemaPalette.get("bluegreen1");
-        const yellow = PastelSchemaPalette.get("yellow4");
-        const red = PastelSchemaPalette.get("red2");
-        const gray = "#f1efeb";
-
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Color:</label>
-                <div className="columnMenu-colors">
-                    <div className={"columnMenu-colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.setColumnColor(col, pink!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.setColumnColor(col, purple!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.setColumnColor(col, blue!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.setColumnColor(col, yellow!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.setColumnColor(col, red!)}></div>
-                    <div className={"columnMenu-colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.setColumnColor(col, gray)}></div>
-                </div>
-            </div>
-        );
-    }
-
-    @undoBatch
-    @action
-    changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => {
-        const columns = this.columns;
-        if (columns === undefined) {
-            this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, "f1efeb")]);
-        } else {
-            if (addNew) {
-                columns.push(new SchemaHeaderField(newKey, "f1efeb"));
-                this.columns = columns;
-            } else {
-                const index = columns.map(c => c.heading).indexOf(oldKey);
-                if (index > -1) {
-                    const column = columns[index];
-                    column.setHeading(newKey);
-                    columns[index] = column;
-                    this.columns = columns;
-                    if (filter) {
-                        Doc.setDocFilter(this.props.Document, newKey, filter, "match");
-                    }
-                    else {
-                        this.props.Document._docFilters = undefined;
-                    }
-                }
-            }
-        }
-    }
-
-    @action
-    openHeader = (col: any, screenx: number, screeny: number) => {
-        this._col = col;
-        this._headerOpen = true;
-        this._pointerX = screenx;
-        this._pointerY = screeny;
-    }
-
-    @action
-    closeHeader = () => { this._headerOpen = false; }
-
-    @undoBatch
-    @action
-    deleteColumn = (key: string) => {
-        const columns = this.columns;
-        if (columns === undefined) {
-            this.columns = new List<SchemaHeaderField>([]);
-        } else {
-            const index = columns.map(c => c.heading).indexOf(key);
-            if (index > -1) {
-                columns.splice(index, 1);
-                this.columns = columns;
-            }
-        }
-        this.closeHeader();
-    }
-
-    getPreviewTransform = (): Transform => {
-        return this.props.ScreenToLocalTransform().translate(- this.borderWidth - NumCast(COLLECTION_BORDER_WIDTH) - this.tableWidth, - this.borderWidth);
-    }
-
-    @action
-    onHeaderClick = (e: React.PointerEvent) => {
-        e.stopPropagation();
-    }
-
-    @action
-    onWheel(e: React.WheelEvent) {
-        const scale = this.props.ScreenToLocalTransform().Scale;
-        this.props.isContentActive(true) && e.stopPropagation();
-    }
-
-    @computed get renderMenuContent() {
-        TraceMobx();
-        return <div className="collectionSchema-header-menuOptions">
-            {this.renderTypes(this._col)}
-            {this.renderColors(this._col)}
-            <div className="collectionSchema-headerMenu-group">
-                <button onClick={() => { this.deleteColumn(this._col.heading); }}
-                >Delete Column</button>
-            </div>
-        </div>;
-    }
-
-    private createTarget = (ele: HTMLDivElement) => {
-        this._previewCont = ele;
-        super.CreateDropTarget(ele);
-    }
-
-    isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
-
-    @action setFocused = (doc: Doc) => this._focusedTable = doc;
-
-    @action setPreviewDoc = (doc: Opt<Doc>) => {
-        SelectionManager.SelectSchemaView(this, doc);
-        this._previewDoc = doc;
-    }
-
-    //toggles preview side-panel of schema
-    @action
-    toggleExpander = () => {
-        this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0;
-    }
-
-    onDividerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, this.toggleExpander);
-    }
-    @action
-    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
-        const nativeWidth = this._previewCont!.getBoundingClientRect();
-        const minWidth = 40;
-        const maxWidth = 1000;
-        const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
-        const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
-        this.props.Document.schemaPreviewWidth = width;
-        return false;
-    }
-
-    onPointerDown = (e: React.PointerEvent): void => {
-        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            if (this.props.isSelected(true)) e.stopPropagation();
-            else this.props.select(false);
-        }
-    }
-
-    @computed
-    get previewDocument(): Doc | undefined { return this._previewDoc; }
-
-    @computed
-    get dividerDragger() {
-        return this.previewWidth() === 0 ? (null) :
-            <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} >
-                <div className="collectionSchemaView-dividerDragger" />
-            </div>;
-    }
-
-    @computed
-    get previewPanel() {
-        return <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
-            {!this.previewDocument ? (null) :
-                <DocumentView
-                    Document={this.previewDocument}
-                    DataDoc={undefined}
-                    fitContentsToDoc={returnTrue}
-                    freezeDimensions={true}
-                    dontCenter={"y"}
-                    focus={DocUtils.DefaultFocus}
-                    renderDepth={this.props.renderDepth}
-                    rootSelected={this.rootSelected}
-                    PanelWidth={this.previewWidth}
-                    PanelHeight={this.previewHeight}
-                    isContentActive={returnTrue}
-                    isDocumentActive={returnFalse}
-                    ScreenToLocalTransform={this.getPreviewTransform}
-                    docFilters={this.docFilters}
-                    docRangeFilters={this.docRangeFilters}
-                    searchFilterDocs={this.searchFilterDocs}
-                    styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
-                    docViewPath={returnEmptyDoclist}
-                    ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                    ContainingCollectionView={this.props.CollectionView}
-                    moveDocument={this.props.moveDocument}
-                    addDocument={this.props.addDocument}
-                    removeDocument={this.props.removeDocument}
-                    whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
-                    addDocTab={this.props.addDocTab}
-                    pinToPres={this.props.pinToPres}
-                    bringToFront={returnFalse}
-                />}
-        </div>;
-    }
-
-    @computed
-    get schemaTable() {
-        return <SchemaTable
-            Document={this.props.Document}
-            PanelHeight={this.props.PanelHeight}
-            PanelWidth={this.props.PanelWidth}
-            childDocs={this.childDocs}
-            CollectionView={this.props.CollectionView}
-            ContainingCollectionView={this.props.ContainingCollectionView}
-            ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-            fieldKey={this.props.fieldKey}
-            renderDepth={this.props.renderDepth}
-            moveDocument={this.props.moveDocument}
-            ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-            active={this.props.isContentActive}
-            onDrop={this.onExternalDrop}
-            addDocTab={this.props.addDocTab}
-            pinToPres={this.props.pinToPres}
-            isSelected={this.props.isSelected}
-            isFocused={this.isFocused}
-            setFocused={this.setFocused}
-            setPreviewDoc={this.setPreviewDoc}
-            deleteDocument={this.props.removeDocument}
-            addDocument={this.props.addDocument}
-            dataDoc={this.props.DataDoc}
-            columns={this.columns}
-            documentKeys={this.documentKeys}
-            headerIsEditing={this._headerIsEditing}
-            openHeader={this.openHeader}
-            onClick={this.onTableClick}
-            onPointerDown={emptyFunction}
-            onResizedChange={this.onResizedChange}
-            setColumns={this.setColumns}
-            reorderColumns={this.reorderColumns}
-            changeColumns={this.changeColumns}
-            setHeaderIsEditing={this.setHeaderIsEditing}
-            changeColumnSort={this.setColumnSort}
-        />;
-    }
-
-    @computed
-    public get schemaToolbar() {
-        return <div className="collectionSchemaView-toolbar">
-            <div className="collectionSchemaView-toolbar-item">
-                <div id="preview-schema-checkbox-div">
-                    <input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />
-                    Show Preview
-                </div>
-            </div>
-        </div>;
-    }
-
-    onSpecificMenu = (e: React.MouseEvent) => {
-        if ((e.target as any)?.className?.includes?.("collectionSchemaView-cell") || (e.target instanceof HTMLSpanElement)) {
-            const cm = ContextMenu.Instance;
-            const options = cm.findByDescription("Options...");
-            const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
-            optionItems.push({ description: "remove", event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: "trash" });
-            !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
-            cm.displayMenu(e.clientX, e.clientY);
-            (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this.
-            e.stopPropagation();
-        }
-    }
-
-    @action
-    onTableClick = (e: React.MouseEvent): void => {
-        if (!(e.target as any)?.className?.includes?.("collectionSchemaView-cell") && !(e.target instanceof HTMLSpanElement)) {
-            this.setPreviewDoc(undefined);
-        } else {
-            e.stopPropagation();
-        }
-        this.setFocused(this.props.Document);
-        this.closeHeader();
-    }
-
-    onResizedChange = (newResized: Resize[], event: any) => {
-        const columns = this.columns;
-        newResized.forEach(resized => {
-            const index = columns.findIndex(c => c.heading === resized.id);
-            const column = columns[index];
-            column.setWidth(resized.value);
-            columns[index] = column;
-        });
-        this.columns = columns;
-    }
-
-    @action
-    setColumns = (columns: SchemaHeaderField[]) => this.columns = columns
-
-    @undoBatch
-    reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
-        const columns = [...columnsValues];
-        const oldIndex = columns.indexOf(toMove);
-        const relIndex = columns.indexOf(relativeTo);
-        const newIndex = (oldIndex > relIndex && !before) ? relIndex + 1 : (oldIndex < relIndex && before) ? relIndex - 1 : relIndex;
-
-        if (oldIndex === newIndex) return;
-
-        columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]);
-        this.columns = columns;
-    }
-
-    onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
-
-    render() {
-        TraceMobx();
-        if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
-        const menuContent = this.renderMenuContent;
-        const menu = <div className="collectionSchema-header-menu"
-            onWheel={e => this.onZoomMenu(e)}
-            onPointerDown={e => this.onHeaderClick(e)}
-            style={{ transform: `translate(${(this.menuCoordinates[0])}px, ${(this.menuCoordinates[1])}px)` }}>
-            <Measure offset onResize={action((r: any) => {
-                const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
-                this._menuWidth = dim[0]; this._menuHeight = dim[1];
-            })}>
-                {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
-            </Measure>
-        </div>;
-        return <div className={"collectionSchemaView" + (this.props.Document._searchDoc ? "-searchContainer" : "-container")}
-            style={{
-                overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
-                pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined,
-                width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
-            }}  >
-            <div className="collectionSchemaView-tableContainer"
-                style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
-                onContextMenu={this.onSpecificMenu}
-                onPointerDown={this.onPointerDown}
-                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
-                onDrop={e => this.onExternalDrop(e, {})}
-                ref={this.createTarget}>
-                {this.schemaTable}
-            </div>
-            {this.dividerDragger}
-            {!this.previewWidth() ? (null) : this.previewPanel}
-            {this._headerOpen && this.props.isContentActive() ? menu : null}
-        </div>;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index fb60265e3..e5b1721f9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -29,7 +29,7 @@ import CollectionMapView from './CollectionMapView';
 import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
 import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { CollectionPileView } from './CollectionPileView';
-import { CollectionSchemaView } from "./CollectionSchemaView";
+import { CollectionSchemaView } from "./schemaView/CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { SubCollectionViewProps } from './CollectionSubView';
 import { CollectionTimeView } from './CollectionTimeView';
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
deleted file mode 100644
index 0c69ee030..000000000
--- a/src/client/views/collections/SchemaTable.tsx
+++ /dev/null
@@ -1,599 +0,0 @@
-import React = require("react");
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
-import "react-table/react-table.css";
-import { DateField } from "../../../fields/DateField";
-import { AclPrivate, AclReadonly, DataSym, Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { listSpec } from "../../../fields/Schema";
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { ComputedField } from "../../../fields/ScriptField";
-import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
-import { ImageField } from "../../../fields/URLField";
-import { GetEffectiveAcl } from "../../../fields/util";
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils";
-import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { CompileScript, Transformer, ts } from "../../util/Scripting";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/globalCssVariables.scss';
-import { ContextMenu } from "../ContextMenu";
-import '../DocumentDecorations.scss';
-import { DocumentView } from "../nodes/DocumentView";
-import { DefaultStyleProvider } from "../StyleProvider";
-import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
-import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
-import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
-import "./CollectionSchemaView.scss";
-import { CollectionView } from "./CollectionView";
-
-
-enum ColumnType {
-    Any,
-    Number,
-    String,
-    Boolean,
-    Doc,
-    Image,
-    List,
-    Date
-}
-
-// this map should be used for keys that should have a const type of value
-const columnTypes: Map<string, ColumnType> = new Map([
-    ["title", ColumnType.String],
-    ["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
-    ["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
-    ["_curPage", ColumnType.Number], ["_currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
-]);
-
-export interface SchemaTableProps {
-    Document: Doc; // child doc
-    dataDoc?: Doc;
-    PanelHeight: () => number;
-    PanelWidth: () => number;
-    childDocs?: Doc[];
-    CollectionView: Opt<CollectionView>;
-    ContainingCollectionView: Opt<CollectionView>;
-    ContainingCollectionDoc: Opt<Doc>;
-    fieldKey: string;
-    renderDepth: number;
-    deleteDocument?: (document: Doc | Doc[]) => boolean;
-    addDocument?: (document: Doc | Doc[]) => boolean;
-    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    ScreenToLocalTransform: () => Transform;
-    active: (outsideReaction: boolean | undefined) => boolean;
-    onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
-    addDocTab: (document: Doc, where: string) => boolean;
-    pinToPres: (document: Doc) => void;
-    isSelected: (outsideReaction?: boolean) => boolean;
-    isFocused: (document: Doc, outsideReaction: boolean) => boolean;
-    setFocused: (document: Doc) => void;
-    setPreviewDoc: (document: Opt<Doc>) => void;
-    columns: SchemaHeaderField[];
-    documentKeys: any[];
-    headerIsEditing: boolean;
-    openHeader: (column: any, screenx: number, screeny: number) => void;
-    onClick: (e: React.MouseEvent) => void;
-    onPointerDown: (e: React.PointerEvent) => void;
-    onResizedChange: (newResized: Resize[], event: any) => void;
-    setColumns: (columns: SchemaHeaderField[]) => void;
-    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => void;
-    changeColumns: (oldKey: string, newKey: string, addNew: boolean) => void;
-    setHeaderIsEditing: (isEditing: boolean) => void;
-    changeColumnSort: (columnField: SchemaHeaderField, descending: boolean | undefined) => void;
-}
-
-@observer
-export class SchemaTable extends React.Component<SchemaTableProps> {
-    @observable _cellIsEditing: boolean = false;
-    @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 };
-    @observable _openCollections: Set<number> = new Set;
-
-    @observable _showDoc: Doc | undefined;
-    @observable _showDataDoc: any = "";
-    @observable _showDocPos: number[] = [];
-
-    @observable _showTitleDropdown: boolean = false;
-
-    @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
-    @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; }
-    @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); }
-
-    @computed get childDocs() {
-        if (this.props.childDocs) return this.props.childDocs;
-
-        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
-        return DocListCast(doc[this.props.fieldKey]);
-    }
-    set childDocs(docs: Doc[]) {
-        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
-        doc[this.props.fieldKey] = new List<Doc>(docs);
-    }
-
-    @computed get textWrappedRows() {
-        return Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []);
-    }
-    set textWrappedRows(textWrappedRows: string[]) {
-        this.props.Document.textwrappedSchemaRows = new List<string>(textWrappedRows);
-    }
-
-    @computed get resized(): { id: string, value: number }[] {
-        return this.props.columns.reduce((resized, shf) => {
-            (shf.width > -1) && resized.push({ id: shf.heading, value: shf.width });
-            return resized;
-        }, [] as { id: string, value: number }[]);
-    }
-    @computed get sorted(): SortingRule[] {
-        return this.props.columns.reduce((sorted, shf) => {
-            shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc });
-            return sorted;
-        }, [] as SortingRule[]);
-    }
-
-    @action
-    changeSorting = (col: any) => {
-        this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
-    }
-
-    @action
-    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown
-
-    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
-    @computed get tableColumns(): Column<Doc>[] {
-        const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
-        const columns: Column<Doc>[] = [];
-        const tableIsFocused = this.props.isFocused(this.props.Document, false);
-        const focusedRow = this._focusedCell.row;
-        const focusedCol = this._focusedCell.col;
-        const isEditable = !this.props.headerIsEditing;
-
-        columns.push({
-            expander: true, Header: "", width: 58,
-            Expander: (rowInfo) => {
-                return rowInfo.original.type !== DocumentType.COL ? (null) :
-                    <div className="collectionSchemaView-expander" onClick={action(() => (this._openCollections[rowInfo.isExpanded ? "delete" : "add"])(rowInfo.viewIndex))}>
-                        <FontAwesomeIcon icon={rowInfo.isExpanded ? "caret-down" : "caret-right"} size="lg" />
-                    </div>;
-            }
-        });
-        columns.push(...this.props.columns.map(col => {
-            const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
-                this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
-                    this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
-                        this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
-
-            const keysDropdown = <KeysDropdown
-                keyValue={col.heading}
-                possibleKeys={possibleKeys}
-                existingKeys={this.props.columns.map(c => c.heading)}
-                canAddNew={true}
-                addNew={false}
-                onSelect={this.props.changeColumns}
-                setIsEditing={this.props.setHeaderIsEditing}
-                docs={this.props.childDocs}
-                Document={this.props.Document}
-                dataDoc={this.props.dataDoc}
-                fieldKey={this.props.fieldKey}
-                ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-                ContainingCollectionView={this.props.ContainingCollectionView}
-                active={this.props.active}
-                openHeader={this.props.openHeader}
-                icon={icon}
-                col={col}
-                // try commenting this out
-                width={"100%"}
-            />;
-
-            const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
-            const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}>
-                {keysDropdown}
-                <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
-                    <FontAwesomeIcon icon={sortIcon} size="lg" />
-                </div>
-            </div>;
-
-            return {
-                Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
-                accessor: (doc: Doc) => doc ? Field.toString(doc[col.heading] as Field) : 0,
-                id: col.heading,
-                Cell: (rowProps: CellInfo) => {
-                    const rowIndex = rowProps.index;
-                    const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
-                    const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-
-                    const props: CellProps = {
-                        row: rowIndex,
-                        col: columnIndex,
-                        rowProps: rowProps,
-                        isFocused: isFocused,
-                        changeFocusedCellByIndex: this.changeFocusedCellByIndex,
-                        CollectionView: this.props.CollectionView,
-                        ContainingCollection: this.props.ContainingCollectionView,
-                        Document: this.props.Document,
-                        fieldKey: this.props.fieldKey,
-                        renderDepth: this.props.renderDepth,
-                        addDocTab: this.props.addDocTab,
-                        pinToPres: this.props.pinToPres,
-                        moveDocument: this.props.moveDocument,
-                        setIsEditing: this.setCellIsEditing,
-                        isEditable: isEditable,
-                        setPreviewDoc: this.props.setPreviewDoc,
-                        setComputed: this.setComputed,
-                        getField: this.getField,
-                        showDoc: this.showDoc,
-                    };
-
-
-                    switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) {
-                        case ColumnType.Number: return <CollectionSchemaNumberCell {...props} />;
-                        case ColumnType.String: return <CollectionSchemaStringCell {...props} />;
-                        case ColumnType.Boolean: return <CollectionSchemaCheckboxCell {...props} />;
-                        case ColumnType.Doc: return <CollectionSchemaDocCell {...props} />;
-                        case ColumnType.Image: return <CollectionSchemaImageCell {...props} />;
-                        case ColumnType.List: return <CollectionSchemaListCell {...props} />;
-                        case ColumnType.Date: return <CollectionSchemaDateCell {...props} />;
-                        default:
-                            return <CollectionSchemaCell {...props} />;
-                    }
-                },
-                minWidth: 200,
-            };
-        }));
-        columns.push({
-            Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
-            accessor: (doc: Doc) => 0,
-            id: "add",
-            Cell: (rowProps: CellInfo) => {
-                const rowIndex = rowProps.index;
-                const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
-                const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-                return <CollectionSchemaButtons  {...{
-                    row: rowProps.index,
-                    col: columnIndex,
-                    rowProps: rowProps,
-                    isFocused: isFocused,
-                    changeFocusedCellByIndex: this.changeFocusedCellByIndex,
-                    CollectionView: this.props.CollectionView,
-                    ContainingCollection: this.props.ContainingCollectionView,
-                    Document: this.props.Document,
-                    fieldKey: this.props.fieldKey,
-                    renderDepth: this.props.renderDepth,
-                    addDocTab: this.props.addDocTab,
-                    pinToPres: this.props.pinToPres,
-                    moveDocument: this.props.moveDocument,
-                    setIsEditing: this.setCellIsEditing,
-                    isEditable: isEditable,
-                    setPreviewDoc: this.props.setPreviewDoc,
-                    setComputed: this.setComputed,
-                    getField: this.getField,
-                    showDoc: this.showDoc,
-                }} />;
-            },
-            width: 28,
-            resizable: false
-        });
-        return columns;
-    }
-
-
-    constructor(props: SchemaTableProps) {
-        super(props);
-        if (this.props.Document._schemaHeaders === undefined) {
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
-            new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
-        }
-    }
-
-    componentDidMount() {
-        document.addEventListener("keydown", this.onKeyDown);
-    }
-
-    componentWillUnmount() {
-        document.removeEventListener("keydown", this.onKeyDown);
-    }
-
-    tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
-        const tableDoc = this.props.Document[DataSym];
-        const effectiveAcl = GetEffectiveAcl(tableDoc);
-
-        if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) {
-            doc.context = this.props.Document;
-            tableDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
-            return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
-        }
-        return false;
-    }
-
-    private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
-        return !rowInfo ? {} : {
-            ScreenToLocalTransform: this.props.ScreenToLocalTransform,
-            addDoc: this.tableAddDoc,
-            removeDoc: this.props.deleteDocument,
-            rowInfo,
-            rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
-            textWrapRow: this.toggleTextWrapRow,
-            rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
-            dropAction: StrCast(this.props.Document.childDropAction),
-            addDocTab: this.props.addDocTab
-        };
-    }
-
-    private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
-        if (!rowInfo || column) return {};
-
-        const row = rowInfo.index;
-        //@ts-ignore
-        const col = this.columns.map(c => c.heading).indexOf(column!.id);
-        const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
-        // TODO: editing border doesn't work :(
-        return {
-            style: { border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb" }
-        };
-    }
-
-    @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
-
-    @action
-    onKeyDown = (e: KeyboardEvent): void => {
-        if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {// && this.props.isSelected(true)) {
-            const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
-            this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
-
-            if (direction) {
-                const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
-                pdoc && this.props.setPreviewDoc(pdoc);
-                e.stopPropagation();
-            }
-        } else if (e.keyCode === 27) {
-            this.props.setPreviewDoc(undefined);
-            e.stopPropagation(); // stopPropagation for left/right arrows 
-        }
-    }
-
-    changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => {
-        switch (direction) {
-            case "tab": return { row: (curRow + 1 === this.childDocs.length ? 0 : curRow + 1), col: curCol + 1 === this.props.columns.length ? 0 : curCol + 1 };
-            case "right": return { row: curRow, col: curCol + 1 === this.props.columns.length ? curCol : curCol + 1 };
-            case "left": return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 };
-            case "up": return { row: curRow === 0 ? curRow : curRow - 1, col: curCol };
-            case "down": return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol };
-        }
-        return this._focusedCell;
-    }
-
-    @action
-    changeFocusedCellByIndex = (row: number, col: number): void => {
-        if (this._focusedCell.row !== row || this._focusedCell.col !== col) {
-            this._focusedCell = { row: row, col: col };
-        }
-        this.props.setFocused(this.props.Document);
-    }
-
-    @undoBatch
-    createRow = action(() => {
-        this.props.addDocument?.(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }));
-        this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
-    });
-
-    @undoBatch
-    @action
-    createColumn = () => {
-        let index = 0;
-        let found = this.props.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
-        while (found) {
-            index++;
-            found = this.props.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
-        }
-        this.props.columns.push(new SchemaHeaderField(`New field ${index ? "(" + index + ")" : ""}`, "#f1efeb"));
-    }
-
-    @action
-    getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => {
-        if (doc && field && column.type === ColumnType.Any) {
-            const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)];
-            if (val instanceof ImageField) return ColumnType.Image;
-            if (val instanceof Doc) return ColumnType.Doc;
-            if (val instanceof DateField) return ColumnType.Date;
-            if (val instanceof List) return ColumnType.List;
-        }
-        if (column.type && column.type !== 0) {
-            return column.type;
-        }
-        if (columnTypes.get(column.heading)) {
-            return column.type = columnTypes.get(column.heading)!;
-        }
-        return column.type = ColumnType.Any;
-    }
-
-    @undoBatch
-    @action
-    toggleTextwrap = async () => {
-        const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []);
-        if (textwrappedRows.length) {
-            this.props.Document.textwrappedSchemaRows = new List<string>([]);
-        } else {
-            const docs = DocListCast(this.props.Document[this.props.fieldKey]);
-            const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
-            this.props.Document.textwrappedSchemaRows = new List<string>(allRows);
-        }
-    }
-
-    @action
-    toggleTextWrapRow = (doc: Doc): void => {
-        const textWrapped = this.textWrappedRows;
-        const index = textWrapped.findIndex(id => doc[Id] === id);
-
-        index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]);
-
-        this.textWrappedRows = textWrapped;
-    }
-
-    @computed
-    get reactTable() {
-        const children = this.childDocs;
-        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
-        const expanded: { [name: string]: any } = {};
-        Array.from(this._openCollections.keys()).map(col => expanded[col.toString()] = true);
-        const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
-
-        return <ReactTable
-            style={{ position: "relative" }}
-            data={children}
-            page={0}
-            pageSize={children.length}
-            showPagination={false}
-            columns={this.tableColumns}
-            getTrProps={this.getTrProps}
-            getTdProps={this.getTdProps}
-            sortable={false}
-            TrComponent={MovableRow}
-            sorted={this.sorted}
-            expanded={expanded}
-            resized={this.resized}
-            onResizedChange={this.props.onResizedChange}
-            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== DocumentType.COL) ? (null) :
-                <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
-
-        />;
-    }
-
-    onContextMenu = (e: React.MouseEvent): void => {
-        ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
-    }
-
-    getField = (row: number, col?: number) => {
-        const docs = this.childDocs;
-
-        row = row % docs.length;
-        while (row < 0) row += docs.length;
-        const columns = this.props.columns;
-        const doc = docs[row];
-        if (col === undefined) {
-            return doc;
-        }
-        if (col >= 0 && col < columns.length) {
-            const column = this.props.columns[col].heading;
-            return doc[column];
-        }
-        return undefined;
-    }
-
-    createTransformer = (row: number, col: number): Transformer => {
-        const self = this;
-        const captures: { [name: string]: Field } = {};
-
-        const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
-            return root => {
-                function visit(node: ts.Node) {
-                    node = ts.visitEachChild(node, visit, context);
-                    if (ts.isIdentifier(node)) {
-                        const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
-                        const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
-                        if (isntPropAccess && isntPropAssign) {
-                            if (node.text === "$r") {
-                                return ts.createNumericLiteral(row.toString());
-                            } else if (node.text === "$c") {
-                                return ts.createNumericLiteral(col.toString());
-                            } else if (node.text === "$") {
-                                if (ts.isCallExpression(node.parent)) {
-                                    // captures.doc = self.props.Document;
-                                    // captures.key = self.props.fieldKey;
-                                }
-                            }
-                        }
-                    }
-
-                    return node;
-                }
-                return ts.visitNode(root, visit);
-            };
-        };
-
-        // const getVars = () => {
-        //     return { capturedVariables: captures };
-        // };
-
-        return { transformer, /*getVars*/ };
-    }
-
-    setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => {
-        script =
-            `const $ = (row:number, col?:number) => {
-                const rval = (doc as any)[key][row + ${row}];
-                return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading];
-            }
-            return ${script}`;
-        const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
-        if (compiled.compiled) {
-            doc[field] = new ComputedField(compiled);
-            return true;
-        }
-        return false;
-    }
-
-    @action
-    showDoc = (doc: Doc | undefined, dataDoc?: Doc, screenX?: number, screenY?: number) => {
-        this._showDoc = doc;
-        if (dataDoc && screenX && screenY) {
-            this._showDocPos = this.props.ScreenToLocalTransform().transformPoint(screenX, screenY);
-        }
-    }
-
-    onOpenClick = () => {
-        this._showDoc && this.props.addDocTab(this._showDoc, "add:right");
-    }
-
-    getPreviewTransform = (): Transform => {
-        return this.props.ScreenToLocalTransform().translate(- this.borderWidth - 4 - this.tableWidth, - this.borderWidth);
-    }
-
-    render() {
-        const preview = "";
-        return <div className="collectionSchemaView-table"
-            onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
-            onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
-            {this.reactTable}
-            {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
-            {!this._showDoc ? (null) :
-                <div className="collectionSchemaView-documentPreview" ref="overlay"
-                    style={{
-                        position: "absolute", width: 150, height: 150,
-                        background: "dimGray", display: "block", top: 0, left: 0,
-                        transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`
-                    }} >
-                    <DocumentView
-                        Document={this._showDoc}
-                        DataDoc={this._showDataDoc}
-                        styleProvider={DefaultStyleProvider}
-                        layerProvider={undefined}
-                        docViewPath={returnEmptyDoclist}
-                        freezeDimensions={true}
-                        focus={DocUtils.DefaultFocus}
-                        renderDepth={this.props.renderDepth}
-                        rootSelected={returnFalse}
-                        isContentActive={returnTrue}
-                        isDocumentActive={returnFalse}
-                        PanelWidth={() => 150}
-                        PanelHeight={() => 150}
-                        ScreenToLocalTransform={this.getPreviewTransform}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
-                        searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                        ContainingCollectionView={this.props.CollectionView}
-                        moveDocument={this.props.moveDocument}
-                        whenChildContentsActiveChanged={emptyFunction}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={this.props.pinToPres}
-                        bringToFront={returnFalse}>
-                    </DocumentView>
-                </div>}
-        </div>;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaCells.tsx b/src/client/views/collections/schemaView/CollectionSchemaCells.tsx
new file mode 100644
index 000000000..f75179cea
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaCells.tsx
@@ -0,0 +1,585 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable } from "mobx";
+import { observer } from "mobx-react";
+import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+import { CellInfo } from "react-table";
+import "react-table/react-table.css";
+import { DateField } from "../../../../fields/DateField";
+import { Doc, DocListCast, Field, Opt } from "../../../../fields/Doc";
+import { Id } from "../../../../fields/FieldSymbols";
+import { List } from "../../../../fields/List";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { ComputedField } from "../../../../fields/ScriptField";
+import { BoolCast, Cast, DateCast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
+import { ImageField } from "../../../../fields/URLField";
+import { Utils, emptyFunction } from "../../../../Utils";
+import { Docs } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { DragManager } from "../../../util/DragManager";
+import { KeyCodes } from "../../../util/KeyCodes";
+import { CompileScript } from "../../../util/Scripting";
+import { SearchUtil } from "../../../util/SearchUtil";
+import { SnappingManager } from "../../../util/SnappingManager";
+import { undoBatch } from "../../../util/UndoManager";
+import '../../../views/DocumentDecorations.scss';
+import { EditableView } from "../../EditableView";
+import { MAX_ROW_HEIGHT } from '../../globalCssVariables.scss';
+import { DocumentIconContainer } from "../../nodes/DocumentIcon";
+import { OverlayView } from "../../OverlayView";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "../CollectionView";
+const path = require('path');
+
+// intialize cell properties
+export interface CellProps {
+    row: number;
+    col: number;
+    rowProps: CellInfo;
+    CollectionView: Opt<CollectionView>;
+    ContainingCollection: Opt<CollectionView>;
+    Document: Doc;
+    fieldKey: string;
+    renderDepth: number;
+    addDocTab: (document: Doc, where: string) => boolean;
+    pinToPres: (document: Doc) => void;
+    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined,
+        addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+    isFocused: boolean;
+    changeFocusedCellByIndex: (row: number, col: number) => void;
+    setIsEditing: (isEditing: boolean) => void;
+    isEditable: boolean;
+    setPreviewDoc: (doc: Doc) => void;
+    setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean;
+    getField: (row: number, col?: number) => void;
+    showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void;
+}
+
+@observer
+export class CollectionSchemaCell extends React.Component<CellProps> {
+    public static resolvedFieldKey(column: string, rowDoc: Doc) {
+        const fieldKey = column;
+        if (fieldKey.startsWith("*")) {
+            const rootKey = fieldKey.substring(1);
+            const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))];
+            const matchedKeys = allKeys.filter(key => key.includes(rootKey));
+            if (matchedKeys.length) return matchedKeys[0];
+        }
+        return fieldKey;
+    }
+    @observable protected _isEditing: boolean = false;
+    protected _focusRef = React.createRef<HTMLDivElement>();
+    protected _rowDoc = this.props.rowProps.original;
+    protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original);
+    protected _dropDisposer?: DragManager.DragDropDisposer;
+    @observable contents: string = "";
+
+    componentDidMount() { document.addEventListener("keydown", this.onKeyDown); }
+    componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); }
+
+    @action
+    onKeyDown = (e: KeyboardEvent): void => {
+        if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) {
+            document.removeEventListener("keydown", this.onKeyDown);
+            this._isEditing = true;
+            this.props.setIsEditing(true);
+        }
+    }
+
+    @action
+    isEditingCallback = (isEditing: boolean): void => {
+        document.removeEventListener("keydown", this.onKeyDown);
+        isEditing && document.addEventListener("keydown", this.onKeyDown);
+        this._isEditing = isEditing;
+        this.props.setIsEditing(isEditing);
+        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+    }
+
+    @action
+    onPointerDown = async (e: React.PointerEvent): Promise<void> => {
+        this.onItemDown(e);
+        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+        this.props.setPreviewDoc(this.props.rowProps.original);
+
+        let url: string;
+        if (url = StrCast(this.props.rowProps.row.href)) {
+            try {
+                new URL(url);
+                const temp = window.open(url)!;
+                temp.blur();
+                window.focus();
+            } catch { }
+        }
+
+        const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null);
+        doc && this.props.setPreviewDoc(doc);
+    }
+
+    @undoBatch
+    applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => {
+        const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) });
+        if (!res.success) return false;
+        doc[this.renderFieldKey] = res.result;
+        return true;
+    }
+
+    private drop = (e: Event, de: DragManager.DropEvent) => {
+        if (de.complete.docDragData) {
+            if (de.complete.docDragData.draggedDocuments.length === 1) {
+                this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0];
+            }
+            else {
+                const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {});
+                this._rowDataDoc[this.renderFieldKey] = coll;
+            }
+            e.stopPropagation();
+        }
+    }
+
+    protected dropRef = (ele: HTMLElement | null) => {
+        this._dropDisposer?.();
+        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
+    }
+
+    returnHighlights(contents: string, positions?: number[]) {
+        if (positions) {
+            const results = [];
+            StrCast(this.props.Document._searchString);
+            const length = StrCast(this.props.Document._searchString).length;
+            const color = contents ? "black" : "grey";
+
+            results.push(<span key="-1" style={{ color }}>{contents?.slice(0, positions[0])}</span>);
+            positions.forEach((num, cur) => {
+                results.push(<span key={"start" + cur} style={{ backgroundColor: "#FFFF00", color }}>{contents?.slice(num, num + length)}</span>);
+                let end = 0;
+                cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
+                results.push(<span key={"end" + cur} style={{ color }}>{contents?.slice(num + length, end)}</span>);
+            }
+            );
+            return results;
+        }
+        return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
+    }
+
+    @computed get renderFieldKey() { return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); }
+    onItemDown = async (e: React.PointerEvent) => {
+        if (this.props.Document._searchDoc) {
+            const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
+            const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
+            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext,
+                undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc));
+        }
+    }
+    renderCellWithType(type: string | undefined) {
+        const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+
+        const fieldKey = this.renderFieldKey;
+        const field = this._rowDoc[fieldKey];
+
+        const onPointerEnter = (e: React.PointerEvent): void => {
+            if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
+                dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over";
+            }
+        };
+        const onPointerLeave = (e: React.PointerEvent): void => {
+            dragRef.current!.className = "collectionSchemaView-cellContainer";
+        };
+
+        let contents = Field.toString(field as Field);
+        contents = contents === "" ? "--" : contents;
+
+        let className = "collectionSchemaView-cellWrapper";
+        if (this._isEditing) className += " editing";
+        if (this.props.isFocused && this.props.isEditable) className += " focused";
+        if (this.props.isFocused && !this.props.isEditable) className += " inactive";
+
+        const positions = [];
+        if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
+            let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase();
+            const search = StrCast(this.props.Document._searchString).toLowerCase();
+            let start = term.indexOf(search);
+            let tally = 0;
+            if (start !== -1) {
+                positions.push(start);
+            }
+            while (start < contents?.length && start !== -1) {
+                term = term.slice(start + search.length + 1);
+                tally += start + search.length + 1;
+                start = term.indexOf(search);
+                positions.push(tally + start);
+            }
+            if (positions.length > 1) {
+                positions.pop();
+            }
+        }
+        const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
+        return (
+            <div className="collectionSchemaView-cellContainer" style={{ cursor: field instanceof Doc ? "grab" : "auto" }}
+                ref={dragRef} onPointerDown={this.onPointerDown} onClick={action(e => this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
+                <div className={className} ref={this._focusRef} tabIndex={-1}>
+                    <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null}>
+                        {!this.props.Document._searchDoc ?
+                            <EditableView
+                                editing={this._isEditing}
+                                isEditingCallback={this.isEditingCallback}
+                                display={"inline"}
+                                contents={contents}
+                                height={"auto"}
+                                maxHeight={Number(MAX_ROW_HEIGHT)}
+                                placeholder={placeholder}
+                                GetValue={() => {
+                                    const cfield = ComputedField.WithoutComputed(() => FieldValue(field));
+                                    const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
+                                    const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
+                                    return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
+                                        Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
+                                }}
+                                SetValue={action((value: string) => {
+                                    // sets what is displayed after the user makes an input
+                                    let retVal = false;
+                                    if (value.startsWith(":=") || value.startsWith("=:=")) {
+                                        // decides how to compute a value when given either of the above strings
+                                        const script = value.substring(value.startsWith("=:=") ? 3 : 2);
+                                        retVal = this.props.setComputed(script, value.startsWith(":=") ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col);
+                                    } else {
+                                        // check if the input is a number
+                                        let inputIsNum = true;
+                                        for (let s of value) {
+                                            if (isNaN(parseInt(s)) && !(s == ".") && !(s == ",")) {
+                                                inputIsNum = false;
+                                            }
+                                        }
+                                        // check if the input is a boolean
+                                        let inputIsBool: boolean = value == "false" || value == "true";
+                                        // what to do in the case 
+                                        if (!inputIsNum && !inputIsBool && !value.startsWith("=")) {
+                                            // if it's not a number, it's a string, and should be processed as such
+                                            // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically 
+                                            // after each edit
+                                            let valueSansQuotes = value;
+                                            if (this._isEditing) {
+                                                const vsqLength = valueSansQuotes.length;
+                                                // get rid of outer quotes
+                                                valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0,
+                                                    valueSansQuotes.charAt(vsqLength - 1) == "\"" ? vsqLength - 1 : vsqLength);
+                                            }
+                                            let inputAsString = '"';
+                                            // escape any quotes in the string
+                                            for (const i of valueSansQuotes) {
+                                                if (i == '"') {
+                                                    inputAsString += '\\"';
+                                                } else {
+                                                    inputAsString += i;
+                                                }
+                                            }
+                                            // add a closing quote
+                                            inputAsString += '"';
+                                            //two options here: we can strip off outer quotes or we can figure out what's going on with the script
+                                            const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+                                            const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length
+                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+                                            // handle numbers and expressions
+                                        } else if (inputIsNum || value.startsWith("=")) {
+                                            //TODO: make accept numbers
+                                            const inputscript = value.substring(value.startsWith("=") ? 1 : 0);
+                                            // if commas are not stripped, the parser only considers the numbers after the last comma
+                                            let inputSansCommas = "";
+                                            for (let s of inputscript) {
+                                                if (!(s == ",")) {
+                                                    inputSansCommas += s;
+                                                }
+                                            }
+                                            const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+                                            const changeMade = value.length !== value.length || value.length - 2 !== value.length
+                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+                                            // handle booleans
+                                        } else if (inputIsBool) {
+                                            const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+                                            const changeMade = value.length !== value.length || value.length - 2 !== value.length
+                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+                                        }
+                                    }
+                                    if (retVal) {
+                                        this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
+                                        this.props.setIsEditing(false);
+                                    }
+                                    return retVal;
+                                })}
+                                OnFillDown={async (value: string) => {
+                                    const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+                                    script.compiled && DocListCast(this.props.Document[this.props.fieldKey]).
+                                        forEach((doc, i) => value.startsWith(":=") ?
+                                            this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) :
+                                            this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run));
+                                }}
+                            />
+                            :
+                            this.returnHighlights(contents, positions)
+                        }
+                    </div >
+                </div>
+            </div>
+        );
+    }
+
+    render() { return this.renderCellWithType(undefined); }
+}
+
+@observer
+export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } }
+
+@observer
+export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } }
+
+@observer
+export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } }
+
+@observer
+export class CollectionSchemaDateCell extends CollectionSchemaCell {
+    @computed get _date(): Opt<DateField> { return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; }
+
+    @action
+    handleChange = (date: any) => {
+        // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
+        // if (script.compiled) {
+        //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
+        // } else {
+        // ^ DateCast is always undefined for some reason, but that is what the field should be set to
+        this._rowDoc[this.renderFieldKey] = new DateField(date as Date);
+        //}
+    }
+
+    render() {
+        return !this.props.isFocused ? <span onPointerDown={this.onPointerDown}>{this._date ? Field.toString(this._date as Field) : "--"}</span> :
+            <DatePicker
+                selected={this._date?.date || new Date}
+                onSelect={date => this.handleChange(date)}
+                onChange={date => this.handleChange(date)}
+            />;
+    }
+}
+
+@observer
+export class CollectionSchemaDocCell extends CollectionSchemaCell {
+
+    _overlayDisposer?: () => void;
+
+    @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); }
+
+    @action
+    onSetValue = (value: string) => {
+        this._doc && (Doc.GetProto(this._doc).title = value);
+
+        const script = CompileScript(value, {
+            addReturn: true,
+            typecheck: true,
+            transformer: DocumentIconContainer.getTransformer()
+        });
+
+        const results = script.compiled && script.run();
+        if (results && results.success) {
+            this._rowDoc[this.renderFieldKey] = results.result;
+            return true;
+        }
+        return false;
+    }
+
+    componentWillUnmount() { this.onBlur(); }
+
+    onBlur = () => { this._overlayDisposer?.(); };
+    onFocus = () => {
+        this.onBlur();
+        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+    }
+
+    @action
+    isEditingCallback = (isEditing: boolean): void => {
+        document.removeEventListener("keydown", this.onKeyDown);
+        isEditing && document.addEventListener("keydown", this.onKeyDown);
+        this._isEditing = isEditing;
+        this.props.setIsEditing(isEditing);
+        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+    }
+
+    render() {
+        return !this._doc ? this.renderCellWithType("document") :
+            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1}
+                onPointerDown={this.onPointerDown}
+            >
+                <div className="collectionSchemaView-cellContents-document"
+                    style={{ padding: "5.9px" }}
+                    ref={this.dropRef}
+                    onFocus={this.onFocus}
+                    onBlur={this.onBlur}
+                >
+                    <EditableView
+                        editing={this._isEditing}
+                        isEditingCallback={this.isEditingCallback}
+                        display={"inline"}
+                        contents={this._doc.title || "--"}
+                        height={"auto"}
+                        maxHeight={Number(MAX_ROW_HEIGHT)}
+                        GetValue={() => StrCast(this._doc?.title)}
+                        SetValue={action((value: string) => {
+                            this.onSetValue(value);
+                            return true;
+                        })}
+                    />
+                </div >
+                <div onClick={() => this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton">
+                    <FontAwesomeIcon icon="external-link-alt" size="lg" />
+                </div>
+            </div>;
+    }
+}
+
+@observer
+export class CollectionSchemaImageCell extends CollectionSchemaCell {
+
+    choosePath(url: URL) {
+        if (url.protocol === "data") return url.href;
+        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
+        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here
+
+        const ext = path.extname(url.href);
+        return url.href.replace(ext, "_o" + path.extname(url.href));
+    }
+
+    render() {
+        const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+        const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
+        const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
+        const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
+        const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
+
+        const aspect = Doc.NativeAspect(this._rowDoc);
+        let width = Math.min(75, this.props.rowProps.width);
+        const height = Math.min(75, width / aspect);
+        width = height * aspect;
+
+        const reference = React.createRef<HTMLDivElement>();
+        return <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+            <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
+                <img src={url[0]}
+                    width={paths.length ? width : "20px"}
+                    height={paths.length ? height : "20px"} />
+            </div >
+        </div>;
+    }
+}
+
+
+@observer
+export class CollectionSchemaListCell extends CollectionSchemaCell {
+    _overlayDisposer?: () => void;
+
+    @computed get _field() { return this._rowDoc[this.renderFieldKey]; }
+    @computed get _optionsList() { return this._field as List<any>; }
+    @observable private _opened = false;
+    @observable private _text = "select an item";
+    @observable private _selectedNum = 0;
+
+    @action
+    onSetValue = (value: string) => {
+        // change if its a document
+        this._optionsList[this._selectedNum] = this._text = value;
+
+        (this._field as List<any>).splice(this._selectedNum, 1, value);
+    }
+
+    @action
+    onSelected = (element: string, index: number) => {
+        this._text = element;
+        this._selectedNum = index;
+    }
+
+    onFocus = () => {
+        this._overlayDisposer?.();
+        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+    }
+
+    render() {
+        const link = false;
+        const reference = React.createRef<HTMLDivElement>();
+
+        if (this._optionsList?.length) {
+            const options = !this._opened ? (null) :
+                <div>
+                    {this._optionsList.map((element, index) => {
+                        const val = Field.toString(element);
+                        return <div className="collectionSchemaView-dropdownOption" key={index} style={{ padding: "6px" }} onPointerDown={(e) => this.onSelected(StrCast(element), index)} >
+                            {val}
+                        </div>;
+                    })}
+                </div>;
+
+            const plainText = <div style={{ padding: "5.9px" }}>{this._text}</div>;
+            const textarea = <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} style={{ padding: "5.9px" }} ref={this.dropRef} >
+                <EditableView
+                    editing={this._isEditing}
+                    isEditingCallback={this.isEditingCallback}
+                    display={"inline"}
+                    contents={this._text}
+                    height={"auto"}
+                    maxHeight={Number(MAX_ROW_HEIGHT)}
+                    GetValue={() => this._text}
+                    SetValue={action((value: string) => {
+                        // add special for params 
+                        this.onSetValue(value);
+                        return true;
+                    })}
+                />
+            </div >;
+
+            //☰
+            return (
+                <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+                    <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
+                        <div className="collectionSchemaView-dropDownWrapper">
+                            <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: "length", position: "relative" }}
+                                onClick={action(e => this._opened = !this._opened)} >
+                                <FontAwesomeIcon icon={this._opened ? "caret-up" : "caret-down"} size="sm" />
+                            </button>
+                            <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
+                        </div>
+                        {options}
+                    </div >
+                </div>
+            );
+        }
+        return this.renderCellWithType("list");
+    }
+}
+
+
+@observer
+export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
+    @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); }
+
+    render() {
+        const reference = React.createRef<HTMLDivElement>();
+        return (
+            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+                <input type="checkbox" checked={this._isChecked} onChange={e => this._rowDoc[this.renderFieldKey] = e.target.checked} />
+            </div>
+        );
+    }
+}
+
+
+@observer
+export class CollectionSchemaButtons extends CollectionSchemaCell {
+    render() {
+        return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> :
+            <div style={{ paddingTop: 8, paddingLeft: 3 }} >
+                <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
+                    <FontAwesomeIcon icon="arrow-up" size="sm" />
+                </button>
+                <button style={{ padding: 2 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, false)} >
+                    <FontAwesomeIcon icon="arrow-down" size="sm" />
+                </button>
+            </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
new file mode 100644
index 000000000..b2115b22e
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
@@ -0,0 +1,518 @@
+import React = require("react");
+import { IconProp, library } from "@fortawesome/fontawesome-svg-core";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast, Opt } from "../../../../fields/Doc";
+import { listSpec } from "../../../../fields/Schema";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../../fields/ScriptField";
+import { Cast, StrCast } from "../../../../fields/Types";
+import { undoBatch } from "../../../util/UndoManager";
+import { SearchBox } from "../../search/SearchBox";
+import { ColumnType } from "./CollectionSchemaView";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "../CollectionView";
+
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+
+export interface AddColumnHeaderProps {
+    createColumn: () => void;
+}
+
+@observer
+export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHeaderProps> {
+    render() {
+        return (
+            <button className="add-column" onClick={() => this.props.createColumn()}><FontAwesomeIcon icon="plus" size="sm" /></button>
+        );
+    }
+}
+
+
+export interface ColumnMenuProps {
+    columnField: SchemaHeaderField;
+    // keyValue: string;
+    possibleKeys: string[];
+    existingKeys: string[];
+    // keyType: ColumnType;
+    typeConst: boolean;
+    menuButtonContent: JSX.Element;
+    addNew: boolean;
+    onSelect: (oldKey: string, newKey: string, addnew: boolean) => void;
+    setIsEditing: (isEditing: boolean) => void;
+    deleteColumn: (column: string) => void;
+    onlyShowOptions: boolean;
+    setColumnType: (column: SchemaHeaderField, type: ColumnType) => void;
+    setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void;
+    anchorPoint?: any;
+    setColumnColor: (column: SchemaHeaderField, color: string) => void;
+}
+@observer
+export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps> {
+    @observable private _isOpen: boolean = false;
+    @observable private _node: HTMLDivElement | null = null;
+
+    componentDidMount() { document.addEventListener("pointerdown", this.detectClick); }
+
+    componentWillUnmount() { document.removeEventListener("pointerdown", this.detectClick); }
+
+    @action
+    detectClick = (e: PointerEvent) => {
+        !this._node?.contains(e.target as Node) && this.props.setIsEditing(this._isOpen = false);
+    }
+
+    @action
+    toggleIsOpen = (): void => {
+        this.props.setIsEditing(this._isOpen = !this._isOpen);
+    }
+
+    changeColumnType = (type: ColumnType) => {
+        this.props.setColumnType(this.props.columnField, type);
+    }
+
+    changeColumnSort = (desc: boolean | undefined) => {
+        this.props.setColumnSort(this.props.columnField, desc);
+    }
+
+    changeColumnColor = (color: string) => {
+        this.props.setColumnColor(this.props.columnField, color);
+    }
+
+    @action
+    setNode = (node: HTMLDivElement): void => {
+        if (node) {
+            this._node = node;
+        }
+    }
+
+    renderTypes = () => {
+        if (this.props.typeConst) return (null);
+
+        const type = this.props.columnField.type;
+        return (
+            <div className="collectionSchema-headerMenu-group">
+                <label>Column type:</label>
+                <div className="columnMenu-types">
+                    <div className={"columnMenu-option" + (type === ColumnType.Any ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Any)}>
+                        <FontAwesomeIcon icon={"align-justify"} size="sm" />
+                        Any
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.Number ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Number)}>
+                        <FontAwesomeIcon icon={"hashtag"} size="sm" />
+                        Number
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.String ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.String)}>
+                        <FontAwesomeIcon icon={"font"} size="sm" />
+                        Text
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.Boolean ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Boolean)}>
+                        <FontAwesomeIcon icon={"check-square"} size="sm" />
+                        Checkbox
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.List ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.List)}>
+                        <FontAwesomeIcon icon={"list-ul"} size="sm" />
+                        List
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Doc)}>
+                        <FontAwesomeIcon icon={"file"} size="sm" />
+                        Document
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.Image ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Image)}>
+                        <FontAwesomeIcon icon={"image"} size="sm" />
+                        Image
+                    </div>
+                    <div className={"columnMenu-option" + (type === ColumnType.Date ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Date)}>
+                        <FontAwesomeIcon icon={"calendar"} size="sm" />
+                        Date
+                    </div>
+                </div>
+            </div >
+        );
+    }
+
+    renderSorting = () => {
+        const sort = this.props.columnField.desc;
+        return (
+            <div className="collectionSchema-headerMenu-group">
+                <label>Sort by:</label>
+                <div className="columnMenu-sort">
+                    <div className={"columnMenu-option" + (sort === true ? " active" : "")} onClick={() => this.changeColumnSort(true)}>
+                        <FontAwesomeIcon icon="sort-amount-down" size="sm" />
+                        Sort descending
+                    </div>
+                    <div className={"columnMenu-option" + (sort === false ? " active" : "")} onClick={() => this.changeColumnSort(false)}>
+                        <FontAwesomeIcon icon="sort-amount-up" size="sm" />
+                        Sort ascending
+                    </div>
+                    <div className="columnMenu-option" onClick={() => this.changeColumnSort(undefined)}>
+                        <FontAwesomeIcon icon="times" size="sm" />
+                        Clear sorting
+                    </div>
+                </div>
+            </div>
+        );
+    }
+
+    renderColors = () => {
+        const selected = this.props.columnField.color;
+
+        const pink = PastelSchemaPalette.get("pink2");
+        const purple = PastelSchemaPalette.get("purple2");
+        const blue = PastelSchemaPalette.get("bluegreen1");
+        const yellow = PastelSchemaPalette.get("yellow4");
+        const red = PastelSchemaPalette.get("red2");
+        const gray = "#f1efeb";
+
+        return (
+            <div className="collectionSchema-headerMenu-group">
+                <label>Color:</label>
+                <div className="columnMenu-colors">
+                    <div className={"columnMenu-colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div>
+                </div>
+            </div>
+        );
+    }
+
+    renderContent = () => {
+        return (
+            <div className="collectionSchema-header-menuOptions">
+                {this.props.onlyShowOptions ? <></> :
+                    <>
+                        {this.renderTypes()}
+                        {this.renderSorting()}
+                        {this.renderColors()}
+                        <div className="collectionSchema-headerMenu-group">
+                            <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Delete Column</button>
+                        </div>
+                    </>
+                }
+            </div>
+        );
+    }
+
+    render() {
+        return (
+            <div className="collectionSchema-header-menu" ref={this.setNode}>
+                <Flyout anchorPoint={this.props.anchorPoint ? this.props.anchorPoint : anchorPoints.TOP_CENTER} content={this.renderContent()}>
+                    <div className="collectionSchema-header-toggler" onClick={() => this.toggleIsOpen()}>{this.props.menuButtonContent}</div>
+                </ Flyout >
+            </div>
+        );
+    }
+}
+
+
+export interface KeysDropdownProps {
+    keyValue: string;
+    possibleKeys: string[];
+    existingKeys: string[];
+    canAddNew: boolean;
+    addNew: boolean;
+    onSelect: (oldKey: string, newKey: string, addnew: boolean, filter?: string) => void;
+    setIsEditing: (isEditing: boolean) => void;
+    width?: string;
+    docs?: Doc[];
+    Document: Doc;
+    dataDoc: Doc | undefined;
+    fieldKey: string;
+    ContainingCollectionDoc: Doc | undefined;
+    ContainingCollectionView: Opt<CollectionView>;
+    active?: (outsideReaction?: boolean) => boolean;
+    openHeader: (column: any, screenx: number, screeny: number) => void;
+    col: SchemaHeaderField;
+    icon: IconProp;
+}
+@observer
+export class KeysDropdown extends React.Component<KeysDropdownProps> {
+    @observable private _key: string = this.props.keyValue;
+    @observable private _searchTerm: string = this.props.keyValue;
+    @observable private _isOpen: boolean = false;
+    @observable private _node: HTMLDivElement | null = null;
+    @observable private _inputRef: React.RefObject<HTMLInputElement> = React.createRef();
+
+    @action setSearchTerm = (value: string): void => { this._searchTerm = value; };
+    @action setKey = (key: string): void => { this._key = key; };
+    @action setIsOpen = (isOpen: boolean): void => { this._isOpen = isOpen; };
+
+    @action
+    onSelect = (key: string): void => {
+        this.props.onSelect(this._key, key, this.props.addNew);
+        this.setKey(key);
+        this._isOpen = false;
+        this.props.setIsEditing(false);
+    }
+
+    @action
+    setNode = (node: HTMLDivElement): void => {
+        if (node) {
+            this._node = node;
+        }
+    }
+
+    componentDidMount() {
+        document.addEventListener("pointerdown", this.detectClick);
+        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+        if (filters?.some(filter => filter.split(":")[0] === this._key)) {
+            runInAction(() => this.closeResultsVisibility = "contents");
+        }
+    }
+
+    @action
+    detectClick = (e: PointerEvent): void => {
+        if (this._node && this._node.contains(e.target as Node)) {
+        } else {
+            this._isOpen = false;
+            this.props.setIsEditing(false);
+        }
+    }
+
+    private tempfilter: string = "";
+    @undoBatch
+    onKeyDown = (e: React.KeyboardEvent): void => {
+        if (e.key === "Enter") {
+            if (this._searchTerm.includes(":")) {
+                const colpos = this._searchTerm.indexOf(":");
+                const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+                if (temp === "") {
+                    Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
+                    this.updateFilter();
+                }
+                else {
+                    Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
+                    this.tempfilter = temp;
+                    Doc.setDocFilter(this.props.Document, this._key, temp, "check");
+                    this.props.col.setColor("green");
+                    this.closeResultsVisibility = "contents";
+                }
+            }
+            else {
+                Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove");
+                this.updateFilter();
+                if (this.showKeys.length) {
+                    this.onSelect(this.showKeys[0]);
+                } else if (this._searchTerm !== "" && this.props.canAddNew) {
+                    this.setSearchTerm(this._searchTerm || this._key);
+                    this.onSelect(this._searchTerm);
+                }
+            }
+        }
+    }
+
+    onChange = (val: string): void => {
+        this.setSearchTerm(val);
+    }
+
+    @action
+    onFocus = (e: React.FocusEvent): void => {
+        this._isOpen = true;
+        this.props.setIsEditing(true);
+    }
+
+    @computed get showKeys() {
+        const whitelistKeys = ["context", "author", "*lastModified", "text", "data", "tags", "creationDate"];
+        const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+        const showKeys = new Set<string>();
+        [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.UserDoc().noviceMode ||
+            whitelistKeys.includes(key)
+            || ((!key.startsWith("_") && key[0] === key[0].toUpperCase()) || key[0] === "#")) ? showKeys.add(key) : null);
+        return Array.from(showKeys.keys()).filter(key => !this._searchTerm || key.includes(this._searchTerm));
+    }
+    @action
+    renderOptions = (): JSX.Element[] | JSX.Element => {
+        if (!this._isOpen) {
+            this.defaultMenuHeight = 0;
+            return <></>;
+        }
+        const options = this.showKeys.map(key => {
+            return <div key={key} className="key-option" style={{
+                border: "1px solid lightgray",
+                width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
+            }}
+                onPointerDown={e => {
+                    e.stopPropagation();
+                }}
+                onClick={() => {
+                    this.onSelect(key);
+                    this.setSearchTerm("");
+                }}>{key}</div>;
+        });
+
+        // if search term does not already exist as a group type, give option to create new group type
+
+        if (this._key !== this._searchTerm.slice(0, this._key.length)) {
+            if (this._searchTerm !== "" && this.props.canAddNew) {
+                options.push(<div key={""} className="key-option" style={{
+                    border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
+                }}
+                    onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
+                    Create "{this._searchTerm}" key</div>);
+            }
+        }
+
+        if (options.length === 0) {
+            this.defaultMenuHeight = 0;
+        }
+        else {
+            if (this.props.docs) {
+                const panesize = this.props.docs.length * 30;
+                options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+            }
+            else {
+                options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+            }
+        }
+        return options;
+    }
+
+    docSafe: Doc[] = [];
+
+    @action
+    renderFilterOptions = (): JSX.Element[] | JSX.Element => {
+        if (!this._isOpen || !this.props.dataDoc) {
+            this.defaultMenuHeight = 0;
+            return <></>;
+        }
+        const keyOptions: string[] = [];
+        const colpos = this._searchTerm.indexOf(":");
+        const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+        if (this.docSafe.length === 0) {
+            this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
+        }
+        const docs = this.docSafe;
+        docs.forEach((doc) => {
+            const key = StrCast(doc[this._key]);
+            if (keyOptions.includes(key) === false && key.includes(temp) && key !== "") {
+                keyOptions.push(key);
+            }
+        });
+
+        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+        if (filters === undefined || filters.length === 0 || filters.some(filter => filter.split(":")[0] === this._key) === false) {
+            this.props.col.setColor("rgb(241, 239, 235)");
+            this.closeResultsVisibility = "none";
+        }
+        for (let i = 0; i < (filters?.length ?? 0) - 1; i++) {
+            if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i].split(":")[1]) === false) {
+                keyOptions.push(filters![i + 1]);
+            }
+        }
+        const options = keyOptions.map(key => {
+            let bool = false;
+            if (filters !== undefined) {
+                const ind = filters.findIndex(filter => filter.split(":")[0] === key);
+                const fields = ind === -1 ? undefined : filters[ind].split(":");
+                bool = fields ? fields[1] === "check" : false;
+            }
+            return <div key={key} className="key-option" style={{
+                border: "1px solid lightgray", paddingLeft: 5, textAlign: "left",
+                width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
+            }}
+            >
+                <input type="checkbox"
+                    onPointerDown={e => e.stopPropagation()}
+                    onClick={e => e.stopPropagation()}
+                    onChange={(e) => {
+                        e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, "remove");
+                        e.target.checked === true ? this.closeResultsVisibility = "contents" : console.log("");
+                        e.target.checked === true ? this.props.col.setColor("green") : this.updateFilter();
+                        e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove");
+                    }}
+                    checked={bool}
+                />
+                <span style={{ paddingLeft: 4 }}>
+                    {key}
+                </span>
+
+            </div>;
+        });
+        if (options.length === 0) {
+            this.defaultMenuHeight = 0;
+        }
+        else {
+            if (this.props.docs) {
+                const panesize = this.props.docs.length * 30;
+                options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+            }
+            else {
+                options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+            }
+
+        }
+        return options;
+    }
+
+    @observable defaultMenuHeight = 0;
+
+
+    updateFilter() {
+        const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+        if (filters === undefined || filters.length === 0 || filters.some(filter => filter.split(":")[0] === this._key) === false) {
+            this.props.col.setColor("rgb(241, 239, 235)");
+            this.closeResultsVisibility = "none";
+        }
+    }
+
+    @computed get scriptField() {
+        const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
+        const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+        return script ? () => script : undefined;
+    }
+    filterBackground = () => "rgba(105, 105, 105, 0.432)";
+    @observable filterOpen: boolean | undefined = undefined;
+    closeResultsVisibility: string = "none";
+
+    removeFilters = (e: React.PointerEvent): void => {
+        const keyOptions: string[] = [];
+        if (this.docSafe.length === 0 && this.props.dataDoc) {
+            this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
+        }
+        const docs = this.docSafe;
+        docs.forEach((doc) => {
+            const key = StrCast(doc[this._key]);
+            if (keyOptions.includes(key) === false) {
+                keyOptions.push(key);
+            }
+        });
+
+        Doc.setDocFilter(this.props.Document, this._key, "", "remove");
+        this.props.col.setColor("rgb(241, 239, 235)");
+        this.closeResultsVisibility = "none";
+    }
+    render() {
+        return (
+            <div style={{ display: "flex" }} ref={this.setNode}>
+                <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
+
+                {/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
+                    runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
+                }} /> */}
+
+                <div className="keys-dropdown" style={{ zIndex: 1, width: this.props.width, maxWidth: this.props.width }}>
+                    <input className="keys-search" style={{ width: "100%" }}
+                        ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
+                        onChange={e => this.onChange(e.target.value)}
+                        onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }}
+                        onFocus={this.onFocus} ></input>
+                    <div style={{ display: this.closeResultsVisibility }}>
+                        <FontAwesomeIcon onPointerDown={this.removeFilters} icon={"times-circle"} size="lg"
+                            style={{ cursor: "hand", color: "grey", padding: 2, left: -20, top: -1, height: 15, position: "relative" }} />
+                    </div>
+                    {!this._isOpen ? (null) : <div className="keys-options-wrapper" style={{
+                        width: this.props.width, maxWidth: this.props.width, height: "auto",
+                    }}>
+                        {this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()}
+                    </div>}
+                </div >
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
new file mode 100644
index 000000000..456c38c68
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
@@ -0,0 +1,128 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action } from "mobx";
+import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
+import { Doc } from "../../../../fields/Doc";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { Cast, FieldValue, StrCast } from "../../../../fields/Types";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { DragManager, dropActionType, SetupDrag } from "../../../util/DragManager";
+import { SnappingManager } from "../../../util/SnappingManager";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { ContextMenu } from "../../ContextMenu";
+import "./CollectionSchemaView.scss";
+
+export interface MovableColumnProps {
+    columnRenderer: TableCellRenderer;
+    columnValue: SchemaHeaderField;
+    allColumns: SchemaHeaderField[];
+    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
+    ScreenToLocalTransform: () => Transform;
+}
+export class MovableColumn extends React.Component<MovableColumnProps> {
+    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
+    private _colDropDisposer?: DragManager.DragDropDisposer;
+    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
+    private _sensitivity: number = 16;
+    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+
+    onPointerEnter = (e: React.PointerEvent): void => {
+        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+            this._header!.current!.className = "collectionSchema-col-wrapper";
+            document.addEventListener("pointermove", this.onDragMove, true);
+        }
+    }
+    onPointerLeave = (e: React.PointerEvent): void => {
+        this._header!.current!.className = "collectionSchema-col-wrapper";
+        document.removeEventListener("pointermove", this.onDragMove, true);
+        !e.buttons && document.removeEventListener("pointermove", this.onPointerMove);
+    }
+    onDragMove = (e: PointerEvent): void => {
+        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
+        const rect = this._header!.current!.getBoundingClientRect();
+        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top);
+        const before = x[0] < bounds[0];
+        this._header!.current!.className = "collectionSchema-col-wrapper";
+        if (before) this._header!.current!.className += " col-before";
+        if (!before) this._header!.current!.className += " col-after";
+        e.stopPropagation();
+    }
+
+    createColDropTarget = (ele: HTMLDivElement) => {
+        this._colDropDisposer?.();
+        if (ele) {
+            this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
+        }
+    }
+
+    colDrop = (e: Event, de: DragManager.DropEvent) => {
+        document.removeEventListener("pointermove", this.onDragMove, true);
+        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+        const rect = this._header!.current!.getBoundingClientRect();
+        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top);
+        const before = x[0] < bounds[0];
+        const colDragData = de.complete.columnDragData;
+        if (colDragData) {
+            e.stopPropagation();
+            this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns);
+            return true;
+        }
+        return false;
+    }
+
+    onPointerMove = (e: PointerEvent) => {
+        const onRowMove = (e: PointerEvent) => {
+            e.stopPropagation();
+            e.preventDefault();
+
+            document.removeEventListener("pointermove", onRowMove);
+            document.removeEventListener('pointerup', onRowUp);
+            const dragData = new DragManager.ColumnDragData(this.props.columnValue);
+            DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y);
+        };
+        const onRowUp = (): void => {
+            document.removeEventListener("pointermove", onRowMove);
+            document.removeEventListener('pointerup', onRowUp);
+        };
+        if (e.buttons === 1) {
+            const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
+            if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
+                document.removeEventListener("pointermove", this.onPointerMove);
+                e.stopPropagation();
+
+                document.addEventListener("pointermove", onRowMove);
+                document.addEventListener("pointerup", onRowUp);
+            }
+        }
+    }
+
+    onPointerUp = (e: React.PointerEvent) => {
+        document.removeEventListener("pointermove", this.onPointerMove);
+    }
+
+    @action
+    onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => {
+        this._dragRef = ref;
+        const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY);
+        if (!(e.target as any)?.tagName.includes("INPUT")) {
+            this._startDragPosition = { x: dx, y: dy };
+            document.addEventListener("pointermove", this.onPointerMove);
+        }
+    }
+
+
+    render() {
+        const reference = React.createRef<HTMLDivElement>();
+
+        return (
+            <div className="collectionSchema-col" ref={this.createColDropTarget}>
+                <div className="collectionSchema-col-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+                    <div className="col-dragger" ref={reference} onPointerDown={e => this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}>
+                        {this.props.columnRenderer}
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
new file mode 100644
index 000000000..f48906ba5
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
@@ -0,0 +1,147 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action } from "mobx";
+import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
+import { Doc } from "../../../../fields/Doc";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { Cast, FieldValue, StrCast } from "../../../../fields/Types";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { DragManager, dropActionType, SetupDrag } from "../../../util/DragManager";
+import { SnappingManager } from "../../../util/SnappingManager";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { ContextMenu } from "../../ContextMenu";
+import "./CollectionSchemaView.scss";
+
+export interface MovableRowProps {
+    rowInfo: RowInfo;
+    ScreenToLocalTransform: () => Transform;
+    addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
+    removeDoc: (doc: Doc | Doc[]) => boolean;
+    rowFocused: boolean;
+    textWrapRow: (doc: Doc) => void;
+    rowWrapped: boolean;
+    dropAction: string;
+    addDocTab: any;
+}
+
+export class MovableRow extends React.Component<MovableRowProps> {
+    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
+    private _rowDropDisposer?: DragManager.DragDropDisposer;
+
+    // Event listeners are only necessary when the user is hovering over the table
+    // Create one when the mouse starts hovering...
+    onPointerEnter = (e: React.PointerEvent): void => {
+        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+            this._header!.current!.className = "collectionSchema-row-wrapper";
+            document.addEventListener("pointermove", this.onDragMove, true);
+        }
+    }
+    // ... and delete it when the mouse leaves
+    onPointerLeave = (e: React.PointerEvent): void => {
+        this._header!.current!.className = "collectionSchema-row-wrapper";
+        document.removeEventListener("pointermove", this.onDragMove, true);
+    }
+    // The method for the event listener, reorders columns when dragged to their new locations.
+    onDragMove = (e: PointerEvent): void => {
+        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
+        const rect = this._header!.current!.getBoundingClientRect();
+        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
+        const before = x[1] < bounds[1];
+        this._header!.current!.className = "collectionSchema-row-wrapper";
+        if (before) this._header!.current!.className += " row-above";
+        if (!before) this._header!.current!.className += " row-below";
+        e.stopPropagation();
+    }
+    componentWillUnmount() {
+
+        this._rowDropDisposer?.();
+    }
+    //
+    createRowDropTarget = (ele: HTMLDivElement) => {
+        this._rowDropDisposer?.();
+        if (ele) {
+            this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
+        }
+    }
+    // Controls what hppens when a row is dragged and dropped
+    rowDrop = (e: Event, de: DragManager.DropEvent) => {
+        this.onPointerLeave(e as any);
+        const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc));
+        if (!rowDoc) return false;
+
+        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+        const rect = this._header!.current!.getBoundingClientRect();
+        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
+        const before = x[1] < bounds[1];
+
+        const docDragData = de.complete.docDragData;
+        if (docDragData) {
+            e.stopPropagation();
+            if (docDragData.draggedDocuments[0] === rowDoc) return true;
+            const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before);
+            const movedDocs = docDragData.draggedDocuments;
+            return (docDragData.dropAction || docDragData.userDropAction) ?
+                docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false)
+                : (docDragData.moveDocument) ?
+                    movedDocs.reduce((added: boolean, d) => docDragData.moveDocument?.(d, rowDoc, addDocument) || added, false)
+                    : docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before), false);
+        }
+        return false;
+    }
+
+    onRowContextMenu = (e: React.MouseEvent): void => {
+        const description = this.props.rowWrapped ? "Unwrap text on row" : "Text wrap row";
+        ContextMenu.Instance.addItem({ description: description, event: () => this.props.textWrapRow(this.props.rowInfo.original), icon: "file-pdf" });
+    }
+
+    @undoBatch
+    @action
+    move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => {
+        const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection);
+        return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
+    }
+
+    @action
+    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+        console.log("yes");
+        if (e.key === "Backspace" || e.key === "Delete") {
+            undoBatch(() => this.props.removeDoc(this.props.rowInfo.original));
+        }
+    }
+
+    render() {
+        const { children = null, rowInfo } = this.props;
+
+        if (!rowInfo) {
+            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
+        }
+
+        const { original } = rowInfo;
+        const doc = FieldValue(Cast(original, Doc));
+
+        if (!doc) return (null);
+
+        const reference = React.createRef<HTMLDivElement>();
+        const onItemDown = SetupDrag(reference, () => doc, this.move, StrCast(this.props.dropAction) as dropActionType);
+
+        let className = "collectionSchema-row";
+        if (this.props.rowFocused) className += " row-focused";
+        if (this.props.rowWrapped) className += " row-wrapped";
+
+        return (
+            <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
+                <div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+                    <ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown} >
+                        <div className="row-dragger">
+                            <div className="row-option" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
+                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
+                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
+                        </div>
+                        {children}
+                    </ReactTableDefaults.TrComponent>
+                </div>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaView.scss b/src/client/views/collections/schemaView/CollectionSchemaView.scss
new file mode 100644
index 000000000..b57fee0e4
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaView.scss
@@ -0,0 +1,552 @@
+@import "../../globalCssVariables";
+.collectionSchemaView-container {
+    border-width: $COLLECTION_BORDER_WIDTH;
+    border-color: $intermediate-color;
+    border-style: solid;
+    border-radius: $border-radius;
+    box-sizing: border-box;
+    position: relative;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    margin-top: 0;
+    transition: top 0.5s;
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: nowrap;
+    touch-action: none;
+    div {
+        touch-action: none;
+    }
+    .collectionSchemaView-tableContainer {
+        width: 100%;
+        height: 100%;
+    }
+    .collectionSchemaView-dividerDragger {
+        position: relative;
+        height: 100%;
+        width: $SCHEMA_DIVIDER_WIDTH;
+        z-index: 20;
+        right: 0;
+        top: 0;
+        background: gray;
+        cursor: col-resize;
+    }
+    // .documentView-node:first-child {
+    //     background: $light-color;
+    // }
+}
+
+.collectionSchemaView-searchContainer {
+    border-width: $COLLECTION_BORDER_WIDTH;
+    border-color: $intermediate-color;
+    border-style: solid;
+    border-radius: $border-radius;
+    box-sizing: border-box;
+    position: relative;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    margin-top: 0;
+    transition: top 0.5s;
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: nowrap;
+    touch-action: none;
+    padding: 2px;
+    div {
+        touch-action: none;
+    }
+    .collectionSchemaView-tableContainer {
+        width: 100%;
+        height: 100%;
+    }
+    .collectionSchemaView-dividerDragger {
+        position: relative;
+        height: 100%;
+        width: 20px;
+        z-index: 20;
+        right: 0;
+        top: 0;
+        background: gray;
+        cursor: col-resize;
+    }
+    // .documentView-node:first-child {
+    //     background: $light-color;
+    // }
+}
+
+.ReactTable {
+    width: 100%;
+    background: white;
+    box-sizing: border-box;
+    border: none !important;
+    float: none !important;
+    .rt-table {
+        height: 100%;
+        display: -webkit-inline-box;
+        direction: ltr;
+        overflow: visible;
+    }
+    .rt-noData {
+        display: none;
+    }
+    .rt-thead {
+        width: 100%;
+        z-index: 100;
+        overflow-y: visible;
+        &.-header {
+            font-size: 12px;
+            height: 30px;
+            box-shadow: none;
+            z-index: 100;
+            overflow-y: visible;
+        }
+        .rt-resizable-header-content {
+            height: 100%;
+            overflow: visible;
+        }
+        .rt-th {
+            padding: 0;
+            border: solid lightgray;
+            border-width: 0 1px;
+            border-bottom: 2px solid lightgray;
+        }
+    }
+    .rt-th {
+        font-size: 13px;
+        text-align: center;
+        &:last-child {
+            overflow: visible;
+        }
+    }
+    .rt-tbody {
+        width: 100%;
+        direction: rtl;
+        overflow: visible;
+        .rt-td {
+            border-right: 1px solid rgba(0, 0, 0, 0.2);
+        }
+    }
+    .rt-tr-group {
+        direction: ltr;
+        flex: 0 1 auto;
+        min-height: 30px;
+        border: 0 !important;
+    }
+    .rt-tr {
+        width: 100%;
+        min-height: 30px;
+    }
+    .rt-td {
+        padding: 0;
+        font-size: 13px;
+        text-align: center;
+        white-space: nowrap;
+        display: flex;
+        align-items: center;
+        .imageBox-cont {
+            position: relative;
+            max-height: 100%;
+        }
+        .imageBox-cont img {
+            object-fit: contain;
+            max-width: 100%;
+            height: 100%;
+        }
+        .videoBox-cont {
+            object-fit: contain;
+            width: auto;
+            height: 100%;
+        }
+    }
+    .rt-td.rt-expandable {
+        display: flex;
+        align-items: center;
+        height: inherit;
+    }
+    .rt-resizer {
+        width: 8px;
+        right: -4px;
+    }
+    .rt-resizable-header {
+        padding: 0;
+        height: 30px;
+    }
+    .rt-resizable-header:last-child {
+        overflow: visible;
+        .rt-resizer {
+            width: 5px !important;
+        }
+    }
+}
+
+.documentView-node-topmost {
+    text-align: left;
+    transform-origin: center top;
+    display: inline-block;
+}
+
+.collectionSchema-col {
+    height: 100%;
+}
+
+.collectionSchema-header-menu {
+    height: auto;
+    z-index: 100;
+    position: absolute;
+    background: white;
+    padding: 5px;
+    position: fixed;
+    background: white;
+    border: black 1px solid;
+    .collectionSchema-header-toggler {
+        z-index: 100;
+        width: 100%;
+        height: 100%;
+        padding: 4px;
+        letter-spacing: 2px;
+        text-transform: uppercase;
+        svg {
+            margin-right: 4px;
+        }
+    }
+}
+
+.collectionSchemaView-header {
+    height: 100%;
+    color: gray;
+    z-index: 100;
+    overflow-y: visible;
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+}
+
+button.add-column {
+    width: 28px;
+}
+
+.collectionSchema-header-menuOptions {
+    color: black;
+    width: 180px;
+    text-align: left;
+    .collectionSchema-headerMenu-group {
+        padding: 7px 0;
+        border-bottom: 1px solid lightgray;
+        cursor: pointer;
+        &:first-child {
+            padding-top: 0;
+        }
+        &:last-child {
+            border: none;
+            text-align: center;
+            padding: 12px 0 0 0;
+        }
+    }
+    label {
+        color: $main-accent;
+        font-weight: normal;
+        letter-spacing: 2px;
+        text-transform: uppercase;
+    }
+    input {
+        color: black;
+        width: 100%;
+    }
+    .columnMenu-option {
+        cursor: pointer;
+        padding: 3px;
+        background-color: white;
+        transition: background-color 0.2s;
+        &:hover {
+            background-color: $light-color-secondary;
+        }
+        &.active {
+            font-weight: bold;
+            border: 2px solid $light-color-secondary;
+        }
+        svg {
+            color: gray;
+            margin-right: 5px;
+            width: 10px;
+        }
+    }
+    .keys-dropdown {
+        position: relative;
+        //width: 100%;
+        background-color: white;
+        input {
+            border: 2px solid $light-color-secondary;
+            padding: 3px;
+            height: 28px;
+            font-weight: bold;
+            letter-spacing: "2px";
+            text-transform: "uppercase";
+            &:focus {
+                font-weight: normal;
+            }
+        }
+        .keys-options-wrapper {
+            width: 100%;
+            max-height: 150px;
+            overflow-y: scroll;
+            position: absolute;
+            top: 28px;
+            box-shadow: 0 10px 16px rgba(0, 0, 0, 0.1);
+            background-color: white;
+            .key-option {
+                background-color: white;
+                border: 1px solid lightgray;
+                padding: 2px 3px;
+                &:not(:first-child) {
+                    border-top: 0;
+                }
+                &:hover {
+                    background-color: $light-color-secondary;
+                }
+            }
+        }
+    }
+    .columnMenu-colors {
+        display: flex;
+        justify-content: space-between;
+        flex-wrap: wrap;
+        .columnMenu-colorPicker {
+            cursor: pointer;
+            width: 20px;
+            height: 20px;
+            border-radius: 10px;
+            &.active {
+                border: 2px solid white;
+                box-shadow: 0 0 0 2px lightgray;
+            }
+        }
+    }
+}
+
+.collectionSchema-row {
+    height: 100%;
+    background-color: white;
+    &.row-focused .rt-td {
+        background-color: #bfffc0; //$light-color-secondary;
+    }
+    &.row-wrapped {
+        .rt-td {
+            white-space: normal;
+        }
+    }
+    .row-dragger {
+        display: flex;
+        justify-content: space-around;
+        //flex: 50 0 auto;
+        width: 0;
+        max-width: 50px;
+        //height: 100%;
+        min-height: 30px;
+        align-items: center;
+        color: lightgray;
+        background-color: white;
+        transition: color 0.1s ease;
+        .row-option {
+            // padding: 5px;
+            cursor: pointer;
+            position: absolute;
+            transition: color 0.1s ease;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            z-index: 2;
+            &:hover {
+                color: gray;
+            }
+        }
+    }
+    .collectionSchema-row-wrapper {
+        &.row-above {
+            border-top: 1px solid red;
+        }
+        &.row-below {
+            border-bottom: 1px solid red;
+        }
+        &.row-inside {
+            border: 1px solid red;
+        }
+        .row-dragging {
+            background-color: blue;
+        }
+    }
+}
+
+.collectionSchemaView-cellContainer {
+    width: 100%;
+    height: unset;
+}
+
+.collectionSchemaView-cellWrapper {
+    height: 100%;
+    padding: 4px;
+    text-align: left;
+    padding-left: 19px;
+    position: relative;
+    &:focus {
+        outline: none;
+    }
+    &.editing {
+        padding: 0;
+        input {
+            outline: 0;
+            border: none;
+            background-color: rgb(255, 217, 217);
+            width: 100%;
+            height: 100%;
+            padding: 2px 3px;
+            min-height: 26px;
+        }
+    }
+    &.focused {
+        &.inactive {
+            border: none;
+        }
+    }
+    p {
+        width: 100%;
+        height: 100%;
+    }
+    &:hover .collectionSchemaView-cellContents-docExpander {
+        display: block;
+    }
+    .collectionSchemaView-cellContents-document {
+        display: inline-block;
+    }
+    .collectionSchemaView-cellContents-docButton {
+        float: right;
+        width: "15px";
+        height: "15px";
+    }
+    .collectionSchemaView-dropdownWrapper {
+        border: grey;
+        border-style: solid;
+        border-width: 1px;
+        height: 30px;
+        .collectionSchemaView-dropdownButton {
+            //display: inline-block;
+            float: left;
+            height: 100%;
+        }
+        .collectionSchemaView-dropdownText {
+            display: inline-block;
+            //float: right;
+            height: 100%;
+            display: "flex";
+            font-size: 13;
+            justify-content: "center";
+            align-items: "center";
+        }
+    }
+    .collectionSchemaView-dropdownContainer {
+        position: absolute;
+        border: 1px solid rgba(0, 0, 0, 0.04);
+        box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14);
+        .collectionSchemaView-dropdownOption:hover {
+            background-color: rgba(0, 0, 0, 0.14);
+            cursor: pointer;
+        }
+    }
+}
+
+.collectionSchemaView-cellContents-docExpander {
+    height: 30px;
+    width: 30px;
+    display: none;
+    position: absolute;
+    top: 0;
+    right: 0;
+    background-color: lightgray;
+}
+
+.doc-drag-over {
+    background-color: red;
+}
+
+.collectionSchemaView-toolbar {
+    z-index: 100;
+}
+
+.collectionSchemaView-toolbar {
+    height: 30px;
+    display: flex;
+    justify-content: flex-end;
+    padding: 0 10px;
+    border-bottom: 2px solid gray;
+    .collectionSchemaView-toolbar-item {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+    }
+}
+
+#preview-schema-checkbox-div {
+    margin-left: 20px;
+    font-size: 12px;
+}
+
+.collectionSchemaView-table {
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    padding: 3px;
+}
+
+.rt-td.rt-expandable {
+    overflow: visible;
+    position: relative;
+    height: 100%;
+    z-index: 1;
+}
+
+.reactTable-sub {
+    background-color: rgb(252, 252, 252);
+    width: 100%;
+    .rt-thead {
+        display: none;
+    }
+    .row-dragger {
+        background-color: rgb(252, 252, 252);
+    }
+    .rt-table {
+        background-color: rgb(252, 252, 252);
+    }
+    .collectionSchemaView-table {
+        width: 100%;
+        border: solid 1px;
+        overflow: visible;
+        padding: 0px;
+    }
+}
+
+.collectionSchemaView-expander {
+    height: 100%;
+    min-height: 30px;
+    position: absolute;
+    color: gray;
+    width: 20;
+    height: auto;
+    left: 55;
+    svg {
+        position: absolute;
+        top: 50%;
+        left: 10;
+        transform: translate(-50%, -50%);
+    }
+}
+
+.collectionSchemaView-addRow {
+    color: gray;
+    letter-spacing: 2px;
+    text-transform: uppercase;
+    cursor: pointer;
+    font-size: 10.5px;
+    margin-left: 50px;
+    margin-top: 10px;
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaView.tsx b/src/client/views/collections/schemaView/CollectionSchemaView.tsx
new file mode 100644
index 000000000..ef28f75c8
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaView.tsx
@@ -0,0 +1,575 @@
+import React = require("react");
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, untracked } from "mobx";
+import { observer } from "mobx-react";
+import Measure from "react-measure";
+import { Resize } from "react-table";
+import "react-table/react-table.css";
+import { Doc, Opt } from "../../../../fields/Doc";
+import { List } from "../../../../fields/List";
+import { listSpec } from "../../../../fields/Schema";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { Cast, NumCast } from "../../../../fields/Types";
+import { TraceMobx } from "../../../../fields/util";
+import { emptyFunction, emptyPath, returnFalse, setupMoveUpEvents, returnEmptyDoclist, returnTrue } from "../../../../Utils";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { SnappingManager } from "../../../util/SnappingManager";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../globalCssVariables.scss';
+import { ContextMenu } from "../../ContextMenu";
+import { ContextMenuProps } from "../../ContextMenuItem";
+import '../../../views/DocumentDecorations.scss';
+import { DocumentView } from "../../nodes/DocumentView";
+import { DefaultStyleProvider } from "../../StyleProvider";
+import "./CollectionSchemaView.scss";
+import { CollectionSubView } from "../CollectionSubView";
+import { SchemaTable } from "./SchemaTable";
+import { DocUtils } from "../../../documents/Documents";
+// bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
+
+export enum ColumnType {
+    Any,
+    Number,
+    String,
+    Boolean,
+    Doc,
+    Image,
+    List,
+    Date
+}
+// this map should be used for keys that should have a const type of value
+const columnTypes: Map<string, ColumnType> = new Map([
+    ["title", ColumnType.String],
+    ["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
+    ["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
+    ["_curPage", ColumnType.Number], ["_currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
+]);
+
+@observer
+export class CollectionSchemaView extends CollectionSubView(doc => doc) {
+    private _previewCont?: HTMLDivElement;
+
+    @observable _previewDoc: Doc | undefined = undefined;
+    @observable _focusedTable: Doc = this.props.Document;
+    @observable _col: any = "";
+    @observable _menuWidth = 0;
+    @observable _headerOpen = false;
+    @observable _headerIsEditing = false;
+    @observable _menuHeight = 0;
+    @observable _pointerX = 0;
+    @observable _pointerY = 0;
+    @observable _openTypes: boolean = false;
+
+    @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
+    @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; }
+    @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); }
+    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
+    @computed get scale() { return this.props.ScreenToLocalTransform().Scale; }
+    @computed get columns() { return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); }
+    set columns(columns: SchemaHeaderField[]) { this.props.Document._schemaHeaders = new List<SchemaHeaderField>(columns); }
+
+    @computed get menuCoordinates() {
+        let searchx = 0;
+        let searchy = 0;
+        if (this.props.Document._searchDoc) {
+            const el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0];
+            if (el !== undefined) {
+                const rect = el.getBoundingClientRect();
+                searchx = rect.x;
+                searchy = rect.y;
+            }
+        }
+        const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
+        const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
+        return this.props.ScreenToLocalTransform().transformPoint(x, y);
+    }
+
+    get documentKeys() {
+        const docs = this.childDocs;
+        const keys: { [key: string]: boolean } = {};
+        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
+        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
+        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
+        //  is displayed (unlikely) it won't show up until something else changes.
+        //TODO Types
+        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false))));
+
+        this.columns.forEach(key => keys[key.heading] = true);
+        return Array.from(Object.keys(keys));
+    }
+
+    @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
+
+    @undoBatch
+    setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => {
+        this._openTypes = false;
+        if (columnTypes.get(columnField.heading)) return;
+
+        const columns = this.columns;
+        const index = columns.indexOf(columnField);
+        if (index > -1) {
+            columnField.setType(NumCast(type));
+            columns[index] = columnField;
+            this.columns = columns;
+        }
+    });
+
+    @undoBatch
+    setColumnColor = (columnField: SchemaHeaderField, color: string): void => {
+        const columns = this.columns;
+        const index = columns.indexOf(columnField);
+        if (index > -1) {
+            columnField.setColor(color);
+            columns[index] = columnField;
+            this.columns = columns; // need to set the columns to trigger rerender
+        }
+    }
+
+    @undoBatch
+    @action
+    setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => {
+        const columns = this.columns;
+        columns.forEach(col => col.setDesc(undefined));
+
+        const index = columns.findIndex(c => c.heading === columnField.heading);
+        const column = columns[index];
+        column.setDesc(descending);
+        columns[index] = column;
+        this.columns = columns;
+    }
+
+    renderTypes = (col: any) => {
+        if (columnTypes.get(col.heading)) return (null);
+
+        const type = col.type;
+
+        const anyType = <div className={"columnMenu-option" + (type === ColumnType.Any ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Any)}>
+            <FontAwesomeIcon icon={"align-justify"} size="sm" />
+                Any
+            </div>;
+
+        const numType = <div className={"columnMenu-option" + (type === ColumnType.Number ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Number)}>
+            <FontAwesomeIcon icon={"hashtag"} size="sm" />
+                Number
+            </div>;
+
+        const textType = <div className={"columnMenu-option" + (type === ColumnType.String ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.String)}>
+            <FontAwesomeIcon icon={"font"} size="sm" />
+            Text
+            </div>;
+
+        const boolType = <div className={"columnMenu-option" + (type === ColumnType.Boolean ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Boolean)}>
+            <FontAwesomeIcon icon={"check-square"} size="sm" />
+            Checkbox
+            </div>;
+
+        const listType = <div className={"columnMenu-option" + (type === ColumnType.List ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.List)}>
+            <FontAwesomeIcon icon={"list-ul"} size="sm" />
+            List
+            </div>;
+
+        const docType = <div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Doc)}>
+            <FontAwesomeIcon icon={"file"} size="sm" />
+            Document
+            </div>;
+
+        const imageType = <div className={"columnMenu-option" + (type === ColumnType.Image ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Image)}>
+            <FontAwesomeIcon icon={"image"} size="sm" />
+            Image
+            </div>;
+
+        const dateType = <div className={"columnMenu-option" + (type === ColumnType.Date ? " active" : "")} onClick={() => this.setColumnType(col, ColumnType.Date)}>
+            <FontAwesomeIcon icon={"calendar"} size="sm" />
+                Date
+                </div>;
+
+
+        const allColumnTypes = <div className="columnMenu-types">
+            {anyType}
+            {numType}
+            {textType}
+            {boolType}
+            {listType}
+            {docType}
+            {imageType}
+            {dateType}
+        </div>;
+
+        const justColType = type === ColumnType.Any ? anyType : type === ColumnType.Number ? numType :
+            type === ColumnType.String ? textType : type === ColumnType.Boolean ? boolType :
+                type === ColumnType.List ? listType : type === ColumnType.Doc ? docType :
+                    type === ColumnType.Date ? dateType : imageType;
+
+        return (
+            <div className="collectionSchema-headerMenu-group" onClick={action(() => this._openTypes = !this._openTypes)}>
+                <div>
+                    <label style={{ cursor: "pointer" }}>Column type:</label>
+                    <FontAwesomeIcon icon={"caret-down"} size="lg" style={{ float: "right", transform: `rotate(${this._openTypes ? "180deg" : 0})`, transition: "0.2s all ease" }} />
+                </div>
+                {this._openTypes ? allColumnTypes : justColType}
+            </div >
+        );
+    }
+
+    renderSorting = (col: any) => {
+        const sort = col.desc;
+        return (
+            <div className="collectionSchema-headerMenu-group">
+                <label>Sort by:</label>
+                <div className="columnMenu-sort">
+                    <div className={"columnMenu-option" + (sort === true ? " active" : "")} onClick={() => this.setColumnSort(col, true)}>
+                        <FontAwesomeIcon icon="sort-amount-down" size="sm" />
+                        Sort descending
+                    </div>
+                    <div className={"columnMenu-option" + (sort === false ? " active" : "")} onClick={() => this.setColumnSort(col, false)}>
+                        <FontAwesomeIcon icon="sort-amount-up" size="sm" />
+                        Sort ascending
+                    </div>
+                    <div className="columnMenu-option" onClick={() => this.setColumnSort(col, undefined)}>
+                        <FontAwesomeIcon icon="times" size="sm" />
+                        Clear sorting
+                    </div>
+                </div>
+            </div>
+        );
+    }
+
+    renderColors = (col: any) => {
+        const selected = col.color;
+
+        const pink = PastelSchemaPalette.get("pink2");
+        const purple = PastelSchemaPalette.get("purple2");
+        const blue = PastelSchemaPalette.get("bluegreen1");
+        const yellow = PastelSchemaPalette.get("yellow4");
+        const red = PastelSchemaPalette.get("red2");
+        const gray = "#f1efeb";
+
+        return (
+            <div className="collectionSchema-headerMenu-group">
+                <label>Color:</label>
+                <div className="columnMenu-colors">
+                    <div className={"columnMenu-colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.setColumnColor(col, pink!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.setColumnColor(col, purple!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.setColumnColor(col, blue!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.setColumnColor(col, yellow!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.setColumnColor(col, red!)}></div>
+                    <div className={"columnMenu-colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.setColumnColor(col, gray)}></div>
+                </div>
+            </div>
+        );
+    }
+
+    @undoBatch
+    @action
+    changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => {
+        const columns = this.columns;
+        if (columns === undefined) {
+            this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, "f1efeb")]);
+        } else {
+            if (addNew) {
+                columns.push(new SchemaHeaderField(newKey, "f1efeb"));
+                this.columns = columns;
+            } else {
+                const index = columns.map(c => c.heading).indexOf(oldKey);
+                if (index > -1) {
+                    const column = columns[index];
+                    column.setHeading(newKey);
+                    columns[index] = column;
+                    this.columns = columns;
+                    if (filter) {
+                        Doc.setDocFilter(this.props.Document, newKey, filter, "match");
+                    }
+                    else {
+                        this.props.Document._docFilters = undefined;
+                    }
+                }
+            }
+        }
+    }
+
+    @action
+    openHeader = (col: any, screenx: number, screeny: number) => {
+        this._col = col;
+        this._headerOpen = true;
+        this._pointerX = screenx;
+        this._pointerY = screeny;
+    }
+
+    @action
+    closeHeader = () => { this._headerOpen = false; }
+
+    @undoBatch
+    @action
+    deleteColumn = (key: string) => {
+        const columns = this.columns;
+        if (columns === undefined) {
+            this.columns = new List<SchemaHeaderField>([]);
+        } else {
+            const index = columns.map(c => c.heading).indexOf(key);
+            if (index > -1) {
+                columns.splice(index, 1);
+                this.columns = columns;
+            }
+        }
+        this.closeHeader();
+    }
+
+    getPreviewTransform = (): Transform => {
+        return this.props.ScreenToLocalTransform().translate(- this.borderWidth - NumCast(COLLECTION_BORDER_WIDTH) - this.tableWidth, - this.borderWidth);
+    }
+
+    @action
+    onHeaderClick = (e: React.PointerEvent) => {
+        e.stopPropagation();
+    }
+
+    @action
+    onWheel(e: React.WheelEvent) {
+        const scale = this.props.ScreenToLocalTransform().Scale;
+        this.props.isContentActive(true) && e.stopPropagation();
+    }
+
+    @computed get renderMenuContent() {
+        TraceMobx();
+        return <div className="collectionSchema-header-menuOptions">
+            {this.renderTypes(this._col)}
+            {this.renderColors(this._col)}
+            <div className="collectionSchema-headerMenu-group">
+                <button onClick={() => { this.deleteColumn(this._col.heading); }}
+                >Delete Column</button>
+            </div>
+        </div>;
+    }
+
+    private createTarget = (ele: HTMLDivElement) => {
+        this._previewCont = ele;
+        super.CreateDropTarget(ele);
+    }
+
+    isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
+
+    @action setFocused = (doc: Doc) => this._focusedTable = doc;
+
+    @action setPreviewDoc = (doc: Opt<Doc>) => {
+        SelectionManager.SelectSchemaView(this, doc);
+        this._previewDoc = doc;
+    }
+
+    //toggles preview side-panel of schema
+    @action
+    toggleExpander = () => {
+        this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0;
+    }
+
+    onDividerDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, this.toggleExpander);
+    }
+    @action
+    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
+        const nativeWidth = this._previewCont!.getBoundingClientRect();
+        const minWidth = 40;
+        const maxWidth = 1000;
+        const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
+        const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
+        this.props.Document.schemaPreviewWidth = width;
+        return false;
+    }
+
+    onPointerDown = (e: React.PointerEvent): void => {
+        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
+            if (this.props.isSelected(true)) e.stopPropagation();
+            else this.props.select(false);
+        }
+    }
+
+    @computed
+    get previewDocument(): Doc | undefined { return this._previewDoc; }
+
+    @computed
+    get dividerDragger() {
+        return this.previewWidth() === 0 ? (null) :
+            <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} >
+                <div className="collectionSchemaView-dividerDragger" />
+            </div>;
+    }
+
+    @computed
+    get previewPanel() {
+        return <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
+            {!this.previewDocument ? (null) :
+                <DocumentView
+                    Document={this.previewDocument}
+                    DataDoc={undefined}
+                    fitContentsToDoc={returnTrue}
+                    freezeDimensions={true}
+                    dontCenter={"y"}
+                    focus={DocUtils.DefaultFocus}
+                    renderDepth={this.props.renderDepth}
+                    rootSelected={this.rootSelected}
+                    PanelWidth={this.previewWidth}
+                    PanelHeight={this.previewHeight}
+                    isContentActive={returnTrue}
+                    isDocumentActive={returnFalse}
+                    ScreenToLocalTransform={this.getPreviewTransform}
+                    docFilters={this.docFilters}
+                    docRangeFilters={this.docRangeFilters}
+                    searchFilterDocs={this.searchFilterDocs}
+                    styleProvider={DefaultStyleProvider}
+                    layerProvider={undefined}
+                    docViewPath={returnEmptyDoclist}
+                    ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                    ContainingCollectionView={this.props.CollectionView}
+                    moveDocument={this.props.moveDocument}
+                    addDocument={this.props.addDocument}
+                    removeDocument={this.props.removeDocument}
+                    whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                    addDocTab={this.props.addDocTab}
+                    pinToPres={this.props.pinToPres}
+                    bringToFront={returnFalse}
+                />}
+        </div>;
+    }
+
+    @computed
+    get schemaTable() {
+        return <SchemaTable
+            Document={this.props.Document}
+            PanelHeight={this.props.PanelHeight}
+            PanelWidth={this.props.PanelWidth}
+            childDocs={this.childDocs}
+            CollectionView={this.props.CollectionView}
+            ContainingCollectionView={this.props.ContainingCollectionView}
+            ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+            fieldKey={this.props.fieldKey}
+            renderDepth={this.props.renderDepth}
+            moveDocument={this.props.moveDocument}
+            ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+            active={this.props.isContentActive}
+            onDrop={this.onExternalDrop}
+            addDocTab={this.props.addDocTab}
+            pinToPres={this.props.pinToPres}
+            isSelected={this.props.isSelected}
+            isFocused={this.isFocused}
+            setFocused={this.setFocused}
+            setPreviewDoc={this.setPreviewDoc}
+            deleteDocument={this.props.removeDocument}
+            addDocument={this.props.addDocument}
+            dataDoc={this.props.DataDoc}
+            columns={this.columns}
+            documentKeys={this.documentKeys}
+            headerIsEditing={this._headerIsEditing}
+            openHeader={this.openHeader}
+            onClick={this.onTableClick}
+            onPointerDown={emptyFunction}
+            onResizedChange={this.onResizedChange}
+            setColumns={this.setColumns}
+            reorderColumns={this.reorderColumns}
+            changeColumns={this.changeColumns}
+            setHeaderIsEditing={this.setHeaderIsEditing}
+            changeColumnSort={this.setColumnSort}
+        />;
+    }
+
+    @computed
+    public get schemaToolbar() {
+        return <div className="collectionSchemaView-toolbar">
+            <div className="collectionSchemaView-toolbar-item">
+                <div id="preview-schema-checkbox-div">
+                    <input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />
+                    Show Preview
+                </div>
+            </div>
+        </div>;
+    }
+
+    onSpecificMenu = (e: React.MouseEvent) => {
+        if ((e.target as any)?.className?.includes?.("collectionSchemaView-cell") || (e.target instanceof HTMLSpanElement)) {
+            const cm = ContextMenu.Instance;
+            const options = cm.findByDescription("Options...");
+            const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
+            optionItems.push({ description: "remove", event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: "trash" });
+            !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
+            cm.displayMenu(e.clientX, e.clientY);
+            (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this.
+            e.stopPropagation();
+        }
+    }
+
+    @action
+    onTableClick = (e: React.MouseEvent): void => {
+        if (!(e.target as any)?.className?.includes?.("collectionSchemaView-cell") && !(e.target instanceof HTMLSpanElement)) {
+            this.setPreviewDoc(undefined);
+        } else {
+            e.stopPropagation();
+        }
+        this.setFocused(this.props.Document);
+        this.closeHeader();
+    }
+
+    onResizedChange = (newResized: Resize[], event: any) => {
+        const columns = this.columns;
+        newResized.forEach(resized => {
+            const index = columns.findIndex(c => c.heading === resized.id);
+            const column = columns[index];
+            column.setWidth(resized.value);
+            columns[index] = column;
+        });
+        this.columns = columns;
+    }
+
+    @action
+    setColumns = (columns: SchemaHeaderField[]) => this.columns = columns
+
+    @undoBatch
+    reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
+        const columns = [...columnsValues];
+        const oldIndex = columns.indexOf(toMove);
+        const relIndex = columns.indexOf(relativeTo);
+        const newIndex = (oldIndex > relIndex && !before) ? relIndex + 1 : (oldIndex < relIndex && before) ? relIndex - 1 : relIndex;
+
+        if (oldIndex === newIndex) return;
+
+        columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]);
+        this.columns = columns;
+    }
+
+    onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
+
+    render() {
+        TraceMobx();
+        if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
+        const menuContent = this.renderMenuContent;
+        const menu = <div className="collectionSchema-header-menu"
+            onWheel={e => this.onZoomMenu(e)}
+            onPointerDown={e => this.onHeaderClick(e)}
+            style={{ transform: `translate(${(this.menuCoordinates[0])}px, ${(this.menuCoordinates[1])}px)` }}>
+            <Measure offset onResize={action((r: any) => {
+                const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
+                this._menuWidth = dim[0]; this._menuHeight = dim[1];
+            })}>
+                {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
+            </Measure>
+        </div>;
+        return <div className={"collectionSchemaView" + (this.props.Document._searchDoc ? "-searchContainer" : "-container")}
+            style={{
+                overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
+                pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined,
+                width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
+            }}  >
+            <div className="collectionSchemaView-tableContainer"
+                style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
+                onContextMenu={this.onSpecificMenu}
+                onPointerDown={this.onPointerDown}
+                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
+                onDrop={e => this.onExternalDrop(e, {})}
+                ref={this.createTarget}>
+                {this.schemaTable}
+            </div>
+            {this.dividerDragger}
+            {!this.previewWidth() ? (null) : this.previewPanel}
+            {this._headerOpen && this.props.isContentActive() ? menu : null}
+        </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/SchemaTable.tsx b/src/client/views/collections/schemaView/SchemaTable.tsx
new file mode 100644
index 000000000..0d5c9e077
--- /dev/null
+++ b/src/client/views/collections/schemaView/SchemaTable.tsx
@@ -0,0 +1,601 @@
+import React = require("react");
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from "mobx";
+import { observer } from "mobx-react";
+import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
+import "react-table/react-table.css";
+import { DateField } from "../../../../fields/DateField";
+import { AclPrivate, AclReadonly, DataSym, Doc, DocListCast, Field, Opt } from "../../../../fields/Doc";
+import { Id } from "../../../../fields/FieldSymbols";
+import { List } from "../../../../fields/List";
+import { listSpec } from "../../../../fields/Schema";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+import { ComputedField } from "../../../../fields/ScriptField";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
+import { ImageField } from "../../../../fields/URLField";
+import { GetEffectiveAcl } from "../../../../fields/util";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../../Utils";
+import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { CompileScript, Transformer, ts } from "../../../util/Scripting";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../globalCssVariables.scss';
+import { ContextMenu } from "../../ContextMenu";
+import '../../../views/DocumentDecorations.scss';
+import { DocumentView } from "../../nodes/DocumentView";
+import { DefaultStyleProvider } from "../../StyleProvider";
+import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
+import { MovableColumn } from "./CollectionSchemaMovableColumn";
+import { MovableRow } from "./CollectionSchemaMovableRow";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "../CollectionView";
+
+
+enum ColumnType {
+    Any,
+    Number,
+    String,
+    Boolean,
+    Doc,
+    Image,
+    List,
+    Date
+}
+
+// this map should be used for keys that should have a const type of value
+const columnTypes: Map<string, ColumnType> = new Map([
+    ["title", ColumnType.String],
+    ["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
+    ["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
+    ["_curPage", ColumnType.Number], ["_currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
+]);
+
+export interface SchemaTableProps {
+    Document: Doc; // child doc
+    dataDoc?: Doc;
+    PanelHeight: () => number;
+    PanelWidth: () => number;
+    childDocs?: Doc[];
+    CollectionView: Opt<CollectionView>;
+    ContainingCollectionView: Opt<CollectionView>;
+    ContainingCollectionDoc: Opt<Doc>;
+    fieldKey: string;
+    renderDepth: number;
+    deleteDocument?: (document: Doc | Doc[]) => boolean;
+    addDocument?: (document: Doc | Doc[]) => boolean;
+    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+    ScreenToLocalTransform: () => Transform;
+    active: (outsideReaction: boolean | undefined) => boolean;
+    onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
+    addDocTab: (document: Doc, where: string) => boolean;
+    pinToPres: (document: Doc) => void;
+    isSelected: (outsideReaction?: boolean) => boolean;
+    isFocused: (document: Doc, outsideReaction: boolean) => boolean;
+    setFocused: (document: Doc) => void;
+    setPreviewDoc: (document: Opt<Doc>) => void;
+    columns: SchemaHeaderField[];
+    documentKeys: any[];
+    headerIsEditing: boolean;
+    openHeader: (column: any, screenx: number, screeny: number) => void;
+    onClick: (e: React.MouseEvent) => void;
+    onPointerDown: (e: React.PointerEvent) => void;
+    onResizedChange: (newResized: Resize[], event: any) => void;
+    setColumns: (columns: SchemaHeaderField[]) => void;
+    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => void;
+    changeColumns: (oldKey: string, newKey: string, addNew: boolean) => void;
+    setHeaderIsEditing: (isEditing: boolean) => void;
+    changeColumnSort: (columnField: SchemaHeaderField, descending: boolean | undefined) => void;
+}
+
+@observer
+export class SchemaTable extends React.Component<SchemaTableProps> {
+    @observable _cellIsEditing: boolean = false;
+    @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 };
+    @observable _openCollections: Set<number> = new Set;
+
+    @observable _showDoc: Doc | undefined;
+    @observable _showDataDoc: any = "";
+    @observable _showDocPos: number[] = [];
+
+    @observable _showTitleDropdown: boolean = false;
+
+    @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); }
+    @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; }
+    @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); }
+
+    @computed get childDocs() {
+        if (this.props.childDocs) return this.props.childDocs;
+
+        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+        return DocListCast(doc[this.props.fieldKey]);
+    }
+    set childDocs(docs: Doc[]) {
+        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+        doc[this.props.fieldKey] = new List<Doc>(docs);
+    }
+
+    @computed get textWrappedRows() {
+        return Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []);
+    }
+    set textWrappedRows(textWrappedRows: string[]) {
+        this.props.Document.textwrappedSchemaRows = new List<string>(textWrappedRows);
+    }
+
+    @computed get resized(): { id: string, value: number }[] {
+        return this.props.columns.reduce((resized, shf) => {
+            (shf.width > -1) && resized.push({ id: shf.heading, value: shf.width });
+            return resized;
+        }, [] as { id: string, value: number }[]);
+    }
+    @computed get sorted(): SortingRule[] {
+        return this.props.columns.reduce((sorted, shf) => {
+            shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc });
+            return sorted;
+        }, [] as SortingRule[]);
+    }
+
+    @action
+    changeSorting = (col: any) => {
+        this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
+    }
+
+    @action
+    changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown
+
+    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
+    @computed get tableColumns(): Column<Doc>[] {
+        const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
+        const columns: Column<Doc>[] = [];
+        const tableIsFocused = this.props.isFocused(this.props.Document, false);
+        const focusedRow = this._focusedCell.row;
+        const focusedCol = this._focusedCell.col;
+        const isEditable = !this.props.headerIsEditing;
+
+        columns.push({
+            expander: true, Header: "", width: 58,
+            Expander: (rowInfo) => {
+                return rowInfo.original.type !== DocumentType.COL ? (null) :
+                    <div className="collectionSchemaView-expander" onClick={action(() => (this._openCollections[rowInfo.isExpanded ? "delete" : "add"])(rowInfo.viewIndex))}>
+                        <FontAwesomeIcon icon={rowInfo.isExpanded ? "caret-down" : "caret-right"} size="lg" />
+                    </div>;
+            }
+        });
+        columns.push(...this.props.columns.map(col => {
+            const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
+                this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
+                    this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
+                        this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
+
+            const keysDropdown = <KeysDropdown
+                keyValue={col.heading}
+                possibleKeys={possibleKeys}
+                existingKeys={this.props.columns.map(c => c.heading)}
+                canAddNew={true}
+                addNew={false}
+                onSelect={this.props.changeColumns}
+                setIsEditing={this.props.setHeaderIsEditing}
+                docs={this.props.childDocs}
+                Document={this.props.Document}
+                dataDoc={this.props.dataDoc}
+                fieldKey={this.props.fieldKey}
+                ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+                ContainingCollectionView={this.props.ContainingCollectionView}
+                active={this.props.active}
+                openHeader={this.props.openHeader}
+                icon={icon}
+                col={col}
+                // try commenting this out
+                width={"100%"}
+            />;
+
+            const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
+            const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}>
+                {keysDropdown}
+                <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
+                    <FontAwesomeIcon icon={sortIcon} size="lg" />
+                </div>
+            </div>;
+
+            return {
+                Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
+                accessor: (doc: Doc) => doc ? Field.toString(doc[col.heading] as Field) : 0,
+                id: col.heading,
+                Cell: (rowProps: CellInfo) => {
+                    const rowIndex = rowProps.index;
+                    const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+                    const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+
+                    const props: CellProps = {
+                        row: rowIndex,
+                        col: columnIndex,
+                        rowProps: rowProps,
+                        isFocused: isFocused,
+                        changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+                        CollectionView: this.props.CollectionView,
+                        ContainingCollection: this.props.ContainingCollectionView,
+                        Document: this.props.Document,
+                        fieldKey: this.props.fieldKey,
+                        renderDepth: this.props.renderDepth,
+                        addDocTab: this.props.addDocTab,
+                        pinToPres: this.props.pinToPres,
+                        moveDocument: this.props.moveDocument,
+                        setIsEditing: this.setCellIsEditing,
+                        isEditable: isEditable,
+                        setPreviewDoc: this.props.setPreviewDoc,
+                        setComputed: this.setComputed,
+                        getField: this.getField,
+                        showDoc: this.showDoc,
+                    };
+
+
+                    switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) {
+                        case ColumnType.Number: return <CollectionSchemaNumberCell {...props} />;
+                        case ColumnType.String: return <CollectionSchemaStringCell {...props} />;
+                        case ColumnType.Boolean: return <CollectionSchemaCheckboxCell {...props} />;
+                        case ColumnType.Doc: return <CollectionSchemaDocCell {...props} />;
+                        case ColumnType.Image: return <CollectionSchemaImageCell {...props} />;
+                        case ColumnType.List: return <CollectionSchemaListCell {...props} />;
+                        case ColumnType.Date: return <CollectionSchemaDateCell {...props} />;
+                        default:
+                            return <CollectionSchemaCell {...props} />;
+                    }
+                },
+                minWidth: 200,
+            };
+        }));
+        columns.push({
+            Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
+            accessor: (doc: Doc) => 0,
+            id: "add",
+            Cell: (rowProps: CellInfo) => {
+                const rowIndex = rowProps.index;
+                const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+                const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+                return <CollectionSchemaButtons  {...{
+                    row: rowProps.index,
+                    col: columnIndex,
+                    rowProps: rowProps,
+                    isFocused: isFocused,
+                    changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+                    CollectionView: this.props.CollectionView,
+                    ContainingCollection: this.props.ContainingCollectionView,
+                    Document: this.props.Document,
+                    fieldKey: this.props.fieldKey,
+                    renderDepth: this.props.renderDepth,
+                    addDocTab: this.props.addDocTab,
+                    pinToPres: this.props.pinToPres,
+                    moveDocument: this.props.moveDocument,
+                    setIsEditing: this.setCellIsEditing,
+                    isEditable: isEditable,
+                    setPreviewDoc: this.props.setPreviewDoc,
+                    setComputed: this.setComputed,
+                    getField: this.getField,
+                    showDoc: this.showDoc,
+                }} />;
+            },
+            width: 28,
+            resizable: false
+        });
+        return columns;
+    }
+
+
+    constructor(props: SchemaTableProps) {
+        super(props);
+        if (this.props.Document._schemaHeaders === undefined) {
+            this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
+            new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
+        }
+    }
+
+    componentDidMount() {
+        document.addEventListener("keydown", this.onKeyDown);
+    }
+
+    componentWillUnmount() {
+        document.removeEventListener("keydown", this.onKeyDown);
+    }
+
+    tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
+        const tableDoc = this.props.Document[DataSym];
+        const effectiveAcl = GetEffectiveAcl(tableDoc);
+
+        if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) {
+            doc.context = this.props.Document;
+            tableDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+            return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
+        }
+        return false;
+    }
+
+    private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
+        return !rowInfo ? {} : {
+            ScreenToLocalTransform: this.props.ScreenToLocalTransform,
+            addDoc: this.tableAddDoc,
+            removeDoc: this.props.deleteDocument,
+            rowInfo,
+            rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
+            textWrapRow: this.toggleTextWrapRow,
+            rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
+            dropAction: StrCast(this.props.Document.childDropAction),
+            addDocTab: this.props.addDocTab
+        };
+    }
+
+    private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
+        if (!rowInfo || column) return {};
+
+        const row = rowInfo.index;
+        //@ts-ignore
+        const col = this.columns.map(c => c.heading).indexOf(column!.id);
+        const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
+        // TODO: editing border doesn't work :(
+        return {
+            style: { border: !this.props.headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb" }
+        };
+    }
+
+    @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
+
+    @action
+    onKeyDown = (e: KeyboardEvent): void => {
+        if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {// && this.props.isSelected(true)) {
+            const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
+            this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
+
+            if (direction) {
+                const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
+                pdoc && this.props.setPreviewDoc(pdoc);
+                e.stopPropagation();
+            }
+        } else if (e.keyCode === 27) {
+            this.props.setPreviewDoc(undefined);
+            e.stopPropagation(); // stopPropagation for left/right arrows 
+        }
+    }
+
+    changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => {
+        switch (direction) {
+            case "tab": return { row: (curRow + 1 === this.childDocs.length ? 0 : curRow + 1), col: curCol + 1 === this.props.columns.length ? 0 : curCol + 1 };
+            case "right": return { row: curRow, col: curCol + 1 === this.props.columns.length ? curCol : curCol + 1 };
+            case "left": return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 };
+            case "up": return { row: curRow === 0 ? curRow : curRow - 1, col: curCol };
+            case "down": return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol };
+        }
+        return this._focusedCell;
+    }
+
+    @action
+    changeFocusedCellByIndex = (row: number, col: number): void => {
+        if (this._focusedCell.row !== row || this._focusedCell.col !== col) {
+            this._focusedCell = { row: row, col: col };
+        }
+        this.props.setFocused(this.props.Document);
+    }
+
+    @undoBatch
+    createRow = action(() => {
+        this.props.addDocument?.(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }));
+        this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
+    });
+
+    @undoBatch
+    @action
+    createColumn = () => {
+        let index = 0;
+        let found = this.props.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
+        while (found) {
+            index++;
+            found = this.props.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
+        }
+        this.props.columns.push(new SchemaHeaderField(`New field ${index ? "(" + index + ")" : ""}`, "#f1efeb"));
+    }
+
+    @action
+    getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => {
+        if (doc && field && column.type === ColumnType.Any) {
+            const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)];
+            if (val instanceof ImageField) return ColumnType.Image;
+            if (val instanceof Doc) return ColumnType.Doc;
+            if (val instanceof DateField) return ColumnType.Date;
+            if (val instanceof List) return ColumnType.List;
+        }
+        if (column.type && column.type !== 0) {
+            return column.type;
+        }
+        if (columnTypes.get(column.heading)) {
+            return column.type = columnTypes.get(column.heading)!;
+        }
+        return column.type = ColumnType.Any;
+    }
+
+    @undoBatch
+    @action
+    toggleTextwrap = async () => {
+        const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []);
+        if (textwrappedRows.length) {
+            this.props.Document.textwrappedSchemaRows = new List<string>([]);
+        } else {
+            const docs = DocListCast(this.props.Document[this.props.fieldKey]);
+            const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
+            this.props.Document.textwrappedSchemaRows = new List<string>(allRows);
+        }
+    }
+
+    @action
+    toggleTextWrapRow = (doc: Doc): void => {
+        const textWrapped = this.textWrappedRows;
+        const index = textWrapped.findIndex(id => doc[Id] === id);
+
+        index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]);
+
+        this.textWrappedRows = textWrapped;
+    }
+
+    @computed
+    get reactTable() {
+        const children = this.childDocs;
+        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
+        const expanded: { [name: string]: any } = {};
+        Array.from(this._openCollections.keys()).map(col => expanded[col.toString()] = true);
+        const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
+
+        return <ReactTable
+            style={{ position: "relative" }}
+            data={children}
+            page={0}
+            pageSize={children.length}
+            showPagination={false}
+            columns={this.tableColumns}
+            getTrProps={this.getTrProps}
+            getTdProps={this.getTdProps}
+            sortable={false}
+            TrComponent={MovableRow}
+            sorted={this.sorted}
+            expanded={expanded}
+            resized={this.resized}
+            onResizedChange={this.props.onResizedChange}
+            // if it has a child, render another table with the children
+            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== DocumentType.COL) ? (null) :
+                <div style={{ paddingLeft: 57 + "px" }} className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
+
+        />;
+    }
+
+    onContextMenu = (e: React.MouseEvent): void => {
+        ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" });
+    }
+
+    getField = (row: number, col?: number) => {
+        const docs = this.childDocs;
+
+        row = row % docs.length;
+        while (row < 0) row += docs.length;
+        const columns = this.props.columns;
+        const doc = docs[row];
+        if (col === undefined) {
+            return doc;
+        }
+        if (col >= 0 && col < columns.length) {
+            const column = this.props.columns[col].heading;
+            return doc[column];
+        }
+        return undefined;
+    }
+
+    createTransformer = (row: number, col: number): Transformer => {
+        const self = this;
+        const captures: { [name: string]: Field } = {};
+
+        const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
+            return root => {
+                function visit(node: ts.Node) {
+                    node = ts.visitEachChild(node, visit, context);
+                    if (ts.isIdentifier(node)) {
+                        const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
+                        const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
+                        if (isntPropAccess && isntPropAssign) {
+                            if (node.text === "$r") {
+                                return ts.createNumericLiteral(row.toString());
+                            } else if (node.text === "$c") {
+                                return ts.createNumericLiteral(col.toString());
+                            } else if (node.text === "$") {
+                                if (ts.isCallExpression(node.parent)) {
+                                    // captures.doc = self.props.Document;
+                                    // captures.key = self.props.fieldKey;
+                                }
+                            }
+                        }
+                    }
+
+                    return node;
+                }
+                return ts.visitNode(root, visit);
+            };
+        };
+
+        // const getVars = () => {
+        //     return { capturedVariables: captures };
+        // };
+
+        return { transformer, /*getVars*/ };
+    }
+
+    setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => {
+        script =
+            `const $ = (row:number, col?:number) => {
+                const rval = (doc as any)[key][row + ${row}];
+                return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading];
+            }
+            return ${script}`;
+        const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
+        if (compiled.compiled) {
+            doc[field] = new ComputedField(compiled);
+            return true;
+        }
+        return false;
+    }
+
+    @action
+    showDoc = (doc: Doc | undefined, dataDoc?: Doc, screenX?: number, screenY?: number) => {
+        this._showDoc = doc;
+        if (dataDoc && screenX && screenY) {
+            this._showDocPos = this.props.ScreenToLocalTransform().transformPoint(screenX, screenY);
+        }
+    }
+
+    onOpenClick = () => {
+        this._showDoc && this.props.addDocTab(this._showDoc, "add:right");
+    }
+
+    getPreviewTransform = (): Transform => {
+        return this.props.ScreenToLocalTransform().translate(- this.borderWidth - 4 - this.tableWidth, - this.borderWidth);
+    }
+
+    render() {
+        const preview = "";
+        return <div className="collectionSchemaView-table"
+            onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
+            onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
+            {this.reactTable}
+            {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
+            {!this._showDoc ? (null) :
+                <div className="collectionSchemaView-documentPreview" ref="overlay"
+                    style={{
+                        position: "absolute", width: 150, height: 150,
+                        background: "dimGray", display: "block", top: 0, left: 0,
+                        transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`
+                    }} >
+                    <DocumentView
+                        Document={this._showDoc}
+                        DataDoc={this._showDataDoc}
+                        styleProvider={DefaultStyleProvider}
+                        layerProvider={undefined}
+                        docViewPath={returnEmptyDoclist}
+                        freezeDimensions={true}
+                        focus={DocUtils.DefaultFocus}
+                        renderDepth={this.props.renderDepth}
+                        rootSelected={returnFalse}
+                        isContentActive={returnTrue}
+                        isDocumentActive={returnFalse}
+                        PanelWidth={() => 150}
+                        PanelHeight={() => 150}
+                        ScreenToLocalTransform={this.getPreviewTransform}
+                        docFilters={returnEmptyFilter}
+                        docRangeFilters={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                        ContainingCollectionView={this.props.CollectionView}
+                        moveDocument={this.props.moveDocument}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        addDocTab={this.props.addDocTab}
+                        pinToPres={this.props.pinToPres}
+                        bringToFront={returnFalse}>
+                    </DocumentView>
+                </div>}
+        </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f0a54e4ac..ecf4c0901 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -8,7 +8,7 @@ import { emptyPath, OmitKeys, Without } from "../../../Utils";
 import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
+import { CollectionSchemaView } from "../collections/schemaView/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
 import { InkingStroke } from "../InkingStroke";
 import { PresElementBox } from "../presentationview/PresElementBox";
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5c168d8a9..a671c955d 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,7 +18,7 @@ import { SetupDrag } from '../../util/DragManager';
 import { SearchUtil } from '../../util/SearchUtil';
 import { Transform } from '../../util/Transform';
 import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView";
+import { CollectionSchemaView, ColumnType } from "../collections/schemaView/CollectionSchemaView";
 import { CollectionViewType } from '../collections/CollectionView';
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -119,7 +119,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     getFinalQuery(query: string): string {
         //alters the query so it looks in the correct fields
-        //if this is true, th`en not all of the field boxes are checked
+        //if this is true, then not all of the field boxes are checked
         //TODO: data
         const initialfilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
 
diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts
index 88de3a19f..74cf934f2 100644
--- a/src/fields/SchemaHeaderField.ts
+++ b/src/fields/SchemaHeaderField.ts
@@ -3,7 +3,7 @@ import { serializable, primitive } from "serializr";
 import { ObjectField } from "./ObjectField";
 import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
-import { ColumnType } from "../client/views/collections/CollectionSchemaView";
+import { ColumnType } from "../client/views/collections/schemaView/CollectionSchemaView";
 
 export const PastelSchemaPalette = new Map<string, string>([
     // ["pink1", "#FFB4E8"],
-- 
cgit v1.2.3-70-g09d2


From 31a00f5e5d374b8a2945525a75f80f4148c143b7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 15 Jul 2021 17:29:04 -0400
Subject: fixed onClick scripts for layout fields of HTMLtags.  adjusted
 formatting of fieldViews/checkboxes/inputs

---
 src/client/views/nodes/DocumentContentsView.tsx           |  2 +-
 src/client/views/nodes/formattedText/DashFieldView.scss   | 11 +++++++----
 src/client/views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 3 files changed, 9 insertions(+), 6 deletions(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 34488ffbe..a0a40becb 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -180,7 +180,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
         const replacer = (match: any, prefix: string, expr: string, postfix: string, offset: any, string: any) => {
             return prefix + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + postfix;
         };
-        layoutFrame = layoutFrame.replace(/(>[^{]*)\{([^.'][^<}]+)\}([^}]*<)/g, replacer);
+        layoutFrame = layoutFrame.replace(/(>[^{]*)[^=]\{([^.'][^<}]+)\}([^}]*<)/g, replacer);
 
         // replace HTML<tag> with corresponding HTML tag as in:  <HTMLdiv> becomes  <HTMLtag Document={props.Document} htmltag='div'> 
         const replacer2 = (match: any, p1: string, offset: any, string: any) => {
diff --git a/src/client/views/nodes/formattedText/DashFieldView.scss b/src/client/views/nodes/formattedText/DashFieldView.scss
index e16036000..e7dd286a5 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.scss
+++ b/src/client/views/nodes/formattedText/DashFieldView.scss
@@ -1,6 +1,7 @@
 .dashFieldView {
     position: relative;
-    display: inline-block;
+    display: inline-flex;
+    align-items: center;
 
     .dashFieldView-enumerables {
         width: 10px;
@@ -13,6 +14,8 @@
         min-width: 12px;
         position: relative;
         display: inline-block;
+        margin: 0;
+        transform: scale(0.7);
         background-color: rgba(155, 155, 155, 0.24);
     }
     .dashFieldView-labelSpan {
@@ -22,11 +25,11 @@
         background: rgba(0,0,0,0.1);
     }
     .dashFieldView-fieldSpan {
-        min-width: 20px;
+        min-width: 8px;
         margin-left: 2px;
         margin-right: 5px;
-        position: relative;
-        display: inline;
+        padding-left: 2px;
+        display: inline-block;
         background-color: rgba(155, 155, 155, 0.24);
         font-weight: bold;
         span {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b97b5ff01..42cb02782 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1554,7 +1554,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 >
                     <div className={`formattedTextBox-outer${selected ? "-selected" : ""}`} ref={this._scrollRef}
                         style={{
-                            width: `calc(100% - ${this.sidebarWidthPercent})`,
+                            width: this.props.dontSelectOnLoad ? "100%" : `calc(100% - ${this.sidebarWidthPercent})`,
                             pointerEvents: !active && !SnappingManager.GetIsDragging() ? "none" : undefined,
                             overflow: this.layoutDoc._singleLine ? "hidden" : undefined,
                         }}
-- 
cgit v1.2.3-70-g09d2


From 14e66ac5bcdaa5e244be68ccb8cbb0c495917910 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 23 Jul 2021 14:41:18 -0400
Subject: fixed issues with layoutString templates (eg customView): scale
 properly when in a time view, have a data doc, scripts are called with
 'scale' parmeter

---
 src/client/util/CurrentUserUtils.ts                | 16 +++++++++------
 src/client/views/DocComponent.tsx                  |  2 +-
 src/client/views/nodes/DocumentContentsView.tsx    | 11 +++++-----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 11 +++++-----
 src/fields/Doc.ts                                  | 24 ++++++++++++++++++++--
 5 files changed, 45 insertions(+), 19 deletions(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 8a98304b2..22504f102 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -405,14 +405,18 @@ export class CurrentUserUtils {
                 selection: { type: "text", anchor: 1, head: 1 },
                 storedMarks: []
             };
-            const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { title: "text", version: headerViewVersion, target: doc, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, cloneFieldFilter: new List<string>(["system"]) }, "header"); // text needs to be a space to allow templateText to be created
+            const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), {
+                title: "text", version: headerViewVersion, target: doc, _height: 70, _headerPointerEvents: "all",
+                _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, _fitWidth: true,
+                cloneFieldFilter: new List<string>(["system"])
+            }, "header");
             const headerBtnHgt = 10;
             headerTemplate[DataSym].layout =
-                "<div style='height:100%'>" +
-                `    <FormattedTextBox {...props} fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._headerHeight}px)'/>` +
-                "    <FormattedTextBox {...props} fieldKey={'header'}  dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._headerFontSize}px' height='{this._headerHeight||1}px' background={this._headerColor ||this.target.mySharedDocs.userColor||'lightGray'} />" +
-                `    <HTMLdiv fontSize='${headerBtnHgt - 1}' onClick={‘(this._headerHeight=Math.min(Math.max(1,this._height-30),this._headerHeight===1?50:1)) && (this._autoHeightMargins=this._headerHeight+${headerBtnHgt})’}  height='${headerBtnHgt}px' background='yellow' >Metadata</HTMLdiv>` +
-                "</div>";
+                "<HTMLdiv transformOrigin='top left' width='{100/scale}%' height='{100/scale}%' transform='scale({scale})'>" +
+                `    <FormattedTextBox {...props} dontScale='true' fieldKey={'text'}  height='calc(100% - ${headerBtnHgt}px - {this._headerHeight}px)'/>` +
+                "    <FormattedTextBox {...props} dontScale='true' fieldKey={'header'}  dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._headerFontSize}px' height='{(this._headerHeight||1)}px' background='{this._headerColor ||this.target.mySharedDocs.userColor||`lightGray`}' />" +
+                `    <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' background='yellow' onClick={‘(this._headerHeight=scale*Math.min(Math.max(1,this._height-30),this._headerHeight===1?50:1)) && (this._autoHeightMargins=this._headerHeight+${headerBtnHgt})’}  >Metadata</HTMLdiv>` +
+                "</HTMLdiv>";
 
             // "<div style={'height:100%'}>" +
             // "    <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.mySharedDocs.userColor}' />" +
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index da8af7cc0..0b70ce68d 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -119,7 +119,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
 
         styleFromLayoutString = (scale: number) => {
             const style: { [key: string]: any } = {};
-            const divKeys = ["width", "height", "fontSize", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"];
+            const divKeys = ["width", "height", "fontSize", "transform", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"];
             const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a property expression string:  { script }  into a value
                 return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result as string || "";
             };
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index a0a40becb..9b75cd8f9 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -64,6 +64,7 @@ interface HTMLtagProps {
     htmltag: string;
     onClick?: ScriptField;
     onInput?: ScriptField;
+    scaling: number;
 }
 
 //"<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} overflow='hidden' position='absolute' width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'> <ImageBox {...props} fieldKey={'data'}/> <HTMLspan width='200px' top='0' height='35px' textAlign='center' paddingTop='10px' transform='translate(-40px, 45px) rotate(-45deg)' position='absolute' color='{this.bannerColor===`green`?`light`:`dark`}blue' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}blue'> {this.title}</HTMLspan></HTMLdiv>"
@@ -82,7 +83,7 @@ interface HTMLtagProps {
 export class HTMLtag extends React.Component<HTMLtagProps> {
     click = (e: React.MouseEvent) => {
         const clickScript = (this.props as any).onClick as Opt<ScriptField>;
-        clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc });
+        clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, scale: this.props.scaling });
     }
     onInput = (e: React.FormEvent<HTMLDivElement>) => {
         const onInputScript = (this.props as any).onInput as Opt<ScriptField>;
@@ -90,9 +91,9 @@ export class HTMLtag extends React.Component<HTMLtagProps> {
     }
     render() {
         const style: { [key: string]: any } = {};
-        const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "Document", "key", "onInput", "onClick", "__proto__"]).omit;
+        const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "scaling", "Document", "key", "onInput", "onClick", "__proto__"]).omit;
         const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string:  { script }  into a value
-            return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || "";
+            return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string || "";
         };
         Object.keys(divKeys).map((prop: string) => {
             const p = (this.props as any)[prop] as string;
@@ -184,7 +185,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
 
         // replace HTML<tag> with corresponding HTML tag as in:  <HTMLdiv> becomes  <HTMLtag Document={props.Document} htmltag='div'> 
         const replacer2 = (match: any, p1: string, offset: any, string: any) => {
-            return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} htmltag='${p1}'`;
+            return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} scaling='${this.props.scaling?.() || 1}' htmltag='${p1}'`;
         };
         layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2);
 
@@ -200,7 +201,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
             if (splits.length > 1) {
                 const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] });
                 layoutFrame = splits[0] + ` ${func}={props.${func}} ` + splits[1].substring(code[1].end + 1);
-                return ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name, value: "string" });
+                return ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name, scale: "number", value: "string" });
             }
             return undefined;
             // add input function to props
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 95d8f555c..6dd63fb47 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -71,6 +71,7 @@ export interface FormattedTextBoxProps {
     xPadding?: number;   // used to override document's settings for xMargin --- see CollectionCarouselView
     yPadding?: number;
     noSidebar?: boolean;
+    dontScale?: boolean;
     dontSelectOnLoad?: boolean; // suppress selecting the text box when loaded (and mark as not being associated with scrollTop document field)
 }
 export const GoogleRef = "googleDocId";
@@ -126,7 +127,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get scrollHeight() { return NumCast(this.rootDoc[this.fieldKey + "-scrollHeight"]); }
     @computed get sidebarHeight() { return !this.sidebarWidth() ? 0 : NumCast(this.rootDoc[this.SidebarKey + "-height"]); }
     @computed get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
-    @computed get autoHeightMargins() { return this.titleHeight + (this.layoutDoc._autoHeightMargins && !this.props.dontSelectOnLoad ? NumCast(this.layoutDoc._autoHeightMargins) : 0); }
+    @computed get autoHeightMargins() { return this.titleHeight + NumCast(this.layoutDoc._autoHeightMargins); }
     @computed get _recording() { return this.dataDoc?.mediaState === "recording"; }
     set _recording(value) {
         !this.dataDoc.recordingSource && (this.dataDoc.mediaState = value ? "recording" : undefined);
@@ -1524,10 +1525,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             <div className="formattedTextBox-cont"
                 onWheel={e => this.isContentActive() && e.stopPropagation()}
                 style={{
-                    transform: `scale(${scale})`,
-                    transformOrigin: "top left",
-                    width: `${100 / scale}%`,
-                    height: `${100 / scale}%`,
+                    transform: this.props.dontScale ? undefined : `scale(${scale})`,
+                    transformOrigin: this.props.dontScale ? undefined : "top left",
+                    width: this.props.dontScale ? undefined : `${100 / scale}%`,
+                    height: this.props.dontScale ? undefined : `${100 / scale}%`,
                     // overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
                     ...this.styleFromLayoutString(scale)   // this converts any expressions in the format string to style props.  e.g., <FormattedTextBox height='{this._headerHeight}px' >
                 }}>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index bd0ba3ad7..464a8ad05 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -803,6 +803,27 @@ export namespace Doc {
         return undefined;
     }
 
+    // Makes a delegate of a document by first creating a delegate where data should be stored
+    // (ie, the 'data' doc), and then creates another delegate of that (ie, the 'layout' doc).
+    // This is appropriate if you're trying to create a document that behaves like all
+    // regularly created documents (e.g, text docs, pdfs, etc which all have data/layout docs)
+    export function MakeDelegateWithProto(doc: Doc, id?: string, title?: string): Doc {
+        const delegateProto = new Doc();
+        delegateProto[Initializing] = true;
+        delegateProto.proto = doc;
+        delegateProto.author = Doc.CurrentUserEmail;
+        delegateProto.isPrototype = true;
+        title && (delegateProto.title = title);
+        const delegate = new Doc(id, true);
+        delegate[Initializing] = true;
+        delegate.proto = delegateProto;
+        delegate.author = Doc.CurrentUserEmail;
+        Doc.AddDocToList(delegateProto[DataSym], "aliases", delegate);
+        delegate[Initializing] = false;
+        delegateProto[Initializing] = false;
+        return delegate;
+    }
+
     let _applyCount: number = 0;
     export function ApplyTemplate(templateDoc: Doc) {
         if (templateDoc) {
@@ -1150,8 +1171,7 @@ export namespace Doc {
         return ndoc;
     }
     export function delegateDragFactory(dragFactory: Doc) {
-        const ndoc = Doc.MakeDelegate(dragFactory);
-        ndoc.isPrototype = true;
+        const ndoc = Doc.MakeDelegateWithProto(dragFactory);
         if (ndoc && dragFactory["dragFactory-count"] !== undefined) {
             dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1;
             Doc.GetProto(ndoc).title = ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString();
-- 
cgit v1.2.3-70-g09d2


From c9f379adab864132e6cf044f808a43254601e4bb Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Fri, 30 Jul 2021 13:26:25 -0400
Subject: major UI / updates + refactoring

---
 deploy/assets/favicon.png                          |  Bin 0 -> 22180 bytes
 deploy/index.html                                  |  114 +-
 deploy/loader.css                                  |   85 +
 deploy/loader.js                                   |   14 +
 src/client/documents/Documents.ts                  |    4 +-
 src/client/util/CurrentUserUtils.ts                |   44 +-
 src/client/views/AntimodeMenu.scss                 |    1 +
 src/client/views/DocumentButtonBar.tsx             |    2 +-
 src/client/views/MainView.scss                     |   30 +-
 src/client/views/MainView.tsx                      |   29 +-
 src/client/views/PropertiesView.tsx                |    2 +-
 src/client/views/_nodeModuleOverrides.scss         |    4 +-
 src/client/views/collections/CollectionMenu.scss   |    4 +-
 src/client/views/collections/CollectionMenu.tsx    |    2 +-
 src/client/views/collections/TabDocView.tsx        |    2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   10 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |    3 +-
 src/client/views/global/globalCssVariables.scss    |    3 +
 src/client/views/nodes/DocumentContentsView.tsx    |    4 +-
 src/client/views/nodes/DocumentView.tsx            |    2 +-
 src/client/views/nodes/FontIconBox.tsx             |    3 +-
 src/client/views/nodes/PresBox.scss                | 1243 ----------
 src/client/views/nodes/PresBox.tsx                 | 2472 --------------------
 .../views/nodes/formattedText/RichTextMenu.tsx     |   10 +-
 src/client/views/nodes/trails/PresBox.scss         | 1243 ++++++++++
 src/client/views/nodes/trails/PresBox.tsx          | 2440 +++++++++++++++++++
 src/client/views/nodes/trails/PresElementBox.scss  |  235 ++
 src/client/views/nodes/trails/PresElementBox.tsx   |  388 +++
 src/client/views/nodes/trails/PresEnums.ts         |   28 +
 src/client/views/nodes/trails/index.ts             |    3 +
 .../views/presentationview/PresElementBox.scss     |  235 --
 .../views/presentationview/PresElementBox.tsx      |  386 ---
 src/client/views/topbar/TopBar.scss                |   12 +-
 src/client/views/topbar/TopBar.tsx                 |   89 +-
 tslint.json                                        |   41 +-
 35 files changed, 4587 insertions(+), 4600 deletions(-)
 create mode 100644 deploy/assets/favicon.png
 create mode 100644 deploy/loader.css
 create mode 100644 deploy/loader.js
 delete mode 100644 src/client/views/nodes/PresBox.scss
 delete mode 100644 src/client/views/nodes/PresBox.tsx
 create mode 100644 src/client/views/nodes/trails/PresBox.scss
 create mode 100644 src/client/views/nodes/trails/PresBox.tsx
 create mode 100644 src/client/views/nodes/trails/PresElementBox.scss
 create mode 100644 src/client/views/nodes/trails/PresElementBox.tsx
 create mode 100644 src/client/views/nodes/trails/PresEnums.ts
 create mode 100644 src/client/views/nodes/trails/index.ts
 delete mode 100644 src/client/views/presentationview/PresElementBox.scss
 delete mode 100644 src/client/views/presentationview/PresElementBox.tsx

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/deploy/assets/favicon.png b/deploy/assets/favicon.png
new file mode 100644
index 000000000..59595b910
Binary files /dev/null and b/deploy/assets/favicon.png differ
diff --git a/deploy/index.html b/deploy/index.html
index dda0c6457..d96215391 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -1,114 +1,22 @@
 <html style="overflow: hidden;">
 
 <head>
-    <title>Dash Web</title>
-    <link href="https://fonts.googleapis.com/css?family=Fjalla+One|Hind+Siliguri:300" rel="stylesheet">
-    <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500' rel='stylesheet'>
+    <title>Dash</title>
+    <link rel="preconnect" href="https://fonts.googleapis.com">
+    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+    <link
+        href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&family=Lato:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Merriweather:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Roboto:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap"
+        rel="stylesheet">
+    <link rel="shortcut icon" type="image/jpg" href="./assets/favicon.png" />
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
         integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
     <script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/3.3.1/typescript.min.js"></script>
-
-    <script>
-        function getCookie(cname) {
-            var name = cname + "=";
-            var ca = document.cookie.split(';');
-            for (var i = 0; i < ca.length; i++) {
-                var c = ca[i];
-                while (c.charAt(0) == ' ') {
-                    c = c.substring(1);
-                }
-                if (c.indexOf(name) == 0) {
-                    return Number(c.substring(name.length, c.length));
-                }
-            }
-            return 3000;
-        } 
-    </script>
-    <style>
-        .dash-loader {
-            display: flex;
-            align-content: center;
-            justify-content: center;
-            background-color: #AEDDF8;
-            transition: 3s;
-            z-index: 10;
-            width: 100vw;
-            height: 100vh;
-        }
-
-        .dash-loader-container {
-            display: grid;
-            grid-auto-rows: auto 30px auto;
-        }
-
-        .dash-progress-bar {
-            width: 200px;
-            height: 5px;
-            align-self: center;
-            margin-top: 20px;
-            background-color: #ececec;
-            border-radius: 5px;
-            overflow: hidden;
-        }
-
-        .dash-progress {
-            width: 0%;
-            height: 20px;
-            background-color: #5b9fdd;
-            transition: 0.1s;
-        }
-
-        .dash-animation-container {
-            width: 10vw;
-            height: 10vw;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            border-radius: 100%;
-            background-color: #5B9FDD;
-            justify-self: center;
-            align-self: flex-end;
-        }
-
-        .dash-loader-text {
-            font-size: 15px;
-            font-family: "Roboto";
-            text-align: center;
-            color: #5B9FDD;
-        }
-
-        .dash-d-path {
-            stroke-dasharray: 1000;
-            stroke-dashoffset: 1000;
-            animation: dash-d-path 3s linear infinite;
-        }
-
-        @keyframes dash-d-path {
-            0% {
-                stroke-dashoffset: 1000;
-            }
-
-            20% {
-                stroke-dashoffset: 0;
-            }
-
-            70% {
-                stroke-dashoffset: 0;
-            }
-
-            90% {
-                stroke-dashoffset: 1000;
-            }
-
-            100% {
-                stroke-dashoffset: 1000;
-            }
-        }
-    </style>
+    <script src="loader.js"></script>
+    <link rel="stylesheet" href="./loader.css" />
 </head>
 
 <body style="display:flex" id="dash-body">
-    <div class="dash-loader" id="loader" style="z-index:10; width:100%; height:100%;">
+    <div class="dash-loader" id="loader">
         <div class="dash-loader-container">
             <div class="dash-animation-container">
                 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px"
@@ -127,7 +35,7 @@
                     console.log("Last Load = " + load);
                     let dashmesg = (width, msg) => {
                         if (document.getElementById("dash-progress")) document.getElementById("dash-progress").style.width = width
-                        if (document.getElementById("dash-progress")) document.getElementById("dash-progress").innerHTML = msg
+                        if (document.getElementById("dash-progress")) document.getElementById("dash-loader-text").innerHTML = msg
                     }
                     setTimeout(() => dashmesg("10%", "Loading Dash..."), load / 10);
                     setTimeout(() => dashmesg("33%", "Preparing dashboards..."), load / 3);
diff --git a/deploy/loader.css b/deploy/loader.css
new file mode 100644
index 000000000..4be0cc98c
--- /dev/null
+++ b/deploy/loader.css
@@ -0,0 +1,85 @@
+.dash-loader {
+    display: flex;
+    align-content: center;
+    justify-content: center;
+    background-color: #BDDDF5;
+    transition: 3s;
+    z-index: 10;
+    z-index:10; 
+    width:100%;
+    height:100%;
+}
+
+.dash-loader-container {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    align-content: center;
+}
+
+.dash-progress-bar {
+    width: 200px;
+    height: 5px;
+    align-self: center;
+    margin-top: 20px;
+    background-color: #ececec;
+    border-radius: 5px;
+    overflow: hidden;
+}
+
+.dash-progress {
+    width: 0%;
+    height: 20px;
+    background-color: #4476F7;
+    transition: 0.1s;
+}
+
+.dash-animation-container {
+    width: 10vw;
+    height: 10vw;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 100%;
+    background-color: #4476F7;
+    justify-self: center;
+}
+
+.dash-loader-text {
+    font-size: 15px;
+    font-family: "Roboto";
+    font-weight: bold;
+    text-align: center;
+    color: #4476F7;
+    user-select: none;
+    -webkit-user-select: none;
+}
+
+.dash-d-path {
+    stroke-dasharray: 1000;
+    stroke-dashoffset: 1000;
+    animation: dash-d-path 3s linear infinite;
+}
+
+@keyframes dash-d-path {
+    0% {
+        stroke-dashoffset: 1000;
+    }
+
+    20% {
+        stroke-dashoffset: 0;
+    }
+
+    70% {
+        stroke-dashoffset: 0;
+    }
+
+    90% {
+        stroke-dashoffset: 1000;
+    }
+
+    100% {
+        stroke-dashoffset: 1000;
+    }
+}
\ No newline at end of file
diff --git a/deploy/loader.js b/deploy/loader.js
new file mode 100644
index 000000000..0be421e14
--- /dev/null
+++ b/deploy/loader.js
@@ -0,0 +1,14 @@
+function getCookie(cname) {
+    var name = cname + "=";
+    var ca = document.cookie.split(';');
+    for (var i = 0; i < ca.length; i++) {
+        var c = ca[i];
+        while (c.charAt(0) == ' ') {
+            c = c.substring(1);
+        }
+        if (c.indexOf(name) == 0) {
+            return Number(c.substring(name.length, c.length));
+        }
+    }
+    return 3000;
+} 
\ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f1db3e32c..81465a241 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -45,14 +45,14 @@ import { LabelBox } from "../views/nodes/LabelBox";
 import { LinkBox } from "../views/nodes/LinkBox";
 import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup";
 import { PDFBox } from "../views/nodes/PDFBox";
-import { PresBox } from "../views/nodes/PresBox";
+import { PresBox } from "../views/nodes/trails/PresBox";
 import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
 import { ScriptingBox } from "../views/nodes/ScriptingBox";
 import { SliderBox } from "../views/nodes/SliderBox";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
 import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
-import { PresElementBox } from "../views/presentationview/PresElementBox";
+import { PresElementBox } from "../views/nodes/trails/PresElementBox";
 import { SearchBox } from "../views/search/SearchBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { DocumentType } from "./DocumentTypes";
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 22504f102..62fab1b23 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -35,6 +35,8 @@ import { UndoManager } from "./UndoManager";
 import { SnappingManager } from "./SnappingManager";
 import { InkTool } from "../../fields/InkField";
 import { computedFn } from "mobx-utils";
+import { ColorScheme } from "./SettingsManager";
+import { Colors } from "../views/global/globalEnums";
 
 
 export let resolvedPorts: { server: number, socket: number };
@@ -472,7 +474,7 @@ export class CurrentUserUtils {
             { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc },
             { toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },
             { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc },
-            { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
+            // { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
             { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc },
             { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
             { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc },
@@ -534,8 +536,8 @@ export class CurrentUserUtils {
             { title: "Sharing", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc.mySharedDocs as Doc },
             // { title: "Filter", target: Cast(doc.currentFilter, Doc, null), icon: "filter", click: 'selectMainMenu(self)' },
             { title: "Pres. Trails", target: Cast(doc.myPresentations, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' },
-            { title: "Help", target: undefined as any, icon: "question-circle", click: 'selectMainMenu(self)' },
-            { title: "Settings", target: undefined as any, icon: "cog", click: 'selectMainMenu(self)' },
+            // { title: "Help", target: undefined as any, icon: "question-circle", click: 'selectMainMenu(self)' },
+            // { title: "Settings", target: undefined as any, icon: "cog", click: 'selectMainMenu(self)' },
             { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)' },
         ];
     }
@@ -561,7 +563,6 @@ export class CurrentUserUtils {
                     dontUndo: true,
                     title,
                     target,
-                    backgroundColor: "black",
                     _dropAction: "alias",
                     _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
                     _width: 60,
@@ -576,8 +577,10 @@ export class CurrentUserUtils {
                 title: "menuItemPanel",
                 childDropAction: "alias",
                 _chromeHidden: true,
+                backgroundColor: Colors.DARK_GRAY,
+                boxShadow: "rgba(0,0,0,0)",
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
-                backgroundColor: "black", ignoreClick: true,
+                ignoreClick: true,
                 _gridGap: 0,
                 _yMargin: 0,
                 _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true
@@ -587,8 +590,6 @@ export class CurrentUserUtils {
         PromiseValue(Cast(doc.menuStack, Doc)).then(stack => {
             stack && PromiseValue(stack.data).then(btns => {
                 DocListCastAsync(btns).then(bts => bts?.forEach(btn => {
-                    btn.color = "white";
-                    btn._backgroundColor = "";
                     btn.dontUndo = true;
                     btn.system = true;
                     if (btn.title === "Catalog" || btn.title === "My Files") { // migration from Catalog to My Files
@@ -759,7 +760,7 @@ export class CurrentUserUtils {
         await doc.myDashboards;
         if (doc.myDashboards === undefined) {
             doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "My Dashboards", _height: 400, childHideLinkButton: true,
+                title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true
@@ -775,7 +776,7 @@ export class CurrentUserUtils {
         await doc.myPresentations;
         if (doc.myPresentations === undefined) {
             doc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "My Presentations", _height: 100,
+                title: "My Trails", _showTitle: "title", _height: 100,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true
@@ -794,7 +795,7 @@ export class CurrentUserUtils {
             doc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true });
             doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true });
             doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileRoot as Doc, doc.myFileOrphans as Doc], {
-                title: "My Documents", _height: 100,
+                title: "My Documents", _showTitle: "title", _height: 100,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
                 isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true,
@@ -808,7 +809,7 @@ export class CurrentUserUtils {
         // setup Recently Closed library item
         if (doc.myRecentlyClosedDocs === undefined) {
             doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "Recently Closed", treeViewShowClearButton: true, childHideLinkButton: true,
+                title: "Recently Closed", _showTitle: "title", treeViewShowClearButton: true, childHideLinkButton: true,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true
@@ -839,7 +840,7 @@ export class CurrentUserUtils {
             doc.treeViewOpen = true;
             doc.treeViewExpandedView = "fields";
             doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], {
-                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, title: "My UserDoc",
+                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, title: "My UserDoc", _showTitle: "title",
                 treeViewTruncateTitleWidth: 150, ignoreClick: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true
             })) as any as Doc;
@@ -859,6 +860,7 @@ export class CurrentUserUtils {
     static async setupSidebarButtons(doc: Doc) {
         CurrentUserUtils.setupSidebarContainer(doc);
         await CurrentUserUtils.setupToolsBtnPanel(doc);
+        CurrentUserUtils.setupImportSidebar(doc);
         CurrentUserUtils.setupDashboards(doc);
         CurrentUserUtils.setupPresentations(doc);
         CurrentUserUtils.setupFilesystem(doc);
@@ -891,6 +893,7 @@ export class CurrentUserUtils {
         (doc["dockedBtn-undo"] as Doc).dontUndo = true;
         (doc["dockedBtn-redo"] as Doc).dontUndo = true;
     }
+
     // sets up the default set of documents to be shown in the Overlay layer
     static setupOverlays(doc: Doc) {
         if (doc.myOverlayDocs === undefined) {
@@ -924,7 +927,8 @@ export class CurrentUserUtils {
             if (!sharedDocs) {
                 sharedDocs = Docs.Create.StackingDocument([], {
                     title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15,
-                    _showTitle: "title", ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Add, "_acl-Public": SharingPermissions.Add, _chromeHidden: true,
+                    _showTitle: "title", ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Add, "_acl-Public": SharingPermissions.Add,
+                    _chromeHidden: true, boxShadow: "0 0",
                 }, sharingDocumentId + "outer", sharingDocumentId);
                 (sharedDocs as Doc)["acl-Public"] = (sharedDocs as Doc)[DataSym]["acl-Public"] = SharingPermissions.Add;
             }
@@ -939,14 +943,14 @@ export class CurrentUserUtils {
     static setupImportSidebar(doc: Doc) {
         if (doc.myImportDocs === undefined) {
             doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], {
-                title: "My ImportDocuments", _forceActive: true, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
+                title: "My ImportDocuments", _forceActive: true, ignoreClick: true, _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
                 childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, _lockedPosition: true, system: true, _chromeHidden: true,
             }));
         }
         if (doc.myImportPanel === undefined) {
             const uploads = Cast(doc.myImportDocs, Doc, null);
             const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _stayInCollection: true, _hideContextMenu: true, title: "Import", icon: "upload", system: true });
-            doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, ignoreClick: true, _chromeHidden: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, system: true }));
+            doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, _showTitle: "title", ignoreClick: true, _chromeHidden: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, system: true, boxShadow: "0 0" }));
         }
     }
 
@@ -1007,10 +1011,14 @@ export class CurrentUserUtils {
                 const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || [];
                 SnappingManager.SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]);
             }, { fireImmediately: true });
+        // Document properties on load
         doc.system = true;
+        doc.darkScheme = ColorScheme.Dark;
         doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
         doc.title = Doc.CurrentUserEmail;
         doc._raiseWhenDragged = true;
+        doc._showLabel = false;
+        doc._showMenuLabel = true;
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
         doc.activeInkWidth = StrCast(doc.activeInkWidth, "1");
         doc.activeInkBezier = StrCast(doc.activeInkBezier, "0");
@@ -1201,7 +1209,7 @@ export class CurrentUserUtils {
         const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row");
         Doc.AddDocToList(myPresentations, "data", presentation);
         userDoc.activePresentation = presentation;
-        const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
+        const toggleTheme = ScriptField.MakeScript(`Doc.UserDoc().darkScheme = !Doc.UserDoc().darkScheme`);
         const toggleComic = ScriptField.MakeScript(`toggleComicMode()`);
         const snapshotDashboard = ScriptField.MakeScript(`snapshotDashboard()`);
         const createDashboard = ScriptField.MakeScript(`createNewDashboard()`);
@@ -1257,6 +1265,4 @@ Scripting.addGlobal(function createNewPresentation() { return MainView.Instance.
 Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); },
     "returns all the links to the document or its annotations", "(doc: any)");
 Scripting.addGlobal(function importDocument() { return CurrentUserUtils.importDocument(); },
-    "imports files from device directly into the import sidebar");
-Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; },
-    "toggle between regular rendeing and an informal sketch/comic style");
+    "imports files from device directly into the import sidebar");
\ No newline at end of file
diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss
index b509f9f54..e23bf27c1 100644
--- a/src/client/views/AntimodeMenu.scss
+++ b/src/client/views/AntimodeMenu.scss
@@ -6,6 +6,7 @@
     z-index: 10001;
     height: $antimodemenu-height;
     background: $dark-gray;
+    border-bottom: $standard-border;
     // box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
     // border-radius: 0px 6px 6px 6px;
     z-index: 1001;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index a5d80cd22..b11aa99b0 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -24,7 +24,7 @@ import { DocumentView } from './nodes/DocumentView';
 import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
 import { TemplateMenu } from "./TemplateMenu";
 import React = require("react");
-import { PresBox } from './nodes/PresBox';
+import { PresBox } from './nodes/trails/PresBox';
 import { undoBatch } from '../util/UndoManager';
 import { CollectionViewType } from './collections/CollectionView';
 const higflyout = require("@hig/flyout");
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 2069986ad..ba1c91720 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -22,10 +22,6 @@
     height: 100%;
 }
 
-.mainContent-div-flyout {
-    left: calc(-1 * var(--flyoutHandleWidth));
-}
-
 // add nodes menu. Note that the + button is actually an input label, not an actual button.
 .mainView-docButtons {
     position: absolute;
@@ -111,14 +107,21 @@
     user-select: none;
 }
 
+.properties-container {
+    height: 100%;
+    position: relative;
+    left: 100%;
+    top: calc(-100% - 36px);
+    z-index: 3000;
+}
+
 .mainView-propertiesDragger {
     //background-color: rgb(140, 139, 139);
-    background-color: $light-gray;
+    background-color: $medium-gray;
     height: 55px;
     width: 17px;
     position: absolute;
     top: 50%;
-    border: 1px black solid;
     border-radius: 0;
     border-top-left-radius: 10px;
     border-bottom-left-radius: 10px;
@@ -141,18 +144,6 @@
     }
 }
 
-.mainiView-propertiesView {
-    display: flex;
-    flex-direction: column;
-    height: 100%;
-    position: absolute;
-    right: 0;
-    top: 0;
-    border-left: solid 1px;
-    z-index: 100000;
-    cursor: auto;
-}
-
 .mainView-innerContent, .mainView-innerContent-dark {
     display: contents;
     flex-direction: row;
@@ -171,7 +162,7 @@
     }
 
     .propertiesView {
-        right: 0;
+        left: 0;
         position: absolute;
         z-index: 2;
         background-color: $medium-gray;
@@ -220,6 +211,7 @@
 .mainView-menuPanel {
     min-width: var(--menuPanelWidth);
     background-color: $dark-gray;
+    border-right: $standard-border;
 
     .collectionStackingView {
         scrollbar-width: none;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7d6bfbd40..49f4f7a6e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -64,6 +64,7 @@ import { PropertiesView } from './PropertiesView';
 import { SearchBox } from './search/SearchBox';
 import { DefaultStyleProvider, DashboardStyleProvider, StyleProp } from './StyleProvider';
 import { TopBar } from './topbar/TopBar';
+import { Colors } from './global/globalEnums';
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
@@ -179,12 +180,12 @@ export class MainView extends React.Component {
         const targets = document.elementsFromPoint(e.x, e.y);
         if (targets.length) {
             const targClass = targets[0].className.toString();
-            if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) {
-                const check = targets.some((thing) =>
-                    (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
-                        thing.className === "collectionSchema-header-menuOptions"));
-                !check && SearchBox.Instance.resetSearch(true);
-            }
+            // if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) {
+            //     const check = targets.some((thing) =>
+            //         (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
+            //             thing.className === "collectionSchema-header-menuOptions"));
+            //     !check && SearchBox.Instance.resetSearch(true);
+            // }
             !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu();
             !["timeline-menu-desc", "timeline-menu-item", "timeline-menu-input"].includes(targClass) && TimelineMenu.Instance.closeMenu();
         }
@@ -193,7 +194,7 @@ export class MainView extends React.Component {
     initEventListeners = () => {
         window.addEventListener("drop", e => e.preventDefault(), false);  // prevent default behavior of navigating to a new web page
         window.addEventListener("dragover", e => e.preventDefault(), false);
-        document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
+        // document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined));
         document.addEventListener("pointerdown", this.globalPointerDown);
         document.addEventListener("click", (e: MouseEvent) => {
             if (!e.cancelBubble) {
@@ -405,22 +406,26 @@ export class MainView extends React.Component {
     }
 
     @computed get mainInnerContent() {
+        const width = this.propertiesWidth() + this._flyoutWidth + this.menuPanelWidth();
+        const transform = this._flyoutWidth ? 'translate(-28px, 0px)' : undefined;
         return <>
             {this.menuPanel}
             <div key="inner" className={`mainView-innerContent${this.darkScheme ? "-dark" : ""}`}>
                 {this.flyout}
-                <div className="mainView-libraryHandle" style={{ display: !this._flyoutWidth ? "none" : undefined, left: this._flyoutWidth ? (this._flyoutWidth + this.menuPanelWidth() - 10) : -10 }} onPointerDown={this.onFlyoutPointerDown} >
+                <div className="mainView-libraryHandle" style={{ display: !this._flyoutWidth ? "none" : undefined }} onPointerDown={this.onFlyoutPointerDown} >
                     <FontAwesomeIcon icon="chevron-left" color={this.darkScheme ? "white" : "black"} style={{ opacity: "50%" }} size="sm" />
                 </div>
-                <div className="mainView-innerContainer" style={{ width: `calc(100% - ${this.propertiesWidth() + this._flyoutWidth + this.menuPanelWidth()}px)` }}>
+                <div className="mainView-innerContainer" style={{ width: `calc(100% - ${width}px)`, transform: transform }}>
                     <CollectionMenu />
 
                     {this.dockingContent}
 
-                    <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ right: this.propertiesWidth() - 1 }}>
-                        <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? "chevron-left" : "chevron-right"} color={this.darkScheme ? "white" : "black"} size="sm" />
+                    <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ right: this._flyoutWidth ? 0 : this.propertiesWidth() - 1 }}>
+                        <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? "chevron-left" : "chevron-right"} color={this.darkScheme ? Colors.WHITE : Colors.BLACK} size="sm" />
+                    </div>
+                    <div className="properties-container">
+                        {this.propertiesWidth() < 10 ? (null) : <PropertiesView styleProvider={DefaultStyleProvider} width={this.propertiesWidth()} height={this.getContentsHeight()} />}
                     </div>
-                    {this.propertiesWidth() < 10 ? (null) : <PropertiesView styleProvider={DefaultStyleProvider} width={this.propertiesWidth()} height={this.getContentsHeight()} />}
                 </div>
             </div>
         </>;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 4df3e4f00..8136edf04 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -24,7 +24,7 @@ import { EditableView } from "./EditableView";
 import { InkStrokeProperties } from "./InkStrokeProperties";
 import { DocumentView, StyleProviderFunc } from "./nodes/DocumentView";
 import { KeyValueBox } from "./nodes/KeyValueBox";
-import { PresBox } from "./nodes/PresBox";
+import { PresBox } from "./nodes/trails/PresBox";
 import { PropertiesButtons } from "./PropertiesButtons";
 import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector";
 import "./PropertiesView.scss";
diff --git a/src/client/views/_nodeModuleOverrides.scss b/src/client/views/_nodeModuleOverrides.scss
index cb59489c0..140be2140 100644
--- a/src/client/views/_nodeModuleOverrides.scss
+++ b/src/client/views/_nodeModuleOverrides.scss
@@ -58,12 +58,10 @@ div .lm_header {
 .lm_header .lm_controls {
     align-items: center;
     position: absolute;
-    background-color: #000000;
+    background-color: $dark-gray;
     border-radius: 5px;
     display: flex;
-    top: 2px;
     justify-content: space-evenly;
-    right: 2px;
     height: 18px;
     width: 65px;
 }
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index c0fc774d3..f04b19ef7 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -38,10 +38,10 @@
         border: unset;
 
         .collectionMenu-divider {
-            height: 85%;
+            height: 100%;
             margin-left: 3px;
             margin-right: 3px;
-            width: 1.5px;
+            width: 2px;
             background-color: $medium-gray;
         }
 
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 6e6fabd0d..a9b978c4e 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -29,7 +29,7 @@ import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentView } from "../nodes/DocumentView";
 import { RichTextMenu } from "../nodes/formattedText/RichTextMenu";
-import { PresBox } from "../nodes/PresBox";
+import { PresBox } from "../nodes/trails/PresBox";
 import "./CollectionMenu.scss";
 import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { TabDocView } from "./TabDocView";
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 0e67bebd8..d82810652 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -25,7 +25,7 @@ import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { LightboxView } from '../LightboxView';
 import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
-import { PresBox, PinProps, PresMovement } from '../nodes/PresBox';
+import { PinProps, PresBox, PresMovement } from '../nodes/trails';
 import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a4e310e6c..c5f6f7bf2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -38,7 +38,7 @@ import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDo
 import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { pageSchema } from "../../nodes/ImageBox";
-import { PresBox } from "../../nodes/PresBox";
+import { PresBox } from "../../nodes/trails/PresBox";
 import { StyleLayers, StyleProp } from "../../StyleProvider";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
@@ -834,10 +834,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                 map(doc => ({ ...this.childDataProvider(doc, ""), ...this.childSizeProvider(doc, "") }));
             if (measuredDocs.length) {
                 const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) =>  // computes range of content
-                ({
-                    xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
-                    yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
-                })
+                    ({
+                        xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
+                        yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
+                    })
                     , {
                         xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
                         yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b1f2750c3..4fae961b1 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -19,7 +19,8 @@ import { Transform } from "../../../util/Transform";
 import { undoBatch, UndoManager } from "../../../util/UndoManager";
 import { ContextMenu } from "../../ContextMenu";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
-import { PresBox, PresMovement } from "../../nodes/PresBox";
+import { PresBox } from "../../nodes/trails/PresBox";
+import { PresMovement } from "../../nodes/trails/PresEnums";
 import { PreviewCursor } from "../../PreviewCursor";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { SubCollectionViewProps } from "../CollectionSubView";
diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss
index a8d4235bd..72adc171b 100644
--- a/src/client/views/global/globalCssVariables.scss
+++ b/src/client/views/global/globalCssVariables.scss
@@ -38,6 +38,9 @@ $antimodemenu-height: 36px;
 $contextMenu-zindex: 100000; // context menu shows up over everything
 $radialMenu-zindex: 100000; // context menu shows up over everything
 
+// borders
+$standard-border: solid 1px #9F9F9F;
+
 $searchpanel-height: 32px;
 $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc
 $docDecorations-zindex: 998; // then doc decorations appear over everything else
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 9b75cd8f9..3d2cdf5a4 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -11,7 +11,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec
 import { CollectionSchemaView } from "../collections/collectionSchema/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
 import { InkingStroke } from "../InkingStroke";
-import { PresElementBox } from "../presentationview/PresElementBox";
+import { PresElementBox } from "../nodes/trails/PresElementBox";
 import { SearchBox } from "../search/SearchBox";
 import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
 import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
@@ -32,7 +32,7 @@ import { LabelBox } from "./LabelBox";
 import { LinkAnchorBox } from "./LinkAnchorBox";
 import { LinkBox } from "./LinkBox";
 import { PDFBox } from "./PDFBox";
-import { PresBox } from "./PresBox";
+import { PresBox } from "./trails/PresBox";
 import { ScreenshotBox } from "./ScreenshotBox";
 import { ScriptingBox } from "./ScriptingBox";
 import { SliderBox } from "./SliderBox";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 60fa462ad..80a014926 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,7 +43,7 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import "./DocumentView.scss";
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { LinkDocPreview } from "./LinkDocPreview";
-import { PresBox } from './PresBox';
+import { PresBox } from './trails/PresBox';
 import { RadialMenu } from './RadialMenu';
 import React = require("react");
 import { ScriptingBox } from "./ScriptingBox";
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 6ae4b9726..0d415e238 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -14,6 +14,7 @@ import { DocComponent } from '../DocComponent';
 import { StyleProp } from '../StyleProvider';
 import { FieldView, FieldViewProps } from './FieldView';
 import './FontIconBox.scss';
+import { Colors } from '../global/globalEnums';
 const FontIconSchema = createSchema({
     icon: "string",
 });
@@ -47,7 +48,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
         const icon = StrCast(this.dataDoc.icon, "user") as any;
         const presSize = shape === 'round' ? 25 : 30;
         const presTrailsIcon = <img src={`/assets/${"presTrails.png"}`}
-            style={{ width: presSize, height: presSize, filter: `invert(${color === "white" ? "100%" : "0%"})`, marginBottom: "5px" }} />;
+            style={{ width: presSize, height: presSize, filter: `invert(${color === Colors.DARK_GRAY ? "0%" : "100%"})`, marginBottom: "5px" }} />;
         const button = <button className={`menuButton-${shape}`} onContextMenu={this.specificContextMenu}
             style={{ backgroundColor: backgroundColor, }}>
             <div className="menuButton-wrap">
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
deleted file mode 100644
index 5d1c5f4eb..000000000
--- a/src/client/views/nodes/PresBox.scss
+++ /dev/null
@@ -1,1243 +0,0 @@
-@import "../global/globalCssVariables";
-
-.presBox-cont {
-    cursor: auto;
-    position: absolute;
-    display: block;
-    pointer-events: inherit;
-    z-index: 2;
-    font-family: Roboto;
-    width: 100%;
-    min-width: 20px;
-    height: 100%;
-    min-height: 35px;
-    letter-spacing: 2px;
-    overflow: hidden;
-    transition: 0.7s opacity ease;
-
-    .presBox-listCont {
-        position: relative;
-        height: calc(100% - 67px);
-        width: 100%;
-    }
-
-    .presBox-toolbar-dropdown {
-        border-radius: 5px;
-        background-color: white;
-        transform: translate(8px, -5px);
-        box-shadow: 1px 1px 4px 4px rgba(0, 0, 0, 0.25);
-        z-index: 1000;
-        width: calc(100% - 50px);
-        height: max-content;
-        justify-self: center;
-        letter-spacing: normal;
-        height: max-content;
-        font-weight: 500;
-        position: relative;
-        font-size: 13;
-    }
-
-    .presBox-toolbar {
-        position: relative;
-        display: inline-flex;
-        align-items: center;
-        height: 30px;
-        width: 100%;
-        color: $white;
-        background-color: $dark-gray;
-
-        .toolbar-button {
-            cursor: pointer;
-            margin-left: 10px;
-            margin-right: 10px;
-            letter-spacing: 0;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            transition: 0.5s;
-        }
-
-        .toolbar-button.active {
-            color: $light-blue;
-            background-color: white;
-            border-radius: 100%;
-        }
-
-        .toolbar-transitionButtons {
-            display: block;
-
-            .toolbar-transition {
-                display: flex;
-                font-size: 10;
-                width: 100;
-                background-color: rgba(0, 0, 0, 0);
-                min-width: max-content;
-
-                .toolbar-icon {
-                    margin-right: 5px;
-                }
-            }
-        }
-    }
-
-    .toolbar-moreInfo {
-        position: absolute;
-        right: 5px;
-        display: flex;
-        width: max-content;
-        height: 25px;
-        justify-content: center;
-        transform: rotate(90deg);
-        align-items: center;
-        transition: 0.7s ease;
-
-        .toolbar-moreInfoBall {
-            width: 4px;
-            height: 4px;
-            border-radius: 100%;
-            background-color: white;
-            margin: 1px;
-            position: relative;
-        }
-    }
-
-    .toolbar-moreInfo.active {
-        transform: rotate(0deg);
-    }
-
-    .toolbar-divider {
-        border-left: solid $medium-gray 0.5px;
-        height: 20px;
-    }
-}
-
-.dropdown {
-    font-size: 10;
-    margin-left: 5px;
-    color: $medium-gray;
-    transition: 0.5s ease;
-}
-
-.dropdown.active {
-    transform: rotate(180deg);
-    color: $light-blue;
-    opacity: 0.8;
-}
-
-.presBox-radioButtons {
-    font-size: 10px;
-    font-weight: 200;
-    // background-color: rgba(0, 0, 0, 0.1);
-
-    .checkbox-container {
-        margin-left: 10px;
-        display: inline-flex;
-        width: 100%;
-        height: 20px;
-        align-items: center;
-    }
-
-    .checkbox-dropdown {
-        display: flex;
-        width: 100%;
-        align-items: flex-end;
-        gap: 5px;
-
-        .presBox-viewPicker {
-            width: calc(100% - 120px);
-            min-width: 30px;
-        }
-    }
-}
-
-.presBox-ribbon {
-    position: relative;
-    display: inline;
-    font-family: Roboto;
-    z-index: 100;
-    transition: 0.7s;
-
-    .ribbon-doubleButton {
-        display: inline-flex;
-    }
-
-    .presBox-reactiveGrid {
-        display: grid;
-        justify-content: flex-start;
-        align-items: center;
-        grid-template-columns: repeat(auto-fit, 70px);
-    }
-
-    .ribbon-colorBox {
-        cursor: pointer;
-        border: solid 1px $black;
-        display: flex;
-        margin-left: 5px;
-        margin-top: 5px;
-        margin-bottom: 5px;
-        justify-content: center;
-        align-items: center;
-        height: 15px;
-        width: 15px;
-        padding: 0px;
-        transform: translate(2px, 3px);
-    }
-
-    .ribbon-property {
-        font-size: 11;
-        font-weight: 200;
-        height: 20;
-        background-color: $white;
-        color: $black;
-        border: solid 1px $black;
-        display: flex;
-        margin-left: 5px;
-        margin-top: 5px;
-        margin-bottom: 5px;
-        width: max-content;
-        justify-content: center;
-        align-items: center;
-        padding-right: 10px;
-        padding-left: 10px;
-    }
-
-    .ribbon-propertyUpDown {
-        height: 20;
-        width: 20;
-        margin-top: 5px;
-        display: grid;
-        grid-template-rows: 10px 10px;
-
-        .ribbon-propertyUpDownItem {
-            cursor: pointer;
-            color: white;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            height: 100%;
-            width: 100%;
-            background: $black;
-        }
-
-        .ribbon-propertyUpDownItem:hover {
-            background: $medium-gray;
-            transform: scale(1.05);
-        }
-    }
-
-    .presBox-subheading {
-        font-size: 11;
-        font-weight: 400;
-        margin-top: 10px;
-    }
-
-    @media screen and (-webkit-min-device-pixel-ratio:0) {
-
-        .multiThumb-slider {
-            display: grid;
-            background-color: $white;
-            height: 10px;
-            border-radius: 10px;
-            overflow: hidden;
-
-            .toolbar-slider {
-                margin-top: 0px;
-                background: none;
-                -webkit-appearance: none;
-                pointer-events: none;
-            }
-
-            .toolbar-slider.start::-webkit-slider-thumb {
-                width: 10px;
-                pointer-events: auto;
-                -webkit-appearance: none;
-                height: 10px;
-                cursor: ew-resize;
-                background: $medium-blue;
-                box-shadow: -100vw 0 0 100vw $white;
-            }
-
-            .toolbar-slider.end::-webkit-slider-thumb {
-                width: 10px;
-                pointer-events: auto;
-                -webkit-appearance: none;
-                height: 10px;
-                cursor: ew-resize;
-                background: $medium-blue;
-                box-shadow: -100vw 0 0 100vw $light-blue;
-            }
-        }
-
-        .toolbar-slider {
-            margin-top: 5px;
-            position: relative;
-            align-self: center;
-            justify-self: left;
-            overflow: hidden;
-            width: 100%;
-            height: 10px;
-            border-radius: 10px;
-            -webkit-appearance: none;
-            background-color: $white;
-        }
-
-        .toolbar-slider:focus {
-            outline: none;
-        }
-
-        .toolbar-slider::-webkit-slider-runnable-track {
-            height: 10px;
-            -webkit-appearance: none;
-            margin-top: -1px;
-        }
-
-        .toolbar-slider::-webkit-slider-thumb {
-            width: 10px;
-            pointer-events: auto;
-            -webkit-appearance: none;
-            height: 10px;
-            cursor: ew-resize;
-            background: $medium-blue;
-            box-shadow: -100vw 0 0 100vw $light-blue;
-        }
-
-        .presBox-checkbox {
-            -webkit-appearance: none;
-            -webkit-user-select: none;
-            -moz-user-select: none;
-            -ms-user-select: none;
-            user-select: none;
-            margin: 0;
-            margin-right: 3px;
-            border-radius: 100%;
-            height: 15px;
-            width: 15px;
-            min-width: 15px;
-            cursor: pointer;
-            background: $white;
-        }
-
-        .presBox-checkbox:focus {
-            outline: none;
-        }
-
-        .presBox-checkbox:hover {
-            background: $light-gray;
-        }
-
-        .presBox-checkbox:checked {
-            background: $light-blue;
-        }
-    }
-
-
-
-    .slider-headers {
-        position: relative;
-        display: grid;
-        justify-content: space-between;
-        width: 100%;
-        height: max-content;
-        grid-template-columns: auto auto auto;
-        grid-template-rows: max-content;
-        font-weight: 100;
-        margin-top: 3px;
-        font-size: 10px;
-
-        .slider-block {
-            width: 63px;
-            border-radius: 5px;
-            text-align: center;
-            margin-bottom: 8px;
-            margin-top: 8px;
-        }
-
-        .slider-number {
-            border-radius: 3px;
-            width: 30px;
-            margin: auto;
-        }
-    }
-
-    .slider-value {
-        top: -20;
-        color: #2f86a2;
-        position: absolute;
-    }
-
-    .slider-value.none,
-    .slider-headers.none,
-    .toolbar-slider.none {
-        display: none;
-    }
-
-    .dropdown-header {
-        padding-bottom: 10px;
-        font-weight: 800;
-        text-align: center;
-        font-size: 16;
-        width: 90%;
-        color: $black;
-        transform: translate(5%, 0px);
-        border-bottom: solid 2px $medium-gray;
-    }
-
-
-    .ribbon-textInput {
-        border-radius: 2px;
-        height: 20px;
-        font-size: 11.5;
-        font-weight: 100;
-        align-self: center;
-        justify-self: left;
-        margin-top: 5px;
-        padding-left: 10px;
-        background-color: $white;
-        border: solid 1px $black;
-        min-width: 80px;
-        max-width: 200px;
-        width: 100%;
-    }
-
-    .presBox-input {
-        width: 30;
-        height: 100%;
-        background: none;
-        border: none;
-        text-align: right;
-    }
-
-    .presBox-input:focus {
-        outline: none;
-    }
-
-    .ribbon-frameSelector {
-        border: $black solid 1px;
-        width: 60px;
-        height: 20px;
-        margin-top: 5px;
-        display: grid;
-        grid-template-columns: auto 27px auto;
-        position: relative;
-        border-radius: 5px;
-        overflow: hidden;
-        align-items: center;
-        justify-self: left;
-
-        .fwdKeyframe,
-        .backKeyframe {
-            cursor: pointer;
-            position: relative;
-            height: 100%;
-            background: $white;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            text-align: center;
-            color: $black;
-        }
-
-        .numKeyframe {
-            cursor: pointer;
-            font-size: 10;
-            font-weight: 600;
-            position: relative;
-            color: $black;
-            display: flex;
-            width: 100%;
-            height: 100%;
-            text-align: center;
-            align-items: center;
-            justify-content: center;
-        }
-    }
-
-    .ribbon-final-box {
-        align-self: flex-start;
-        justify-self: center;
-        display: grid;
-        margin-top: 10px;
-        grid-template-rows: auto auto;
-        /* padding-left: 10px; */
-        /* padding-right: 10px; */
-        letter-spacing: normal;
-        min-width: max-content;
-        width: 100%;
-        font-size: 13;
-        font-weight: 500;
-        position: relative;
-
-
-        .ribbon-final-button {
-            cursor: pointer;
-            position: relative;
-            font-size: 11;
-            font-weight: normal;
-            letter-spacing: normal;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            margin-bottom: 5px;
-            height: 25px;
-            color: white;
-            width: 100%;
-            max-width: 120;
-            padding-left: 10;
-            padding-right: 10;
-            border-radius: 10px;
-            background-color: $medium-gray;
-        }
-
-        .ribbon-final-button:hover {
-            transform: scale(1.05);
-            transition: all 0.4s;
-        }
-
-        .ribbon-final-button-hidden {
-            cursor: pointer;
-            position: relative;
-            font-size: 11;
-            font-weight: normal;
-            letter-spacing: normal;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            margin-bottom: 5px;
-            height: 25px;
-            color: $light-gray;
-            width: 100%;
-            max-width: 120;
-            padding-left: 10;
-            padding-right: 10;
-            border-radius: 10px;
-            background-color: $black;
-        }
-
-        .ribbon-final-button-hidden:hover {
-            transform: scale(1.05);
-            transition: all 0.4s;
-        }
-
-        .ribbon-frameList {
-            width: calc(100% - 5px);
-            height: 50px;
-            background-color: $white;
-            border: 1px solid $medium-gray;
-            grid-template-rows: max-content;
-
-            .frameList-header {
-                display: grid;
-                width: 100%;
-                height: 20px;
-                background-color: $medium-gray;
-
-                .frameList-headerButtons {
-                    display: flex;
-                    grid-column: 7;
-                    width: 60px;
-                    justify-self: right;
-                    justify-content: flex-end;
-
-                    .headerButton {
-                        cursor: pointer;
-                        position: relative;
-                        border-radius: 100%;
-                        z-index: 300;
-                        width: 15px;
-                        height: 15px;
-                        display: flex;
-                        font-size: 10px;
-                        justify-self: center;
-                        align-self: center;
-                        background-color: rgba(0, 0, 0, 0.5);
-                        color: white;
-                        justify-content: center;
-                        align-items: center;
-                        transition: 0.2s;
-                        margin-right: 3px;
-                    }
-
-                    .headerButton:hover {
-                        background-color: rgba(0, 0, 0, 1);
-                        transform: scale(1.15);
-                    }
-                }
-            }
-        }
-    }
-
-    .selectedList {
-        display: block;
-        min-width: 50;
-        max-width: 120;
-        height: 70;
-        overflow-y: scroll;
-
-        .selectedList-items {
-            font-size: 7;
-            font-weight: normal;
-        }
-    }
-
-    .ribbon-button {
-        cursor: pointer;
-        font-size: 10.5;
-        font-weight: 300;
-        height: 20;
-        background-color: $medium-gray;
-        color: white;
-        display: flex;
-        margin-top: 5px;
-        margin-bottom: 5px;
-        border-radius: 5px;
-        margin-right: 5px;
-        width: max-content;
-        justify-content: center;
-        align-items: center;
-        padding-right: 10px;
-        padding-left: 10px;
-    }
-
-    .ribbon-button:hover {
-        transform: scale(1.03);
-        transition: all 0.4s;
-        font-weight: 400;
-        opacity: 1;
-        color: $white;
-        background-color: $black;
-    }
-
-    .ribbon-toggle {
-        cursor: pointer;
-        font-size: 10.5;
-        font-weight: 200;
-        height: 20;
-        background-color: $white;
-        border: solid 1px rgba(0, 0, 0, 0.5);
-        display: flex;
-        color: $black;
-        margin-top: 5px;
-        margin-bottom: 5px;
-        border-radius: 5px;
-        margin-right: 5px;
-        width: max-content;
-        justify-content: center;
-        align-items: center;
-        padding-right: 10px;
-        padding-left: 10px;
-    }
-
-    .ribbon-toggle.active {
-        background-color: #aedef8;
-    }
-
-    .ribbon-toggle:hover {
-        transform: scale(1.03);
-        transition: all 0.4s;
-        border: solid 1px rgba(0, 0, 0, 0.75);
-    }
-
-    svg.svg-inline--fa.fa-thumbtack.fa-w-12.toolbar-thumbtack {
-        right: 40;
-        position: absolute;
-        transform: rotate(45deg);
-    }
-
-    .ribbon-box {
-        display: grid;
-        grid-template-rows: max-content auto;
-        justify-self: center;
-        margin-top: 10px;
-        padding-right: 10px;
-        letter-spacing: normal;
-        width: 100%;
-        height: max-content;
-        font-weight: 500;
-        position: relative;
-        font-size: 13;
-        padding-bottom: 10px;
-        border-bottom: solid 1px $dark-gray;
-
-        .presBox-dropdown:hover {
-            border: solid 1px $medium-blue;
-
-            .presBox-dropdownIcon {
-                color: $medium-blue;
-            }
-        }
-
-        .presBox-dropdown {
-            cursor: pointer;
-            display: grid;
-            grid-template-columns: auto 20%;
-            position: relative;
-            border: solid 1px $black;
-            background-color: $light-gray;
-            border-radius: 5px;
-            font-size: 10;
-            height: 25;
-            color: $black;
-            padding-left: 5px;
-            align-items: center;
-            margin-top: 5px;
-            margin-bottom: 5px;
-            font-weight: 200;
-            width: 100%;
-            min-width: max-content;
-            max-width: 200px;
-            overflow: visible;
-
-
-            .presBox-dropdownOption {
-                cursor: pointer;
-                font-size: 11;
-                display: block;
-                padding-left: 10px;
-                padding-right: 5px;
-                padding-top: 3;
-                padding-bottom: 3;
-            }
-
-            .presBox-dropdownOption:hover {
-                position: relative;
-                background-color: lightgrey;
-            }
-
-            .presBox-dropdownOption.active {
-                position: relative;
-                background-color: $light-blue;
-            }
-
-            .presBox-dropdownOptions {
-                position: absolute;
-                top: 23px;
-                left: -2px;
-                z-index: 200;
-                width: 85%;
-                min-width: max-content;
-                display: block;
-                background: #FFFFFF;
-                border: 0.5px solid #979797;
-                box-sizing: border-box;
-                box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
-            }
-
-            .presBox-dropdownIcon {
-                position: relative;
-                color: black;
-                align-self: center;
-                justify-self: center;
-                margin-right: 2px;
-            }
-        }
-    }
-}
-
-.presBox-ribbon.active {
-    display: grid;
-    grid-template-columns: auto auto auto auto auto;
-    grid-template-rows: 100%;
-    height: 100px;
-    padding-top: 5px;
-    padding-bottom: 5px;
-    border: solid 1px $black;
-    // overflow: auto; 
-
-    ::-webkit-scrollbar {
-        -webkit-appearance: none;
-        height: 3px;
-        width: 8px;
-    }
-
-    ::-webkit-scrollbar-thumb {
-        border-radius: 2px;
-    }
-}
-
-.dropdown-play-button {
-    cursor: pointer;
-    font-size: 12;
-    padding-left: 5px;
-    padding-right: 5px;
-    padding-top: 5px;
-    padding-bottom: 5px;
-    text-align: left;
-    justify-content: left;
-}
-
-.dropdown-play-button:hover {
-    background-color: lightgrey;
-}
-
-.presBox-button-left {
-    cursor: pointer;
-    position: relative;
-    align-self: flex-start;
-    justify-self: flex-start;
-    width: 100%;
-    height: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    border-radius: 4px;
-    padding-left: 7px;
-    padding-right: 7px;
-    border-bottom-right-radius: 0;
-    border-top-right-radius: 0;
-}
-
-.presBox-button-right {
-    cursor: pointer;
-    position: relative;
-    text-align: center;
-    border-left: solid 1px $medium-gray;
-    width: 20%;
-    height: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    border-radius: 4px;
-    padding-left: 7px;
-    padding-right: 7px;
-    border-bottom-left-radius: 0;
-    border-top-left-radius: 0;
-}
-
-.presBox-button-right.active {
-    background-color: #223063;
-    border: #aedcf6 solid 1px;
-    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
-}
-
-.dropdown-play {
-    cursor: pointer;
-    right: 0px;
-    top: calc(100% + 2px);
-    display: none;
-    border-radius: 5px;
-    width: max-content;
-    min-height: 20px;
-    height: max-content;
-    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
-    z-index: 200;
-    background-color: white;
-    color: $black;
-    position: absolute;
-    overflow: hidden;
-}
-
-.dropdown-play.active {
-    display: block;
-}
-
-.open-layout {
-    cursor: pointer;
-    position: relative;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    transform: translate(0px, -1px);
-    background-color: $white;
-    width: 40px;
-    height: 15px;
-    align-self: center;
-    justify-self: center;
-    border: solid 1px $black;
-    border-top: 0px;
-    border-bottom-right-radius: 7px;
-    border-bottom-left-radius: 7px;
-}
-
-.layout-container {
-    padding: 5px;
-    display: grid;
-    background-color: $white;
-    grid-template-columns: repeat(auto-fit, minmax(90px, 100px));
-    width: 100%;
-    border: solid 1px $black;
-    min-width: 100px;
-    overflow: hidden;
-
-    .layout:hover {
-        border: solid 2px $medium-blue;
-    }
-
-    .layout {
-        cursor: pointer;
-        align-self: center;
-        justify-self: center;
-        margin-top: 5;
-        margin-bottom: 5;
-        position: relative;
-        height: 55px;
-        min-width: 90px;
-        width: 90px;
-        overflow: hidden;
-        background-color: white;
-        border: solid $medium-gray 1px;
-        display: grid;
-        grid-template-rows: auto;
-        align-items: center;
-        text-align: center;
-
-        .title {
-            position: relative;
-            align-self: end;
-            padding-left: 3px;
-            margin-left: 3px;
-            margin-right: 3px;
-            height: 13;
-            font-size: 12;
-            display: flex;
-            background-color: #white;
-        }
-
-        .subtitle {
-            align-self: flex-start;
-            position: relative;
-            padding-left: 3px;
-            margin-left: 3px;
-            margin-right: 3px;
-            font-weight: 400;
-            height: 13;
-            font-size: 9;
-            display: flex;
-            background-color: $white;
-        }
-
-        .content {
-            position: relative;
-            font-weight: 200;
-            align-self: flex-start;
-            padding-left: 3px;
-            margin-left: 3px;
-            margin-right: 3px;
-            height: 13;
-            font-size: 10;
-            display: flex;
-            background-color: $white;
-            height: 33;
-            text-align: left;
-            font-size: 8px;
-        }
-    }
-}
-
-.presBox-buttons {
-    position: relative;
-    width: 100%;
-    background: gray;
-    min-height: 35px;
-    padding-top: 5px;
-    padding-bottom: 5px;
-    display: grid;
-    grid-template-columns: auto auto;
-
-    .presBox-viewPicker {
-        cursor: pointer;
-        height: 25;
-        position: relative;
-        display: inline-block;
-        grid-column: 1;
-        border-radius: 5px;
-        min-width: 15px;
-        max-width: 100px;
-        left: 8px;
-    }
-
-    .presBox-presentPanel {
-        display: flex;
-        justify-self: end;
-        width: 100%;
-        max-width: 300px;
-        min-width: 150px;
-    }
-
-
-
-    select {
-        background: $dark-gray;
-        color: $white;
-    }
-
-    .presBox-button {
-        cursor: pointer;
-        height: 25px;
-        border-radius: 5px;
-        display: none;
-        justify-content: center;
-        align-content: center;
-        align-items: center;
-        text-align: center;
-        letter-spacing: normal;
-        width: inherit;
-        background: $dark-gray;
-        color: $white;
-    }
-
-    .presBox-button.active {
-        display: flex;
-    }
-
-    .presBox-button.active:hover {
-        background-color: $medium-blue;
-    }
-
-    .presBox-button.edit {
-        display: flex;
-        max-width: 25px;
-    }
-
-    .presBox-button.present {
-        display: flex;
-        width: max-content;
-        position: absolute;
-        right: 10px;
-
-        .present-icon {
-            margin-right: 7px;
-        }
-    }
-
-
-
-    .collectionViewBaseChrome-viewPicker {
-        min-width: 50;
-        width: 5%;
-        height: 25;
-        position: relative;
-        display: inline-block;
-        left: 8px;
-    }
-}
-
-.presBox-backward,
-.presBox-forward {
-    width: 25px;
-    border-radius: 5px;
-    top: 50%;
-    position: absolute;
-    display: inline-block;
-}
-
-.presBox-backward {
-    left: 5;
-}
-
-.presBox-forward {
-    right: 5;
-}
-
-// CSS adjusted for mobile devices
-@media only screen and (max-device-width: 480px) {
-    .presBox-cont .presBox-buttons {
-        position: absolute;
-        top: 70%;
-        left: 50%;
-        transform: translate(-50%, 0);
-        width: max-content;
-        height: 15%;
-        z-index: 2;
-        align-items: center;
-        background: rgba(0, 0, 0, 0);
-        display: inline-flex;
-
-        .presBox-button {
-            margin-top: 5%;
-            height: 250;
-            width: 300;
-            font-size: 100;
-            display: flex;
-            align-items: center;
-            background: $dark-gray;
-            color: $white;
-        }
-
-        .presBox-viewPicker {
-            top: -70;
-            left: 2.5%;
-            height: 50;
-            width: 95%;
-            font-size: 30px;
-            position: absolute;
-            min-width: 50px;
-        }
-    }
-
-    .presBox-cont .presBox-listCont {
-        top: 50;
-        height: calc(100% - 80px);
-    }
-
-    .input,
-    .select {
-        font-size: 100%;
-    }
-}
-
-.miniPres {
-    cursor: grab;
-    position: absolute;
-    right: 10;
-    top: 10;
-    opacity: 0.1;
-    transition: all 0.4s;
-    color: $white;
-}
-
-.miniPres:hover {
-    opacity: 1;
-}
-
-.presPanelOverlay {
-    background-color: $dark-gray;
-    color: $white;
-    border-radius: 5px;
-    grid-template-rows: 100%;
-    height: 25;
-    width: max-content;
-    min-width: max-content;
-    justify-content: space-evenly;
-    align-items: center;
-    display: flex;
-    position: absolute;
-    right: 10px;
-    transition: all 0.2s;
-
-    .presPanel-button-text {
-        cursor: pointer;
-        display: flex;
-        height: 20;
-        width: max-content;
-        font-family: Roboto;
-        font-weight: 400;
-        margin-left: 3px;
-        margin-right: 3px;
-        padding-right: 3px;
-        padding-left: 3px;
-        letter-spacing: normal;
-        border-radius: 5px;
-        align-items: center;
-        justify-content: center;
-        transition: all 0.3s;
-    }
-
-    .presPanel-divider {
-        width: 0.5px;
-        height: 80%;
-        border-right: solid 1px $medium-gray;
-    }
-
-    .presPanel-button-frame {
-        justify-self: center;
-        align-self: center;
-        align-items: center;
-        display: grid;
-        grid-template-columns: auto auto auto;
-        justify-content: space-around;
-        font-size: 11;
-        margin-left: 7;
-        width: 30;
-        height: 85%;
-        background-color: rgba(91, 157, 221, 0.4);
-        border-radius: 5px;
-    }
-
-    .presPanel-button {
-        cursor: pointer;
-        display: flex;
-        height: 20;
-        min-width: 20;
-        margin-left: 3px;
-        margin-right: 3px;
-        border-radius: 100%;
-        align-items: center;
-        justify-content: center;
-        transition: all 0.3s;
-    }
-
-    .presPanel-button:hover {
-        background-color: $medium-gray;
-        transform: scale(1.2);
-    }
-
-    .presPanel-button-text:hover {
-        background-color: $medium-gray;
-    }
-
-
-}
-
-// .miniPres {
-//     cursor: grab;
-//     position: absolute;
-//     overflow: hidden;
-//     right: 10;
-//     top: 10;
-//     opacity: 0.1;
-//     transition: all 0.4s;
-//     /* border: solid 1px; */
-//     color: white;
-//     /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
-
-//     .miniPresOverlay {
-//         display: grid;
-//         grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
-//         grid-template-rows: 100%;
-//         height: 100%;
-//         justify-items: center;
-//         align-items: center;
-
-//         .miniPres-button-text {
-//             cursor: pointer;
-//             display: flex;
-//             height: 20;
-//             font-weight: 400;
-//             min-width: 100%;
-//             border-radius: 5px;
-//             align-items: center;
-//             justify-content: center;
-//             transition: all 0.3s;
-//         }
-
-//         .miniPres-button-frame {
-//             justify-self: center;
-//             align-self: center;
-//             align-items: center;
-//             display: grid;
-//             grid-template-columns: auto auto auto;
-//             justify-content: space-around;
-//             font-size: 11;
-//             margin-left: 7;
-//             width: 30;
-//             height: 85%;
-//             background-color: rgba(91, 157, 221, 0.4);
-//             border-radius: 5px;
-//         }
-
-//         .miniPres-divider {
-//             width: 0.5px;
-//             height: 80%;
-//             border-right: solid 2px #5a5a5a;
-//         }
-
-//         .miniPres-button {
-//             cursor: pointer;
-//             display: flex;
-//             height: 20;
-//             min-width: 20;
-//             border-radius: 100%;
-//             align-items: center;
-//             justify-content: center;
-//             transition: all 0.3s;
-//         }
-
-//         .miniPres-button:hover {
-//             background-color: #5a5a5a;
-//         }
-
-//         .miniPres-button-text:hover {
-//             background-color: #5a5a5a;
-//         }
-//     }
-// }
\ No newline at end of file
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
deleted file mode 100644
index f3fb6ff17..000000000
--- a/src/client/views/nodes/PresBox.tsx
+++ /dev/null
@@ -1,2472 +0,0 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip } from "@material-ui/core";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { ColorState, SketchPicker } from "react-color";
-import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { Doc, DocListCast, DocListCastAsync, FieldResult } from "../../../fields/Doc";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { InkTool } from "../../../fields/InkField";
-import { List } from "../../../fields/List";
-import { PrefetchProxy } from "../../../fields/Proxy";
-import { listSpec, makeInterface } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { returnFalse, returnOne, returnTrue, emptyFunction } from '../../../Utils';
-import { Docs } from "../../documents/Documents";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DocumentManager } from "../../util/DocumentManager";
-import { Scripting } from "../../util/Scripting";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionView, CollectionViewType } from "../collections/CollectionView";
-import { TabDocView } from "../collections/TabDocView";
-import { ViewBoxBaseComponent } from "../DocComponent";
-import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
-import { FieldView, FieldViewProps } from './FieldView';
-import "./PresBox.scss";
-import Color = require("color");
-import { LightboxView } from "../LightboxView";
-
-export enum PresMovement {
-    Zoom = "zoom",
-    Pan = "pan",
-    Jump = "jump",
-    None = "none",
-}
-
-export enum PresEffect {
-    Zoom = "Zoom",
-    Lightspeed = "Lightspeed",
-    Fade = "Fade in",
-    Flip = "Flip",
-    Rotate = "Rotate",
-    Bounce = "Bounce",
-    Roll = "Roll",
-    None = "None",
-    Left = "left",
-    Right = "right",
-    Center = "center",
-    Top = "top",
-    Bottom = "bottom"
-}
-
-enum PresStatus {
-    Autoplay = "auto",
-    Manual = "manual",
-    Edit = "edit"
-}
-
-export enum PresColor {
-    LightBlue = "#AEDDF8",
-    DarkBlue = "#5B9FDD",
-    LightBackground = "#ececec",
-    SlideBackground = "#d5dce2",
-}
-
-export class PinProps {
-    audioRange?: boolean;
-    unpin?: boolean;
-    setPosition?: boolean;
-    hidePresBox?: boolean;
-}
-
-type PresBoxSchema = makeInterface<[typeof documentSchema]>;
-const PresBoxDocument = makeInterface(documentSchema);
-
-@observer
-export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
-
-    static renderEffectsDoc(renderDoc: any, layoutDoc: Doc) {
-        const effectProps = {
-            left: layoutDoc.presEffectDirection === PresEffect.Left,
-            right: layoutDoc.presEffectDirection === PresEffect.Right,
-            top: layoutDoc.presEffectDirection === PresEffect.Top,
-            bottom: layoutDoc.presEffectDirection === PresEffect.Bottom,
-            opposite: true,
-            delay: layoutDoc.presTransition,
-            // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
-        };
-        switch (layoutDoc.presEffect) {
-            case PresEffect.Zoom: return (<Zoom {...effectProps}>{renderDoc}</Zoom>);
-            case PresEffect.Fade: return (<Fade {...effectProps}>{renderDoc}</Fade>);
-            case PresEffect.Flip: return (<Flip {...effectProps}>{renderDoc}</Flip>);
-            case PresEffect.Rotate: return (<Rotate {...effectProps}>{renderDoc}</Rotate>);
-            case PresEffect.Bounce: return (<Bounce {...effectProps}>{renderDoc}</Bounce>);
-            case PresEffect.Roll: return (<Roll {...effectProps}>{renderDoc}</Roll>);
-            case PresEffect.Lightspeed: return (<LightSpeed {...effectProps}>{renderDoc}</LightSpeed>);
-            case PresEffect.None:
-            default: return renderDoc;
-        }
-    }
-    public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
-        return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ?
-            PresBox.renderEffectsDoc(renderDoc, layoutDoc)
-            :
-            renderDoc;
-    }
-
-    @observable public static Instance: PresBox;
-
-    @observable _isChildActive = false;
-    @observable _moveOnFromAudio: boolean = true;
-    @observable _presTimer!: NodeJS.Timeout;
-    @observable _presKeyEventsActive: boolean = false;
-
-    @observable _selectedArray: ObservableMap = new ObservableMap<Doc, any>();
-    @observable _eleArray: HTMLElement[] = [];
-    @observable _dragArray: HTMLElement[] = [];
-    @observable _pathBoolean: boolean = false;
-    @observable _expandBoolean: boolean = false;
-
-    private _disposers: { [name: string]: IReactionDisposer } = {};
-    @observable private transitionTools: boolean = false;
-    @observable private newDocumentTools: boolean = false;
-    @observable private progressivizeTools: boolean = false;
-    @observable private openMovementDropdown: boolean = false;
-    @observable private openEffectDropdown: boolean = false;
-    @observable private presentTools: boolean = false;
-    @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
-    @computed get tagDocs() {
-        const tagDocs: Doc[] = [];
-        for (const doc of this.childDocs) {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            tagDocs.push(tagDoc);
-        }
-        return tagDocs;
-    }
-    @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); }
-    @computed get activeItem() { return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null); }
-    @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); }
-    @computed get scrollable(): boolean {
-        if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
-        else return false;
-    }
-    @computed get panable(): boolean {
-        if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
-        else return false;
-    }
-    @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); }
-    constructor(props: any) {
-        super(props);
-        if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this);
-        if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations.
-            Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
-                title: "pres element template", type: DocumentType.PRESELEMENT, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
-            }));
-            // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
-            // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
-            // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data
-            // stored on each pres element.
-            (this.presElement as Doc).lookupField = ScriptField.MakeFunction("lookupPresBoxField(container, field, data)",
-                { field: "string", data: Doc.name, container: Doc.name });
-        }
-        this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
-    }
-    @computed get selectedDocumentView() {
-        if (SelectionManager.Views().length) return SelectionManager.Views()[0];
-        if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
-    }
-    @computed get isPres(): boolean {
-        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
-        if (this.selectedDoc?.type === DocumentType.PRES) {
-            document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
-            document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
-            return true;
-        }
-        return false;
-    }
-    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
-
-    @action
-    componentWillUnmount() {
-        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
-        this._presKeyEventsActive = false;
-        this.resetPresentation();
-        // Turn of progressivize editors
-        this.turnOffEdit(true);
-        Object.values(this._disposers).forEach(disposer => disposer?.());
-    }
-
-    @action
-    componentDidMount() {
-        this.rootDoc.presBox = this.rootDoc;
-        this.rootDoc._forceRenderEngine = "timeline";
-        this.layoutDoc.presStatus = PresStatus.Edit;
-        this.layoutDoc._gridGap = 0;
-        this.layoutDoc._yMargin = 0;
-        this.turnOffEdit(true);
-        DocListCastAsync((Doc.UserDoc().myPresentations as Doc).data).then(pres =>
-            !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc));
-        this._disposers.selection = reaction(() => SelectionManager.Views(),
-            views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation());
-    }
-
-    @action
-    updateCurrentPresentation = (pres?: Doc) => {
-        if (pres) Doc.UserDoc().activePresentation = pres;
-        else Doc.UserDoc().activePresentation = this.rootDoc;
-        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
-        document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
-        this._presKeyEventsActive = true;
-        PresBox.Instance = this;
-    }
-
-    // There are still other internal frames and should go through all frames before going to next slide
-    nextInternalFrame = (targetDoc: Doc, activeItem: Doc) => {
-        const currentFrame = Cast(targetDoc?._currentFrame, "number", null);
-        const childDocs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
-        targetDoc._viewTransition = "all 1s";
-        setTimeout(() => targetDoc._viewTransition = undefined, 1010);
-        this.nextKeyframe(targetDoc, activeItem);
-        if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
-        else targetDoc.keyFrameEditing = true;
-    }
-
-    _mediaTimer!: [NodeJS.Timeout, Doc];
-    // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
-    startTempMedia = (targetDoc: Doc, activeItem: Doc) => {
-        const duration: number = NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime);
-        if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
-            const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
-            targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration);
-        }
-        // if (targetDoc.type === DocumentType.AUDIO) {
-        //     if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
-        //     targetDoc._triggerAudio = NumCast(activeItem.presStartTime);
-        //     this._mediaTimer = [setTimeout(() => targetDoc._audioStop = true, duration * 1000), targetDoc];
-        // } else if (targetDoc.type === DocumentType.VID) {
-        //     targetDoc._triggerVideoStop = true;
-        //     setTimeout(() => targetDoc._currentTimecode = NumCast(activeItem.presStartTime), 10);
-        //     setTimeout(() => targetDoc._triggerVideo = true, 20);
-        //     this._mediaTimer = [setTimeout(() => targetDoc._triggerVideoStop = true, (duration * 1000) + 20), targetDoc];
-        // }
-    }
-
-    stopTempMedia = (targetDocField: FieldResult) => {
-        const targetDoc = Cast(targetDocField, Doc, null);
-        if (targetDoc?.type === DocumentType.AUDIO) {
-            if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
-            targetDoc._audioStop = true;
-        } else if (targetDoc?.type === DocumentType.VID) {
-            if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
-            targetDoc._triggerVideoStop = true;
-        }
-    }
-
-    // No more frames in current doc and next slide is defined, therefore move to next slide 
-    nextSlide = (activeNext: Doc) => {
-        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
-        let nextSelected = this.itemIndex + 1;
-        this.gotoDocument(nextSelected, this.activeItem);
-        for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
-            if (!this.childDocs[nextSelected].groupWithUp) {
-                break;
-            } else {
-                console.log("Title: " + this.childDocs[nextSelected].title);
-                this.gotoDocument(nextSelected, this.activeItem, true);
-            }
-        }
-    }
-
-    // Called when the user activates 'next' - to move to the next part of the pres. trail
-    @action
-    next = () => {
-        const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null);
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const lastFrame = Cast(targetDoc?.lastFrame, "number", null);
-        const curFrame = NumCast(targetDoc?._currentFrame);
-        let internalFrames: boolean = false;
-        if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
-        if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
-            // Case 1: There are still other frames and should go through all frames before going to next slide
-            this.nextInternalFrame(targetDoc, activeItem);
-        } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
-            // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide 
-            this.nextSlide(activeNext);
-        } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
-            // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
-            this.gotoDocument(0, this.activeItem);
-        }
-    }
-
-    // Called when the user activates 'back' - to move to the previous part of the pres. trail
-    @action
-    back = () => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null);
-        const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
-        const lastFrame = Cast(targetDoc.lastFrame, "number", null);
-        const curFrame = NumCast(targetDoc._currentFrame);
-        let prevSelected = this.itemIndex;
-        // Functionality for group with up
-        let didZoom = activeItem.presMovement;
-        for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
-            didZoom = this.childDocs[prevSelected].presMovement;
-        }
-        if (lastFrame !== undefined && curFrame >= 1) {
-            // Case 1: There are still other frames and should go through all frames before going to previous slide
-            this.prevKeyframe(targetDoc, activeItem);
-        } else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
-            // Case 2: There are no other frames so it should go to the previous slide
-            prevSelected = Math.max(0, prevSelected - 1);
-            this.gotoDocument(prevSelected, activeItem);
-            if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
-        } else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
-            // Case 3: Pres loop is on so it should go to the last slide
-            this.gotoDocument(this.childDocs.length - 1, activeItem);
-        }
-    }
-
-    //The function that is called when a document is clicked or reached through next or back.
-    //it'll also execute the necessary actions if presentation is playing.
-    public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
-        Doc.UnBrushAllDocs();
-        if (index >= 0 && index < this.childDocs.length) {
-            this.rootDoc._itemIndex = index;
-            const activeItem: Doc = this.activeItem;
-            const targetDoc: Doc = this.targetDoc;
-            if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
-                DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
-            }
-            if (from?.mediaStop === "auto" && this.layoutDoc.presStatus !== PresStatus.Edit) {
-                this.stopTempMedia(from.presentationTargetDoc);
-            }
-            // If next slide is audio / video 'Play automatically' then the next slide should be played
-            if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && (activeItem.mediaStart === "auto")) {
-                this.startTempMedia(targetDoc, activeItem);
-            }
-            if (targetDoc) {
-                targetDoc && runInAction(() => {
-                    if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
-                    else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
-                });
-                setTimeout(() => targetDoc.focusSpeed = 500, this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
-            }
-            if (targetDoc?.lastFrame !== undefined) {
-                targetDoc._currentFrame = 0;
-            }
-            if (!group) this._selectedArray.clear();
-            this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
-            if (this.layoutDoc._viewType === "stacking" && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
-            this.onHideDocument(); //Handles hide after/before
-        }
-    });
-
-    _navTimer!: NodeJS.Timeout;
-    navigateToView = (targetDoc: Doc, activeItem: Doc) => {
-        clearTimeout(this._navTimer);
-        const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
-        bestTarget && runInAction(() => {
-            if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
-                bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
-                bestTarget._scrollTop = activeItem.presPinViewScroll;
-            } else if (bestTarget.type === DocumentType.COMPARISON) {
-                bestTarget._clipWidth = activeItem.presPinClipWidth;
-            } else if (bestTarget.type === DocumentType.VID) {
-                bestTarget._currentTimecode = activeItem.presPinTimecode;
-            } else {
-                bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
-                bestTarget._panX = activeItem.presPinViewX;
-                bestTarget._panY = activeItem.presPinViewY;
-                bestTarget._viewScale = activeItem.presPinViewScale;
-            }
-            this._navTimer = setTimeout(() => bestTarget._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510);
-        });
-    }
-
-    /**
-     * This method makes sure that cursor navigates to the element that
-     * has the option open and last in the group. 
-     * Design choice: If the next document is not in presCollection or 
-     * presCollection itself then if there is a presCollection it will add
-     * a new tab. If presCollection is undefined it will open the document
-     * on the right. 
-     */
-    navigateToElement = async (curDoc: Doc) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const srcContext = Cast(targetDoc.context, Doc, null);
-        const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
-        const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
-        const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
-        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext);
-        this.turnOffEdit();
-        // Handles the setting of presCollection
-        if (includesDoc) {
-            //Case 1: Pres collection should not change as it is already the same
-        } else if (tab !== undefined) {
-            // Case 2: Pres collection should update
-            this.layoutDoc.presCollection = srcContext;
-        }
-        const presStatus = this.rootDoc.presStatus;
-        const selViewCache = Array.from(this._selectedArray.keys());
-        const dragViewCache = Array.from(this._dragArray);
-        const eleViewCache = Array.from(this._eleArray);
-        const self = this;
-        const resetSelection = action(() => {
-            const presDocView = DocumentManager.Instance.getDocumentView(self.rootDoc);
-            if (presDocView) SelectionManager.SelectView(presDocView, false);
-            self.rootDoc.presStatus = presStatus;
-            self._selectedArray.clear();
-            selViewCache.forEach(doc => self._selectedArray.set(doc, undefined));
-            self._dragArray.splice(0, self._dragArray.length, ...dragViewCache);
-            self._eleArray.splice(0, self._eleArray.length, ...eleViewCache);
-        });
-        const openInTab = (doc: Doc, finished?: () => void) => {
-            collectionDocView ? collectionDocView.props.addDocTab(doc, "") : this.props.addDocTab(doc, ":left");
-            this.layoutDoc.presCollection = targetDoc;
-            // this still needs some fixing
-            setTimeout(resetSelection, 500);
-            if (doc !== targetDoc) {
-                setTimeout(finished ?? emptyFunction, 100); /// give it some time to create the targetDoc if we're opening up its context
-            } else {
-                finished?.();
-            }
-        };
-        // If openDocument is selected then it should open the document for the user
-        if (activeItem.openDocument) {
-            LightboxView.SetLightboxDoc(targetDoc);
-        } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
-            LightboxView.SetLightboxDoc(undefined);
-            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right
-        } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
-            LightboxView.SetLightboxDoc(undefined);
-            //awaiting jump so that new scale can be found, since jumping is async     
-            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right    
-        }
-        // After navigating to the document, if it is added as a presPinView then it will
-        // adjust the pan and scale to that of the pinView when it was added.
-        if (activeItem.presPinView) {
-            // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
-            this.navigateToView(targetDoc, activeItem);
-        }
-        // TODO: Add progressivize for navigating web (storing websites for given frames)
-
-    }
-
-    /**
-     * Uses the viewfinder to progressivize through the different views of a single collection.
-     * @param presTargetDoc: document for which internal zoom is used
-     */
-    zoomProgressivizeNext = (activeItem: Doc) => {
-        const targetDoc: Doc = this.targetDoc;
-        const srcContext = Cast(targetDoc?.context, Doc, null);
-        const docView = DocumentManager.Instance.getDocumentView(targetDoc);
-        const vfLeft = this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
-        const vfWidth = this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
-        const vfTop = this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
-        const vfHeight = this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
-        // Case 1: document that is not a Golden Layout tab
-        if (srcContext) {
-            const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
-            if (srcDocView) {
-                const layoutdoc = Doc.Layout(targetDoc);
-                const panelWidth: number = srcDocView.props.PanelWidth();
-                const panelHeight: number = srcDocView.props.PanelHeight();
-                const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2;
-                const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2;
-                const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
-                srcContext._panX = newPanX + (vfLeft + (vfWidth / 2));
-                srcContext._panY = newPanY + (vfTop + (vfHeight / 2));
-                srcContext._viewScale = newScale;
-            }
-        }
-        // Case 2: document is the containing collection
-        if (docView && !srcContext) {
-            const panelWidth: number = docView.props.PanelWidth();
-            const panelHeight: number = docView.props.PanelHeight();
-            const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
-            targetDoc._panX = vfLeft + (vfWidth / 2);
-            targetDoc._panY = vfTop + (vfWidth / 2);
-            targetDoc._viewScale = newScale;
-        }
-        const resize = document.getElementById('resizable');
-        if (resize) {
-            resize.style.width = vfWidth + 'px';
-            resize.style.height = vfHeight + 'px';
-            resize.style.top = vfTop + 'px';
-            resize.style.left = vfLeft + 'px';
-        }
-    }
-
-    /**
-     * For 'Hide Before' and 'Hide After' buttons making sure that
-     * they are hidden each time the presentation is updated.
-     */
-    @action
-    onHideDocument = () => {
-        this.childDocs.forEach((doc, index) => {
-            const curDoc = Cast(doc, Doc, null);
-            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
-            if (tagDoc) tagDoc.opacity = 1;
-            const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
-            const curInd: number = itemIndexes.indexOf(index);
-            if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; }
-            else {
-                if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) { }
-                else if (curDoc.presHideBefore) {
-                    if (index > this.itemIndex) {
-                        tagDoc.opacity = 0;
-                    } else if (!curDoc.presHideAfter) {
-                        tagDoc.opacity = 1;
-                    }
-                }
-                if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== (itemIndexes.length - 1)) { }
-                else if (curDoc.presHideAfter) {
-                    if (index < this.itemIndex) {
-                        tagDoc.opacity = 0;
-                    } else if (!curDoc.presHideBefore) {
-                        tagDoc.opacity = 1;
-                    }
-                }
-            }
-        });
-    }
-
-
-
-    //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
-    @action
-    startAutoPres = (startSlide: number) => {
-        this.updateCurrentPresentation();
-        let activeItem: Doc = this.activeItem;
-        let targetDoc: Doc = this.targetDoc;
-        let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
-        const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
-        const load = async () => { // Wrap the loop into an async function for this to work
-            for (var i = startSlide; i < this.childDocs.length; i++) {
-                activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
-                targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
-                duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
-                if (duration < 100) { duration = 2500; }
-                if (NumCast(targetDoc.lastFrame) > 0) {
-                    for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
-                        await timer(duration / NumCast(targetDoc.lastFrame));
-                        this.next();
-                    }
-                }
-
-                await timer(duration); this.next(); // then the created Promise can be awaited
-                if (i === this.childDocs.length - 1) {
-                    setTimeout(() => {
-                        clearTimeout(this._presTimer);
-                        if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = PresStatus.Manual;
-                        else if (this.layoutDoc.presLoop) this.startAutoPres(0);
-                    }, duration);
-                }
-            }
-        };
-        this.layoutDoc.presStatus = PresStatus.Autoplay;
-        this.startPresentation(startSlide);
-        this.gotoDocument(startSlide, activeItem);
-        load();
-    }
-
-    @action
-    pauseAutoPres = () => {
-        if (this.layoutDoc.presStatus === PresStatus.Autoplay) {
-            if (this._presTimer) clearTimeout(this._presTimer);
-            this.layoutDoc.presStatus = PresStatus.Manual;
-            this.layoutDoc.presLoop = false;
-            this.childDocs.forEach(this.stopTempMedia);
-        }
-    }
-
-    //The function that resets the presentation by removing every action done by it. It also
-    //stops the presentaton.
-    resetPresentation = () => {
-        this.rootDoc._itemIndex = 0;
-        this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)).filter(doc => doc instanceof Doc).forEach(doc => {
-            try {
-                doc.opacity = 1;
-            } catch (e) {
-                console.log("Reset presentation error: ", e);
-            }
-        });
-    }
-
-    @action togglePath = (srcContext: Doc, off?: boolean) => {
-        if (off) {
-            this._pathBoolean = false;
-            srcContext.presPathView = false;
-        } else {
-            runInAction(() => this._pathBoolean = !this._pathBoolean);
-            srcContext.presPathView = this._pathBoolean;
-        }
-    }
-
-    @action toggleExpandMode = () => {
-        runInAction(() => this._expandBoolean = !this._expandBoolean);
-        this.rootDoc.expandBoolean = this._expandBoolean;
-        this.childDocs.forEach((doc) => {
-            doc.presExpandInlineButton = this._expandBoolean;
-        });
-    }
-
-    /**
-     * The function that starts the presentation at the given index, also checking if actions should be applied
-     * directly at start.
-     * @param startIndex: index that the presentation will start at
-     */
-    startPresentation = (startIndex: number) => {
-        this.updateCurrentPresentation();
-        this.childDocs.map(doc => {
-            const tagDoc = doc.presentationTargetDoc as Doc;
-            if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) {
-                tagDoc.opacity = 0;
-            }
-            if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) {
-                tagDoc.opacity = 0;
-            }
-        });
-    }
-
-    /**
-     * The method called to open the presentation as a minimized view
-     */
-    @action
-    updateMinimize = () => {
-        const docView = DocumentManager.Instance.getDocumentView(this.layoutDoc);
-        if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
-            console.log("case 1");
-            this.layoutDoc.presStatus = PresStatus.Edit;
-            Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
-            CollectionDockingView.AddSplit(this.rootDoc, "right");
-        } else if (this.layoutDoc.context && docView) {
-            console.log("case 2");
-            this.layoutDoc.presStatus = PresStatus.Edit;
-            clearTimeout(this._presTimer);
-            const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
-            this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
-            this.rootDoc.y = pt[1] + 10;
-            this.rootDoc._height = 35;
-            this.rootDoc._width = 250;
-            docView.props.removeDocument?.(this.layoutDoc);
-            Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
-        } else {
-            console.log("case 3");
-            // TODO glr: fix this case
-        }
-    }
-
-    /**
-     * Called when the user changes the view type
-     * Either 'List' (stacking) or 'Slides' (carousel)
-     */
-    // @undoBatch
-    viewChanged = action((e: React.ChangeEvent) => {
-        //@ts-ignore
-        const viewType = e.target.selectedOptions[0].value as CollectionViewType;
-        // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
-        viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined);
-        this.rootDoc._viewType = viewType;
-        if (viewType === CollectionViewType.Stacking) this.layoutDoc._gridGap = 0;
-    });
-
-    /**
-     * Called when the user changes the view type
-     * Either 'List' (stacking) or 'Slides' (carousel)
-     */
-    // @undoBatch
-    mediaStopChanged = action((e: React.ChangeEvent) => {
-        const activeItem: Doc = this.activeItem;
-        //@ts-ignore
-        const stopDoc = e.target.selectedOptions[0].value as string;
-        const stopDocIndex: number = Number(stopDoc[0]);
-        activeItem.mediaStopDoc = stopDocIndex;
-        if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
-            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
-            list.push(activeItem);
-            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
-            console.log(list);
-        } else {
-            this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List<Doc>();
-            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
-            list.push(activeItem);
-            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
-            console.log(list);
-        }
-    });
-
-
-    setMovementName = action((movement: any, activeItem: Doc): string => {
-        let output: string = 'none';
-        switch (movement) {
-            case PresMovement.Zoom: output = 'Pan & Zoom'; break; //Pan and zoom
-            case PresMovement.Pan: output = 'Pan'; break; //Pan
-            case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut
-            case PresMovement.None: output = 'None'; break; //None
-            default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom
-        }
-        return output;
-    });
-
-    whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive));
-    // For dragging documents into the presentation trail
-    addDocumentFilter = (docs: Doc[]) => {
-        docs.forEach((doc, i) => {
-            if (doc.presentationTargetDoc) return true;
-            if (doc.type === DocumentType.LABEL) {
-                const audio = Cast(doc.annotationOn, Doc, null);
-                if (audio) {
-                    audio.mediaStart = "manual";
-                    audio.mediaStop = "manual";
-                    audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */));
-                    audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */));
-                    audio.presDuration = audio.presStartTime - audio.presEndTime;
-                    TabDocView.PinDoc(audio, { audioRange: true });
-                    setTimeout(() => this.removeDocument(doc), 0);
-                    return false;
-                }
-            } else {
-                if (!doc.aliasOf) {
-                    const original = Doc.MakeAlias(doc);
-                    TabDocView.PinDoc(original);
-                    setTimeout(() => this.removeDocument(doc), 0);
-                    return false;
-                } else {
-                    if (!doc.presentationTargetDoc) doc.title = doc.title + " - Slide";
-                    doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
-                    doc.presMovement = PresMovement.Zoom;
-                    if (this._expandBoolean) doc.presExpandInlineButton = true;
-                }
-            }
-        });
-        return true;
-    }
-    childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement;
-    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
-    getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
-    panelHeight = () => this.props.PanelHeight() - 40;
-    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
-        (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
-
-    /**
-     * For sorting the array so that the order is maintained when it is dropped.
-     */
-    @action
-    sortArray = (): Doc[] => {
-        return this.childDocs.filter(doc => this._selectedArray.has(doc));
-    }
-
-    /**
-     * Method to get the list of selected items in the order in which they have been selected
-     */
-    @computed get listOfSelected() {
-        const list = Array.from(this._selectedArray.keys()).map((doc: Doc, index: any) => {
-            const curDoc = Cast(doc, Doc, null);
-            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
-            if (curDoc && curDoc === this.activeItem) return <div key={index} className="selectedList-items"><b>{index + 1}.  {curDoc.title}</b></div>;
-            else if (tagDoc) return <div key={index} className="selectedList-items">{index + 1}.  {curDoc.title}</div>;
-            else if (curDoc) return <div key={index} className="selectedList-items">{index + 1}.  {curDoc.title}</div>;
-        });
-        return list;
-    }
-
-    @action
-    selectPres = () => {
-        const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
-        presDocView && SelectionManager.SelectView(presDocView, false);
-    }
-
-    //Regular click
-    @action
-    selectElement = async (doc: Doc) => {
-        const context = Cast(doc.context, Doc, null);
-        this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
-        if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
-        else this.updateCurrentPresentation(context);
-
-        if (this.activeItem.setPosition &&
-            this.activeItem.y !== undefined &&
-            this.activeItem.x !== undefined &&
-            this.targetDoc.x !== undefined &&
-            this.targetDoc.y !== undefined) {
-            const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
-            const time = 10;
-            const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y);
-            const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x);
-
-            for (let i = 0; i < time; i++) {
-                this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time;
-                this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time;
-                await timer(0.1);
-            }
-        }
-    }
-
-    //Command click
-    @action
-    multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
-        if (!this._selectedArray.has(doc)) {
-            this._selectedArray.set(doc, undefined);
-            this._eleArray.push(ref);
-            this._dragArray.push(drag);
-        } else {
-            this._selectedArray.delete(doc);
-            this.removeFromArray(this._eleArray, doc);
-            this.removeFromArray(this._dragArray, doc);
-        }
-        this.selectPres();
-    }
-
-    removeFromArray = (arr: any[], val: any) => {
-        const index: number = arr.indexOf(val);
-        const ret: any[] = arr.splice(index, 1);
-        arr = ret;
-    }
-
-    //Shift click
-    @action
-    shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
-        this._selectedArray.clear();
-        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
-        if (this.activeItem) {
-            for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
-                this._selectedArray.set(this.childDocs[i], undefined);
-                this._eleArray.push(ref);
-                this._dragArray.push(drag);
-            }
-        }
-        this.selectPres();
-    }
-
-    //regular click
-    @action
-    regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean) => {
-        this._selectedArray.clear();
-        this._selectedArray.set(doc, undefined);
-        this._eleArray.splice(0, this._eleArray.length, ref);
-        this._dragArray.splice(0, this._dragArray.length, drag);
-        focus && this.selectElement(doc);
-        this.selectPres();
-    }
-
-    modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => {
-        if (cmdClick) this.multiSelect(doc, ref, drag);
-        else if (shiftClick) this.shiftSelect(doc, ref, drag);
-        else this.regularSelect(doc, ref, drag, focus);
-    }
-
-    static keyEventsWrapper = (e: KeyboardEvent) => {
-        PresBox.Instance.keyEvents(e);
-    }
-
-    // Key for when the presentaiton is active
-    @action
-    keyEvents = (e: KeyboardEvent) => {
-        if (e.target instanceof HTMLInputElement) return;
-        let handled = false;
-        const anchorNode = document.activeElement as HTMLDivElement;
-        if (anchorNode && anchorNode.className?.includes("lm_title")) return;
-        switch (e.key) {
-            case "Backspace":
-                if (this.layoutDoc.presStatus === "edit") {
-                    undoBatch(action(() => {
-                        for (const doc of Array.from(this._selectedArray.keys())) {
-                            this.removeDocument(doc);
-                        }
-                        this._selectedArray.clear();
-                        this._eleArray.length = 0;
-                        this._dragArray.length = 0;
-                    }))();
-                    handled = true;
-                }
-                break;
-            case "Escape":
-                if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); }
-                else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; }
-                else this.layoutDoc.presStatus = "edit";
-                if (this._presTimer) clearTimeout(this._presTimer);
-                handled = true;
-                break;
-            case "Down": case "ArrowDown":
-            case "Right": case "ArrowRight":
-                if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) { // TODO: update to work properly
-                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1;
-                    this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
-                } else {
-                    this.next();
-                    if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; }
-                }
-                handled = true;
-                break;
-            case "Up": case "ArrowUp":
-            case "Left": case "ArrowLeft":
-                if (e.shiftKey && this.itemIndex !== 0) { // TODO: update to work properly
-                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1;
-                    this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
-                } else {
-                    this.back();
-                    if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; }
-                }
-                handled = true;
-                break;
-            case "Spacebar": case " ":
-                if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex);
-                else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer);
-                handled = true;
-                break;
-            case "a":
-                if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === "edit") {
-                    this._selectedArray.clear();
-                    this.childDocs.forEach(doc => this._selectedArray.set(doc, undefined));
-                    handled = true;
-                }
-            default:
-                break;
-        }
-        if (handled) {
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    }
-
-    /**
-     * 
-     */
-    @action
-    viewPaths = () => {
-        const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
-        if (srcContext) {
-            this.togglePath(srcContext);
-        }
-    }
-
-    getAllIndexes = (arr: Doc[], val: Doc): number[] => {
-        const indexes = [];
-        for (let i = 0; i < arr.length; i++) {
-            arr[i] === val && indexes.push(i);
-        }
-        return indexes;
-    }
-
-    // Adds the index in the pres path graphically
-    @computed get order() {
-        const order: JSX.Element[] = [];
-        const docs: Doc[] = [];
-        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
-        const dv = DocumentManager.Instance.getDocumentView(presCollection);
-        this.childDocs.filter(doc => Cast(doc.presentationTargetDoc, Doc, null)).forEach((doc, index) => {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            const srcContext = Cast(tagDoc.context, Doc, null);
-            const width = NumCast(tagDoc._width) / 10;
-            const height = Math.max(NumCast(tagDoc._height) / 10, 15);
-            const edge = Math.max(width, height);
-            const fontSize = edge * 0.8;
-            const gap = 2;
-            if (presCollection === srcContext) {
-                // Case A: Document is contained within the collection
-                if (docs.includes(tagDoc)) {
-                    const prevOccurances: number = this.getAllIndexes(docs, tagDoc).length;
-                    docs.push(tagDoc);
-                    order.push(
-                        <div className="pathOrder"
-                            key={tagDoc.id + 'pres' + index}
-                            style={{ top: NumCast(tagDoc.y) + (prevOccurances * (edge + gap) - (edge / 2)), left: NumCast(tagDoc.x) - (edge / 2), width: edge, height: edge, fontSize: fontSize }}
-                            onClick={() => this.selectElement(doc)}>
-                            <div className="pathOrder-frame">{index + 1}</div>
-                        </div>);
-                } else {
-                    docs.push(tagDoc);
-                    order.push(
-                        <div className="pathOrder"
-                            key={tagDoc.id + 'pres' + index}
-                            style={{ top: NumCast(tagDoc.y) - (edge / 2), left: NumCast(tagDoc.x) - (edge / 2), width: edge, height: edge, fontSize: fontSize }}
-                            onClick={() => this.selectElement(doc)}>
-                            <div className="pathOrder-frame">{index + 1}</div>
-                        </div>);
-                }
-            } else if (doc.presPinView && presCollection === tagDoc && dv) {
-                // Case B: Document is presPinView and is presCollection
-                const scale: number = 1 / NumCast(doc.presPinViewScale);
-                const height: number = dv.props.PanelHeight() * scale;
-                const width: number = dv.props.PanelWidth() * scale;
-                const indWidth = width / 10;
-                const indHeight = Math.max(height / 10, 15);
-                const indEdge = Math.max(indWidth, indHeight);
-                const indFontSize = indEdge * 0.8;
-                const xLoc: number = NumCast(doc.presPinViewX) - (width / 2);
-                const yLoc: number = NumCast(doc.presPinViewY) - (height / 2);
-                docs.push(tagDoc);
-                order.push(
-                    <>
-                        <div className="pathOrder"
-                            key={tagDoc.id + 'pres' + index}
-                            style={{ top: yLoc - (indEdge / 2), left: xLoc - (indEdge / 2), width: indEdge, height: indEdge, fontSize: indFontSize }}
-                            onClick={() => this.selectElement(doc)}
-                        >
-                            <div className="pathOrder-frame">{index + 1}</div>
-                        </div>
-                        <div className="pathOrder-presPinView" style={{ top: yLoc, left: xLoc, width: width, height: height, borderWidth: indEdge / 10 }}></div>
-                    </>);
-            }
-        });
-        return order;
-    }
-
-    /**
-     * Method called for viewing paths which adds a single line with
-     * points at the center of each document added.
-     * Design choice: When this is called it sets _fitToBox as true so the
-     * user can have an overview of all of the documents in the collection.
-     * (Design needed for when documents in presentation trail are in another
-     * collection)
-     */
-    @computed get paths() {
-        let pathPoints = "";
-        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
-        this.childDocs.forEach((doc, index) => {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            const srcContext = Cast(tagDoc?.context, Doc, null);
-            if (tagDoc && presCollection === srcContext) {
-                const n1x = NumCast(tagDoc.x) + (NumCast(tagDoc._width) / 2);
-                const n1y = NumCast(tagDoc.y) + (NumCast(tagDoc._height) / 2);
-                if (index = 0) pathPoints = n1x + "," + n1y;
-                else pathPoints = pathPoints + " " + n1x + "," + n1y;
-            } else if (doc.presPinView && presCollection === tagDoc) {
-                const n1x = NumCast(doc.presPinViewX);
-                const n1y = NumCast(doc.presPinViewY);
-                if (index = 0) pathPoints = n1x + "," + n1y;
-                else pathPoints = pathPoints + " " + n1x + "," + n1y;
-            }
-        });
-        return (<polyline
-            points={pathPoints}
-            style={{
-                opacity: 1,
-                stroke: "#69a6db",
-                strokeWidth: 5,
-                strokeDasharray: '10 5',
-                boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
-            }}
-            fill="none"
-            markerStart="url(#markerArrow)"
-            markerMid="url(#markerSquare)"
-            markerEnd="url(#markerSquareFilled)"
-        />);
-    }
-
-    // Converts seconds to ms and updates presTransition
-    setTransitionTime = (number: String, change?: number) => {
-        let timeInMS = Number(number) * 1000;
-        if (change) timeInMS += change;
-        if (timeInMS < 100) timeInMS = 100;
-        if (timeInMS > 10000) timeInMS = 10000;
-        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presTransition = timeInMS);
-    }
-
-    // Converts seconds to ms and updates presDuration
-    setDurationTime = (number: String, change?: number) => {
-        let timeInMS = Number(number) * 1000;
-        if (change) timeInMS += change;
-        if (timeInMS < 100) timeInMS = 100;
-        if (timeInMS > 20000) timeInMS = 20000;
-        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presDuration = timeInMS);
-    }
-
-    /**
-     * When the movement dropdown is changes
-     */
-    @undoBatch
-    updateMovement = action((movement: any, all?: boolean) => {
-        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
-        array.forEach((doc) => {
-            switch (movement) {
-                case PresMovement.Zoom: //Pan and zoom
-                    doc.presMovement = PresMovement.Zoom;
-                    break;
-                case PresMovement.Pan: //Pan
-                    doc.presMovement = PresMovement.Pan;
-                    break;
-                case PresMovement.Jump: //Jump Cut
-                    doc.presJump = true;
-                    doc.presMovement = PresMovement.Jump;
-                    break;
-                case PresMovement.None: default:
-                    doc.presMovement = PresMovement.None;
-                    break;
-            }
-        });
-    });
-
-    @undoBatch
-    @action
-    updateHideBefore = (activeItem: Doc) => {
-        activeItem.presHideBefore = !activeItem.presHideBefore;
-        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideBefore = activeItem.presHideBefore);
-    }
-
-    @undoBatch
-    @action
-    updateHideAfter = (activeItem: Doc) => {
-        activeItem.presHideAfter = !activeItem.presHideAfter;
-        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideAfter = activeItem.presHideAfter);
-    }
-
-    @undoBatch
-    @action
-    updateOpenDoc = (activeItem: Doc) => {
-        activeItem.openDocument = !activeItem.openDocument;
-        Array.from(this._selectedArray.keys()).forEach((doc) => {
-            doc.openDocument = activeItem.openDocument;
-        });
-    }
-
-    @undoBatch
-    @action
-    updateEffectDirection = (effect: any, all?: boolean) => {
-        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
-        array.forEach((doc) => {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            switch (effect) {
-                case PresEffect.Left:
-                    tagDoc.presEffectDirection = PresEffect.Left;
-                    break;
-                case PresEffect.Right:
-                    tagDoc.presEffectDirection = PresEffect.Right;
-                    break;
-                case PresEffect.Top:
-                    tagDoc.presEffectDirection = PresEffect.Top;
-                    break;
-                case PresEffect.Bottom:
-                    tagDoc.presEffectDirection = PresEffect.Bottom;
-                    break;
-                case PresEffect.Center: default:
-                    tagDoc.presEffectDirection = PresEffect.Center;
-                    break;
-            }
-        });
-    }
-
-    @undoBatch
-    @action
-    updateEffect = (effect: any, all?: boolean) => {
-        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
-        array.forEach((doc) => {
-            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            switch (effect) {
-                case PresEffect.Bounce:
-                    tagDoc.presEffect = PresEffect.Bounce;
-                    break;
-                case PresEffect.Fade:
-                    tagDoc.presEffect = PresEffect.Fade;
-                    break;
-                case PresEffect.Flip:
-                    tagDoc.presEffect = PresEffect.Flip;
-                    break;
-                case PresEffect.Roll:
-                    tagDoc.presEffect = PresEffect.Roll;
-                    break;
-                case PresEffect.Rotate:
-                    tagDoc.presEffect = PresEffect.Rotate;
-                    break;
-                case PresEffect.None: default:
-                    tagDoc.presEffect = PresEffect.None;
-                    break;
-            }
-        });
-    }
-
-    _batch: UndoManager.Batch | undefined = undefined;
-
-    @computed get transitionDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const type = targetDoc.type;
-        const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection);
-        const isPinWithView: boolean = BoolCast(activeItem.presPinView);
-        if (activeItem && targetDoc) {
-            const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
-            let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
-            if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
-            const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
-            activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
-            return (
-                <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
-                    <div className="ribbon-box">
-                        Movement
-                        {isPresCollection || (isPresCollection && isPinWithView) ?
-                            <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
-                                {this.scrollable ? "Scroll to pinned view" : !isPinWithView ? "No movement" : "Pan & Zoom to pinned view"}
-                            </div>
-                            :
-                            <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
-                                {this.setMovementName(activeItem.presMovement, activeItem)}
-                                <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
-                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
-                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
-                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
-                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
-                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
-                                </div>
-                            </div>
-                        }
-                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "inline-flex" : "none" }}>
-                            <div className="presBox-subheading">Movement Speed</div>
-                            <div className="ribbon-property">
-                                <input className="presBox-input"
-                                    type="number" value={transitionSpeed}
-                                    onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
-                            </div>
-                            <div className="ribbon-propertyUpDown">
-                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
-                                    <FontAwesomeIcon icon={"caret-up"} />
-                                </div>
-                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
-                                    <FontAwesomeIcon icon={"caret-down"} />
-                                </div>
-                            </div>
-                        </div>
-                        <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed}
-                            className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}
-                            id="toolbar-slider"
-                            onPointerDown={() => this._batch = UndoManager.StartBatch("presTransition")}
-                            onPointerUp={() => this._batch?.end()}
-                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                e.stopPropagation();
-                                this.setTransitionTime(e.target.value);
-                            }} />
-                        <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                            <div className="slider-text">Fast</div>
-                            <div className="slider-text">Medium</div>
-                            <div className="slider-text">Slow</div>
-                        </div>
-                    </div>
-                    <div className="ribbon-box">
-                        Visibility {"&"} Duration
-                        <div className="ribbon-doubleButton">
-                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideBefore ? "active" : ""}`} onClick={() => this.updateHideBefore(activeItem)}>Hide before</div></Tooltip>}
-                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfter ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>}
-                            <Tooltip title={<><div className="dash-tooltip">{"Open in lightbox view"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? PresColor.LightBlue : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Lightbox</div></Tooltip>
-                        </div>
-                        {(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) : <>
-                            <div className="ribbon-doubleButton" >
-                                <div className="presBox-subheading">Slide Duration</div>
-                                <div className="ribbon-property">
-                                    <input className="presBox-input"
-                                        type="number" value={duration}
-                                        onChange={action((e) => this.setDurationTime(e.target.value))} /> s
-                            </div>
-                                <div className="ribbon-propertyUpDown">
-                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
-                                        <FontAwesomeIcon icon={"caret-up"} />
-                                    </div>
-                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
-                                        <FontAwesomeIcon icon={"caret-down"} />
-                                    </div>
-                                </div>
-                            </div>
-                            <input type="range" step="0.1" min="0.1" max="20" value={duration}
-                                style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }}
-                                className={"toolbar-slider"} id="duration-slider"
-                                onPointerDown={() => { this._batch = UndoManager.StartBatch("presDuration"); }}
-                                onPointerUp={() => { if (this._batch) this._batch.end(); }}
-                                onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }}
-                            />
-                            <div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "grid" }}>
-                                <div className="slider-text">Short</div>
-                                <div className="slider-text">Medium</div>
-                                <div className="slider-text">Long</div>
-                            </div>
-                        </>}
-                    </div>
-                    {isPresCollection ? (null) : <div className="ribbon-box">
-                        Effects
-                        <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
-                            {effect}
-                            <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? PresColor.DarkBlue : 'black' }} icon={"angle-down"} />
-                            <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.None || !targetDoc.presEffect ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None</div>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Fade ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In</div>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Flip ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip</div>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Rotate ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate</div>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Bounce ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce</div>
-                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Roll ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll</div>
-                            </div>
-                        </div>
-                        <div className="ribbon-doubleButton" style={{ display: effect === 'None' ? "none" : "inline-flex" }}>
-                            <div className="presBox-subheading" >Effect direction</div>
-                            <div className="ribbon-property">
-                                {this.effectDirection}
-                            </div>
-                        </div>
-                        <div className="effectDirection" style={{ display: effect === 'None' ? "none" : "grid", width: 40 }}>
-                            <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Left ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Left)}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip>
-                            <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Right ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Right)}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip>
-                            <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Top ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Top)}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip>
-                            <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Bottom ? PresColor.LightBlue : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Bottom)}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip>
-                            <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection === PresEffect.Center || !targetDoc.presEffectDirection ? `solid 2px ${PresColor.LightBlue}` : "solid 2px black", borderRadius: "100%", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Center)}></div></Tooltip>
-                        </div>
-                    </div>}
-                    <div className="ribbon-final-box">
-                        <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
-                            Apply to all
-                        </div>
-                    </div>
-                </div >
-            );
-        }
-    }
-
-    @computed get effectDirection(): string {
-        let effect = '';
-        switch (this.targetDoc.presEffectDirection) {
-            case 'left': effect = "Enter from left"; break;
-            case 'right': effect = "Enter from right"; break;
-            case 'top': effect = "Enter from top"; break;
-            case 'bottom': effect = "Enter from bottom"; break;
-            default: effect = "Enter from center"; break;
-        }
-        return effect;
-    }
-
-    @undoBatch
-    @action
-    applyTo = (array: Doc[]) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        this.updateMovement(activeItem.presMovement, true);
-        this.updateEffect(targetDoc.presEffect, true);
-        this.updateEffectDirection(targetDoc.presEffectDirection, true);
-        array.forEach((doc) => {
-            const curDoc = Cast(doc, Doc, null);
-            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
-            if (tagDoc && targetDoc) {
-                curDoc.presTransition = activeItem.presTransition;
-                curDoc.presDuration = activeItem.presDuration;
-                curDoc.presHideBefore = activeItem.presHideBefore;
-                curDoc.presHideAfter = activeItem.presHideAfter;
-            }
-        });
-    }
-
-    @computed get presPinViewOptionsDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 16, filter: 'invert(1)' }} />;
-        return (
-            <>
-                {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
-                <div className="ribbon-doubleButton">
-                    <Tooltip title={<><div className="dash-tooltip">{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}</div></>}><div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? PresColor.LightBlue : "" }}
-                        onClick={() => {
-                            activeItem.presPinView = !activeItem.presPinView;
-                            targetDoc.presPinView = activeItem.presPinView;
-                            if (activeItem.presPinView) {
-                                if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
-                                    const scroll = targetDoc._scrollTop;
-                                    activeItem.presPinView = true;
-                                    activeItem.presPinViewScroll = scroll;
-                                } else if (targetDoc.type === DocumentType.VID) {
-                                    activeItem.presPinTimecode = targetDoc._currentTimecode;
-                                } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
-                                    const x = targetDoc._panX;
-                                    const y = targetDoc._panY;
-                                    const scale = targetDoc._viewScale;
-                                    activeItem.presPinView = true;
-                                    activeItem.presPinViewX = x;
-                                    activeItem.presPinViewY = y;
-                                    activeItem.presPinViewScale = scale;
-                                } else if (targetDoc.type === DocumentType.COMPARISON) {
-                                    const width = targetDoc._clipWidth;
-                                    activeItem.presPinClipWidth = width;
-                                    activeItem.presPinView = true;
-                                }
-                            }
-                        }}>{presPinWithViewIcon}</div></Tooltip>
-                    {activeItem.presPinView ? <Tooltip title={<><div className="dash-tooltip">{"Update the pinned view with the view of the selected document"}</div></>}><div className="ribbon-button"
-                        onClick={() => {
-                            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
-                                const scroll = targetDoc._scrollTop;
-                                activeItem.presPinViewScroll = scroll;
-                            } else if (targetDoc.type === DocumentType.VID) {
-                                activeItem.presPinTimecode = targetDoc._currentTimecode;
-                            } else if (targetDoc.type === DocumentType.COMPARISON) {
-                                const clipWidth = targetDoc._clipWidth;
-                                activeItem.presPinClipWidth = clipWidth;
-                            } else {
-                                const x = targetDoc._panX;
-                                const y = targetDoc._panY;
-                                const scale = targetDoc._viewScale;
-                                activeItem.presPinViewX = x;
-                                activeItem.presPinViewY = y;
-                                activeItem.presPinViewScale = scale;
-                            }
-                        }}>Update</div></Tooltip> : (null)}
-                </div>
-            </>
-        );
-    }
-
-    @computed get panOptionsDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        return (
-            <>
-                {this.panable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
-                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                        <div className="presBox-subheading">Pan X</div>
-                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                            <input className="presBox-input"
-                                style={{ textAlign: 'left', width: 50 }}
-                                type="number" value={NumCast(activeItem.presPinViewX)}
-                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
-                        </div>
-                    </div>
-                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                        <div className="presBox-subheading">Pan Y</div>
-                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                            <input className="presBox-input"
-                                style={{ textAlign: 'left', width: 50 }}
-                                type="number" value={NumCast(activeItem.presPinViewY)}
-                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
-                        </div>
-                    </div>
-                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                        <div className="presBox-subheading">Scale</div>
-                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                            <input className="presBox-input"
-                                style={{ textAlign: 'left', width: 50 }}
-                                type="number" value={NumCast(activeItem.presPinViewScale)}
-                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
-                        </div>
-                    </div>
-                </div> : (null)}
-            </>
-        );
-    }
-
-    @computed get scrollOptionsDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        return (
-            <>
-                {this.scrollable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
-                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
-                        <div className="presBox-subheading">Scroll</div>
-                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
-                            <input className="presBox-input"
-                                style={{ textAlign: 'left', width: 50 }}
-                                type="number" value={NumCast(activeItem.presPinViewScroll)}
-                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
-                        </div>
-                    </div>
-                </div> : (null)}
-            </>
-        );
-    }
-
-    @computed get mediaStopSlides() {
-        const activeItem: Doc = this.activeItem;
-        const list = this.childDocs.map((doc, i) => {
-            if (i > this.itemIndex) {
-                return (
-                    <option>{i + 1}. {doc.title}</option>
-                );
-            }
-        });
-        return (
-            list
-        );
-    }
-
-    @computed get mediaOptionsDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10);
-        const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
-        const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + ". " + this.childDocs[mediaStopDocInd - 1].title : "";
-        if (activeItem && targetDoc) {
-            return (
-                <div>
-                    <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                        <div>
-                            <div className="ribbon-box">
-                                Start {"&"} End Time
-                                <div className={"slider-headers"}>
-                                    <div className="slider-block" >
-                                        <div className="slider-text" style={{ fontWeight: 500 }}>
-                                            Start time (s)
-                                        </div>
-                                        <div id={"startTime"} className="slider-number" style={{ backgroundColor: PresColor.LightBackground }}>
-                                            <input className="presBox-input"
-                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
-                                                type="number" value={NumCast(activeItem.presStartTime)}
-                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
-                                            />
-                                        </div>
-                                    </div>
-                                    <div className="slider-block">
-                                        <div className="slider-text" style={{ fontWeight: 500 }}>
-                                            Duration (s)
-                                        </div>
-                                        <div className="slider-number" style={{ backgroundColor: PresColor.LightBlue }}>
-                                            {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10}
-                                        </div>
-                                    </div>
-                                    <div className="slider-block">
-                                        <div className="slider-text" style={{ fontWeight: 500 }}>
-                                            End time (s)
-                                        </div>
-                                        <div id={"endTime"} className="slider-number" style={{ backgroundColor: PresColor.LightBackground }}>
-                                            <input className="presBox-input"
-                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
-                                                type="number" value={NumCast(activeItem.presEndTime)}
-                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
-                                            />
-                                        </div>
-                                    </div>
-                                </div>
-                                <div className="multiThumb-slider">
-                                    <input type="range" step="0.1" min="0" max={duration / 10} value={NumCast(activeItem.presEndTime)}
-                                        style={{ gridColumn: 1, gridRow: 1 }}
-                                        className={`toolbar-slider ${"end"}`}
-                                        id="toolbar-slider"
-                                        onPointerDown={() => {
-                                            this._batch = UndoManager.StartBatch("presEndTime");
-                                            const endBlock = document.getElementById("endTime");
-                                            if (endBlock) {
-                                                endBlock.style.color = PresColor.LightBackground;
-                                                endBlock.style.backgroundColor = PresColor.DarkBlue;
-                                            }
-                                        }}
-                                        onPointerUp={() => {
-                                            this._batch?.end();
-                                            const endBlock = document.getElementById("endTime");
-                                            if (endBlock) {
-                                                endBlock.style.color = "black";
-                                                endBlock.style.backgroundColor = PresColor.LightBackground;
-                                            }
-                                        }}
-                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                            e.stopPropagation();
-                                            activeItem.presEndTime = Number(e.target.value);
-                                        }} />
-                                    <input type="range" step="0.1" min="0" max={duration / 10} value={NumCast(activeItem.presStartTime)}
-                                        style={{ gridColumn: 1, gridRow: 1 }}
-                                        className={`toolbar-slider ${"start"}`}
-                                        id="toolbar-slider"
-                                        onPointerDown={() => {
-                                            this._batch = UndoManager.StartBatch("presStartTime");
-                                            const startBlock = document.getElementById("startTime");
-                                            if (startBlock) {
-                                                startBlock.style.color = PresColor.LightBackground;
-                                                startBlock.style.backgroundColor = PresColor.DarkBlue;
-                                            }
-                                        }}
-                                        onPointerUp={() => {
-                                            this._batch?.end();
-                                            const startBlock = document.getElementById("startTime");
-                                            if (startBlock) {
-                                                startBlock.style.color = "black";
-                                                startBlock.style.backgroundColor = PresColor.LightBackground;
-                                            }
-                                        }}
-                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                                            e.stopPropagation();
-                                            activeItem.presStartTime = Number(e.target.value);
-                                        }} />
-                                </div>
-                                <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
-                                    <div className="slider-text">0 s</div>
-                                    <div className="slider-text"></div>
-                                    <div className="slider-text">{duration / 10} s</div>
-                                </div>
-                            </div>
-                            <div className="ribbon-final-box">
-                                Playback
-                                <div className="presBox-subheading">Start playing:</div>
-                                <div className="presBox-radioButtons">
-                                    <div className="checkbox-container">
-                                        <input className="presBox-checkbox"
-                                            type="checkbox"
-                                            onChange={() => activeItem.mediaStart = "manual"}
-                                            checked={activeItem.mediaStart === "manual"}
-                                        />
-                                        <div>On click</div>
-                                    </div>
-                                    <div className="checkbox-container">
-                                        <input className="presBox-checkbox"
-                                            type="checkbox"
-                                            onChange={() => activeItem.mediaStart = "auto"}
-                                            checked={activeItem.mediaStart === "auto"}
-                                        />
-                                        <div>Automatically</div>
-                                    </div>
-                                </div>
-                                <div className="presBox-subheading">Stop playing:</div>
-                                <div className="presBox-radioButtons">
-                                    <div className="checkbox-container">
-                                        <input className="presBox-checkbox"
-                                            type="checkbox"
-                                            onChange={() => activeItem.mediaStop = "manual"}
-                                            checked={activeItem.mediaStop === "manual"}
-                                        />
-                                        <div>At audio end time</div>
-                                    </div>
-                                    <div className="checkbox-container">
-                                        <input className="presBox-checkbox"
-                                            type="checkbox"
-                                            onChange={() => activeItem.mediaStop = "auto"}
-                                            checked={activeItem.mediaStop === "auto"}
-                                        />
-                                        <div>On slide change</div>
-                                    </div>
-                                    {/* <div className="checkbox-container">
-                                    <input className="presBox-checkbox"
-                                        type="checkbox"
-                                        onChange={() => activeItem.mediaStop = "afterSlide"}
-                                        checked={activeItem.mediaStop === "afterSlide"}
-                                    />
-                                    <div className="checkbox-dropdown">
-                                        After chosen slide
-                                        <select className="presBox-viewPicker"
-                                            style={{ opacity: activeItem.mediaStop === "afterSlide" && this.itemIndex !== this.childDocs.length - 1 ? 1 : 0.3 }}
-                                            onPointerDown={e => e.stopPropagation()}
-                                            onChange={this.mediaStopChanged}
-                                            value={mediaStopDocStr}>
-                                            {this.mediaStopSlides}
-                                        </select>
-                                    </div>
-                                </div> */}
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div >
-            );
-        }
-    }
-
-    @computed get newDocumentToolbarDropdown() {
-        return (
-            <div>
-                <div className={'presBox-toolbar-dropdown'} style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                    <div className="layout-container" style={{ height: 'max-content' }}>
-                        <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => { this.layout = 'blank'; this.createNewSlide(this.layout); })} />
-                        <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => { this.layout = 'title'; this.createNewSlide(this.layout); })}>
-                            <div className="title">Title</div>
-                            <div className="subtitle">Subtitle</div>
-                        </div>
-                        <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => { this.layout = 'header'; this.createNewSlide(this.layout); })}>
-                            <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
-                        </div>
-                        <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => { this.layout = 'content'; this.createNewSlide(this.layout); })}>
-                            <div className="title" style={{ alignSelf: 'center' }}>Title</div>
-                            <div className="content">Text goes here</div>
-                        </div>
-                    </div>
-                </div>
-            </div >
-        );
-    }
-
-    @observable openLayouts: boolean = false;
-    @observable addFreeform: boolean = true;
-    @observable layout: string = "";
-    @observable title: string = "";
-
-    @computed get newDocumentDropdown() {
-        return (
-            <div>
-                <div className={"presBox-ribbon"} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                    <div className="ribbon-box">
-                        Slide Title: <br></br>
-                        <input className="ribbon-textInput" placeholder="..." type="text" name="fname"
-                            onChange={(e) => {
-                                e.stopPropagation();
-                                e.preventDefault();
-                                runInAction(() => this.title = e.target.value);
-                            }}>
-                        </input>
-                    </div>
-                    <div className="ribbon-box">
-                        Choose type:
-                        <div className="ribbon-doubleButton">
-                            <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? "" : PresColor.LightBlue }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Text</div>
-                            <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? PresColor.LightBlue : "" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Freeform</div>
-                        </div>
-                    </div>
-                    <div className="ribbon-box" style={{ display: this.addFreeform ? "grid" : "none" }}>
-                        Preset layouts:
-                        <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
-                            <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => this.layout = 'blank')} />
-                            <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => this.layout = 'title')}>
-                                <div className="title">Title</div>
-                                <div className="subtitle">Subtitle</div>
-                            </div>
-                            <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => this.layout = 'header')}>
-                                <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
-                            </div>
-                            <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => this.layout = 'content')}>
-                                <div className="title" style={{ alignSelf: 'center' }}>Title</div>
-                                <div className="content">Text goes here</div>
-                            </div>
-                            <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${PresColor.DarkBlue}` : '' }} onClick={action(() => this.layout = 'twoColumns')}>
-                                <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>Title</div>
-                                <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>Column one text</div>
-                                <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>Column two text</div>
-                            </div>
-                        </div>
-                        <div className="open-layout" onClick={action(() => this.openLayouts = !this.openLayouts)}>
-                            <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"caret-down"} size={"lg"} />
-                        </div>
-                    </div>
-                    <div className="ribbon-final-box">
-                        <div className={this.title !== "" && (this.addFreeform && this.layout !== "" || !this.addFreeform) ? "ribbon-final-button-hidden" : "ribbon-final-button"} onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
-                            Create New Slide
-                        </div>
-                    </div>
-                </div>
-            </div >
-        );
-    }
-
-    createNewSlide = (layout?: string, title?: string, freeform?: boolean) => {
-        let doc = undefined;
-        if (layout) doc = this.createTemplate(layout);
-        if (freeform && layout) doc = this.createTemplate(layout, title);
-        if (!freeform && !layout) doc = Docs.Create.TextDocument("", { _nativeWidth: 400, _width: 225, title: title });
-        if (doc) {
-            const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
-            const data = Cast(presCollection?.data, listSpec(Doc));
-            const presData = Cast(this.rootDoc.data, listSpec(Doc));
-            if (data && presData) {
-                data.push(doc);
-                TabDocView.PinDoc(doc);
-                this.gotoDocument(this.childDocs.length, this.activeItem);
-            } else {
-                this.props.addDocTab(doc, "add:right");
-            }
-        }
-    }
-
-    createTemplate = (layout: string, input?: string) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        let x = 0;
-        let y = 0;
-        if (activeItem && targetDoc) {
-            x = NumCast(targetDoc.x);
-            y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20;
-        }
-        let doc = undefined;
-        const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24pt", });
-        const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16pt" });
-        const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20pt" });
-        const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24pt" });
-        const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14pt" });
-        const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14pt" });
-        const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" });
-        switch (layout) {
-            case 'blank':
-                doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y });
-                break;
-            case 'title':
-                doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
-                break;
-            case 'header':
-                doc = Docs.Create.FreeformDocument([header], { title: input ? input : "Section header", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
-                break;
-            case 'content':
-                doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : "Title and content", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
-                break;
-            case 'twoColumns':
-                doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : "Title and two columns", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
-                break;
-            default:
-                break;
-        }
-        return doc;
-    }
-
-    // Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
-    @computed get presentDropdown() {
-        return (
-            <div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.updateMinimize(); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}>
-                    Mini-player
-                </div>
-                <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}>
-                    Sidebar player
-                </div>
-            </div>
-        );
-    }
-
-    // Case in which the document has keyframes to navigate to next key frame
-    @action
-    nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
-        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
-        const currentFrame = Cast(tagDoc._currentFrame, "number", null);
-        if (currentFrame === undefined) {
-            tagDoc._currentFrame = 0;
-            // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
-            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
-        }
-        // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
-        CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
-        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1);
-        tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
-    }
-
-    @action
-    prevKeyframe = (tagDoc: Doc, actItem: Doc): void => {
-        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
-        const currentFrame = Cast(tagDoc._currentFrame, "number", null);
-        if (currentFrame === undefined) {
-            tagDoc._currentFrame = 0;
-            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
-        }
-        CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
-        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1);
-    }
-
-    /**
-     * Returns the collection type as a string for headers
-     */
-    @computed get stringType(): string {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        let type: string = '';
-        if (activeItem) {
-            switch (targetDoc.type) {
-                case DocumentType.PDF: type = "PDF"; break;
-                case DocumentType.RTF: type = "Text node"; break;
-                case DocumentType.COL: type = "Collection"; break;
-                case DocumentType.AUDIO: type = "Audio"; break;
-                case DocumentType.VID: type = "Video"; break;
-                case DocumentType.IMG: type = "Image"; break;
-                case DocumentType.WEB: type = "Web page"; break;
-                default: type = "Other node"; break;
-            }
-        }
-        return type;
-    }
-
-    @observable private openActiveColorPicker: boolean = false;
-    @observable private openViewedColorPicker: boolean = false;
-
-
-
-    @computed get progressivizeDropdown() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        if (activeItem && targetDoc) {
-            const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black";
-            const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black";
-            return (
-                <div>
-                    <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                        <div className="ribbon-box">
-                            {this.stringType} selected
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? PresColor.LightBlue : "" }} onClick={this.progressivizeChild}>Contents</div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? PresColor.LightBlue : "" }} onClick={this.editProgressivize}>Edit</div>
-                            </div>
-                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
-                                <div className="presBox-subheading">Active text color</div>
-                                <div className="ribbon-colorBox" style={{ backgroundColor: activeFontColor, height: 15, width: 15 }} onClick={action(() => { this.openActiveColorPicker = !this.openActiveColorPicker; })}>
-                                </div>
-                            </div>
-                            {this.activeColorPicker}
-                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
-                                <div className="presBox-subheading">Viewed font color</div>
-                                <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}>
-                                </div>
-                            </div>
-                            {this.viewedColorPicker}
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? PresColor.LightBlue : "" }} onClick={this.progressivizeZoom}>Zoom</div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? PresColor.LightBlue : "" }} onClick={this.editZoomProgressivize}>Edit</div>
-                            </div>
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
-                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? PresColor.LightBlue : "" }} onClick={this.progressivizeScroll}>Scroll</div>
-                                <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? PresColor.LightBlue : "" }} onClick={this.editScrollProgressivize}>Edit</div>
-                            </div>
-                        </div>
-                        <div className="ribbon-final-box">
-                            Frames
-                            <div className="ribbon-doubleButton">
-                                <div className="ribbon-frameSelector">
-                                    <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc, activeItem); }}>
-                                        <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
-                                    </div>
-                                    <div key="num" title="toggle view all" className="numKeyframe" style={{ color: targetDoc.keyFrameEditing ? "white" : "black", backgroundColor: targetDoc.keyFrameEditing ? PresColor.DarkBlue : PresColor.LightBlue }}
-                                        onClick={action(() => targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing)} >
-                                        {NumCast(targetDoc._currentFrame)}
-                                    </div>
-                                    <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={e => { e.stopPropagation(); this.nextKeyframe(targetDoc, activeItem); }}>
-                                        <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
-                                    </div>
-                                </div>
-                                <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
-                            </div>
-                            <div className="ribbon-frameList">
-                                {this.frameListHeader}
-                                {this.frameList}
-                            </div>
-                            <div className="ribbon-toggle" style={{ height: 20, backgroundColor: PresColor.LightBlue }} onClick={() => console.log(" TODO: play frames")}>Play</div>
-                        </div>
-                    </div>
-                </div>
-            );
-        }
-    }
-
-    @undoBatch
-    @action
-    switchActive = (color: ColorState) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const val = String(color.hex);
-        targetDoc["pres-text-color"] = val;
-        return true;
-    }
-    @undoBatch
-    @action
-    switchPresented = (color: ColorState) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const val = String(color.hex);
-        targetDoc["pres-text-viewed-color"] = val;
-        return true;
-    }
-
-    @computed get activeColorPicker() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        return !this.openActiveColorPicker ? (null) : <SketchPicker onChange={this.switchActive}
-            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
-                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
-                '#FFFFFF', '#f1efeb', 'transparent']}
-            color={StrCast(targetDoc["pres-text-color"])} />;
-    }
-
-    @computed get viewedColorPicker() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        return !this.openViewedColorPicker ? (null) : <SketchPicker onChange={this.switchPresented}
-            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
-                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
-                '#FFFFFF', '#f1efeb', 'transparent']}
-            color={StrCast(targetDoc["pres-text-viewed-color"])} />;
-    }
-
-    @action
-    turnOffEdit = (paths?: boolean) => {
-        // Turn off paths
-        if (paths) {
-            const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
-            if (srcContext) this.togglePath(srcContext, true);
-        }
-        // Turn off the progressivize editors for each document
-        this.childDocs.forEach((doc) => {
-            doc.editSnapZoomProgressivize = false;
-            doc.editZoomProgressivize = false;
-            const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
-            if (targetDoc) {
-                targetDoc.editZoomProgressivize = false;
-                // targetDoc.editScrollProgressivize = false;
-            }
-        });
-    }
-
-    //Toggle whether the user edits or not
-    @action
-    editZoomProgressivize = (e: React.MouseEvent) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        if (!targetDoc.editZoomProgressivize) {
-            if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; targetDoc.zoomProgressivize = true;
-            targetDoc.editZoomProgressivize = true;
-            activeItem.editZoomProgressivize = true;
-        } else {
-            targetDoc.editZoomProgressivize = false;
-            activeItem.editZoomProgressivize = false;
-        }
-    }
-
-    //Toggle whether the user edits or not
-    @action
-    editScrollProgressivize = (e: React.MouseEvent) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        if (!targetDoc.editScrollProgressivize) {
-            if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; activeItem.scrollProgressivize = true; }
-            targetDoc.editScrollProgressivize = true;
-        } else {
-            targetDoc.editScrollProgressivize = false;
-        }
-    }
-
-    //Progressivize Zoom
-    @action
-    progressivizeScroll = (e: React.MouseEvent) => {
-        e.stopPropagation();
-        const activeItem: Doc = this.activeItem;
-        activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
-        const targetDoc: Doc = this.targetDoc;
-        targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
-        // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame));
-        if (targetDoc.editScrollProgressivize) {
-            targetDoc.editScrollProgressivize = false;
-            targetDoc._currentFrame = 0;
-            targetDoc.lastFrame = 0;
-        }
-    }
-
-    //Progressivize Zoom
-    @action
-    progressivizeZoom = (e: React.MouseEvent) => {
-        e.stopPropagation();
-        const activeItem: Doc = this.activeItem;
-        activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
-        const targetDoc: Doc = this.targetDoc;
-        targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
-        CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc);
-        if (activeItem.editZoomProgressivize) {
-            activeItem.editZoomProgressivize = false;
-            targetDoc._currentFrame = 0;
-            targetDoc.lastFrame = 0;
-        }
-    }
-
-    //Progressivize Child Docs
-    @action
-    editProgressivize = (e: React.MouseEvent) => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        targetDoc._currentFrame = targetDoc.lastFrame;
-        if (!targetDoc.editProgressivize) {
-            if (!activeItem.presProgressivize) { activeItem.presProgressivize = true; targetDoc.presProgressivize = true; }
-            targetDoc.editProgressivize = true;
-        } else {
-            targetDoc.editProgressivize = false;
-        }
-    }
-
-    @action
-    progressivizeChild = (e: React.MouseEvent) => {
-        e.stopPropagation();
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
-        if (!activeItem.presProgressivize) {
-            targetDoc.keyFrameEditing = false;
-            activeItem.presProgressivize = true;
-            targetDoc.presProgressivize = true;
-            targetDoc._currentFrame = 0;
-            docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
-            targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1;
-        } else {
-            // targetDoc.editProgressivize = false;
-            activeItem.presProgressivize = false;
-            targetDoc.presProgressivize = false;
-            targetDoc._currentFrame = 0;
-            targetDoc.keyFrameEditing = true;
-        }
-    }
-
-    @action
-    checkMovementLists = (doc: Doc, xlist: any, ylist: any) => {
-        const x: List<number> = xlist;
-        const y: List<number> = ylist;
-        const tags: JSX.Element[] = [];
-        let pathPoints = ""; //List of all of the pathpoints that need to be added
-        for (let i = 0; i < x.length - 1; i++) {
-            if (y[i] || x[i]) {
-                if (i === 0) pathPoints = (x[i] - 11) + "," + (y[i] + 33);
-                else pathPoints = pathPoints + " " + (x[i] - 11) + "," + (y[i] + 33);
-                tags.push(<div className="progressivizeMove-frame" style={{ position: 'absolute', top: y[i], left: x[i] }}>{i}</div>);
-            }
-        }
-        tags.push(<svg style={{ overflow: 'visible', position: 'absolute' }}><polyline
-            points={pathPoints}
-            style={{
-                position: 'absolute',
-                opacity: 1,
-                stroke: "#000000",
-                strokeWidth: 2,
-                strokeDasharray: '10 5',
-            }}
-            fill="none"
-        /></svg>);
-        return tags;
-    }
-
-    @observable
-    toggleDisplayMovement = (doc: Doc) => {
-        if (doc.displayMovement) doc.displayMovement = false;
-        else doc.displayMovement = true;
-    }
-
-    @action
-    checkList = (doc: Doc, list: any): number => {
-        const x: List<number> = list;
-        if (x && x.length >= NumCast(doc._currentFrame) + 1) {
-            return x[NumCast(doc._currentFrame)];
-        } else if (x) {
-            x.length = NumCast(doc._currentFrame) + 1;
-            x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1];
-            return x[NumCast(doc._currentFrame)];
-        } else return 100;
-    }
-
-    @computed get progressivizeChildDocs() {
-        const targetDoc: Doc = this.targetDoc;
-        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
-        const tags: JSX.Element[] = [];
-        docs.forEach((doc, index) => {
-            if (doc["x-indexed"] && doc["y-indexed"]) {
-                tags.push(<div style={{ position: 'absolute', display: doc.displayMovement ? "block" : "none" }}>{this.checkMovementLists(doc, doc["x-indexed"], doc["y-indexed"])}</div>);
-            }
-            tags.push(
-                <div className="progressivizeButton" key={index} onPointerLeave={() => { if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; }} onPointerOver={() => { if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; }} onClick={e => { this.toggleDisplayMovement(doc); e.stopPropagation(); }} style={{ backgroundColor: doc.displayMovement ? PresColor.LightBlue : "#c8c8c8", top: NumCast(doc.y), left: NumCast(doc.x) }}>
-                    <div className="progressivizeButton-prev"><FontAwesomeIcon icon={"caret-left"} size={"lg"} onClick={e => { e.stopPropagation(); this.prevAppearFrame(doc, index); }} /></div>
-                    <div className="progressivizeButton-frame">{doc.appearFrame}</div>
-                    <div className="progressivizeButton-next"><FontAwesomeIcon icon={"caret-right"} size={"lg"} onClick={e => { e.stopPropagation(); this.nextAppearFrame(doc, index); }} /></div>
-                </div>);
-        });
-        return tags;
-    }
-
-    @action
-    nextAppearFrame = (doc: Doc, i: number): void => {
-        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
-        // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
-        const appearFrame = Cast(doc.appearFrame, "number", null);
-        if (appearFrame === undefined) {
-            doc.appearFrame = 0;
-        }
-        doc.appearFrame = appearFrame + 1;
-        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
-    }
-
-    @action
-    prevAppearFrame = (doc: Doc, i: number): void => {
-        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
-        // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
-        const appearFrame = Cast(doc.appearFrame, "number", null);
-        if (appearFrame === undefined) {
-            doc.appearFrame = 0;
-        }
-        doc.appearFrame = Math.max(0, appearFrame - 1);
-        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
-    }
-
-    @action
-    updateOpacityList = (list: any, frame: number) => {
-        const x: List<number> = list;
-        if (x && x.length >= frame) {
-            for (let i = 0; i < x.length; i++) {
-                if (i < frame) {
-                    x[i] = 0;
-                } else if (i >= frame) {
-                    x[i] = 1;
-                }
-            }
-            list = x;
-        } else {
-            x.length = frame + 1;
-            for (let i = 0; i < x.length; i++) {
-                if (i < frame) {
-                    x[i] = 0;
-                } else if (i >= frame) {
-                    x[i] = 1;
-                }
-            }
-            list = x;
-        }
-    }
-
-    @computed get moreInfoDropdown() {
-        return (<div></div>);
-    }
-
-    @computed
-    get toolbarWidth(): number {
-        const width = this.props.PanelWidth();
-        return width;
-    }
-
-    @action
-    toggleProperties = () => {
-        if (CurrentUserUtils.propertiesWidth > 0) {
-            CurrentUserUtils.propertiesWidth = 0;
-        } else {
-            CurrentUserUtils.propertiesWidth = 250;
-        }
-    }
-
-    @computed get toolbar() {
-        const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
-        const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel";
-        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
-        const isMini: boolean = this.toolbarWidth <= 100;
-        const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
-        return (mode === CollectionViewType.Carousel3D) ? (null) : (
-            <div id="toolbarContainer" className={'presBox-toolbar'}>
-                {/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
-                    <FontAwesomeIcon icon={"plus"} />
-                    <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
-                </div></Tooltip> */}
-                <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}>
-                    <div style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? PresColor.DarkBlue : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
-                        <FontAwesomeIcon icon={"exchange-alt"} />
-                    </div>
-                </Tooltip>
-                {isMini ? (null) :
-                    <>
-                        <div className="toolbar-divider" />
-                        {/* <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
-                            <div className={"toolbar-button"}
-                                style={{ color: this._expandBoolean ? PresColors.DarkBlue : 'white' }}
-                                onClick={this.toggleExpandMode}>
-                                <FontAwesomeIcon icon={"eye"} />
-                            </div>
-                        </Tooltip>
-                        <div className="toolbar-divider" /> */}
-                        <Tooltip title={<><div className="dash-tooltip">{presKeyEvents ? "Keys are active" : "Keys are not active - click anywhere on the presentation trail to activate keys"}</div></>}>
-                            <div className="toolbar-button" style={{ cursor: presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
-                                <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"keyboard"} style={{ color: presKeyEvents ? PresColor.DarkBlue : 'white' }} />
-                            </div>
-                        </Tooltip>
-                        <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}>
-                            <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
-                                <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? PresColor.DarkBlue : 'white' }} />
-                            </div>
-                        </Tooltip>
-                    </>
-                }
-            </div>
-        );
-    }
-
-    /**
-     * Top panel containes:
-     * viewPicker: The option to choose between List and Slides view for the presentaiton trail
-     * presentPanel: The button to start the presentation / open minimized view of the presentation
-     */
-    @computed get topPanel() {
-        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
-        const isMini: boolean = this.toolbarWidth <= 100;
-        return (
-            <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? "none" : undefined }}>
-                {isMini ? (null) : <select className="presBox-viewPicker"
-                    style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}
-                    onPointerDown={e => e.stopPropagation()}
-                    onChange={this.viewChanged}
-                    value={mode}>
-                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
-                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>
-                </select>}
-                <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
-                    <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
-                        <div className="presBox-button-left"
-                            onClick={undoBatch(() => {
-                                if (this.childDocs.length) {
-                                    this.layoutDoc.presStatus = "manual";
-                                    this.gotoDocument(this.itemIndex, this.activeItem);
-                                }
-                            })}>
-                            <FontAwesomeIcon icon={"play-circle"} />
-                            <div style={{ display: this.props.PanelWidth() > 200 ? "inline-flex" : "none" }}>&nbsp; Present</div>
-                        </div>
-                        {(mode === CollectionViewType.Carousel3D || isMini) ? (null) : <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`}
-                            onClick={(action(() => {
-                                if (this.childDocs.length) this.presentTools = !this.presentTools;
-                            }))}>
-                            <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
-                            {this.presentDropdown}
-                        </div>}
-                    </span>
-                    {this.playButtons}
-                </div>
-            </div>
-        );
-    }
-
-    @action
-    getList = (list: any): List<number> => {
-        const x: List<number> = list;
-        return x;
-    }
-
-    @action
-    updateList = (list: any): List<number> => {
-        const targetDoc: Doc = this.targetDoc;
-        const x: List<number> = list;
-        x.length + 1;
-        x[x.length - 1] = NumCast(targetDoc._scrollY);
-        return x;
-    }
-
-    @action
-    newFrame = () => {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const type: string = StrCast(targetDoc.type);
-        if (!activeItem.frameList) activeItem.frameList = new List<number>();
-        switch (type) {
-            case (DocumentType.PDF || DocumentType.RTF || DocumentType.WEB):
-                this.updateList(activeItem.frameList);
-                break;
-            case DocumentType.COL:
-                break;
-            default:
-                break;
-        }
-    }
-
-    @computed get frameListHeader() {
-        return (<div className="frameList-header">
-            &nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : (null)}
-            <div className={"frameList-headerButtons"}>
-                <Tooltip title={<><div className="dash-tooltip">{"Add frame by example"}</div></>}><div className={"headerButton"} onClick={e => { e.stopPropagation(); this.newFrame(); }}>
-                    <FontAwesomeIcon icon={"plus"} onPointerDown={e => e.stopPropagation()} />
-                </div></Tooltip>
-                <Tooltip title={<><div className="dash-tooltip">{"Edit in collection"}</div></>}><div className={"headerButton"} onClick={e => { e.stopPropagation(); console.log('New frame'); }}>
-                    <FontAwesomeIcon icon={"edit"} onPointerDown={e => e.stopPropagation()} />
-                </div></Tooltip>
-            </div>
-        </div>);
-    }
-
-    @computed get frameList() {
-        const activeItem: Doc = this.activeItem;
-        const targetDoc: Doc = this.targetDoc;
-        const frameList: List<number> = this.getList(activeItem.frameList);
-        if (frameList) {
-            const frameItems = frameList.map((value) =>
-                <div className="framList-item">
-
-                </div>
-            );
-            return (
-
-                <div className="frameList-container">
-                    {frameItems}
-                </div>
-            );
-        } else return (null);
-
-    }
-
-    @computed get playButtonFrames() {
-        const targetDoc: Doc = this.targetDoc;
-        return (
-            <>
-                {this.targetDoc ? <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? "inline-flex" : "none" }}>
-                    <div>{targetDoc._currentFrame}</div>
-                    <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
-                    <div>{targetDoc.lastFrame}</div>
-                </div> : null}
-            </>
-        );
-    }
-
-    @computed get playButtons() {
-        const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1);
-        const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0);
-        // Case 1: There are still other frames and should go through all frames before going to next slide
-        return (<div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== "edit" ? "inline-flex" : "none" }}>
-            <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? PresColor.DarkBlue : 'white' }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
-            <div className="presPanel-divider"></div>
-            <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onClick={() => { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-left"} /></div>
-            <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? "pause" : "play"} /></div></Tooltip>
-            <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onClick={() => { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-right"} /></div>
-            <div className="presPanel-divider"></div>
-            <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}><b>1</b></div></Tooltip>
-            <div
-                className="presPanel-button-text"
-                onClick={() => this.gotoDocument(0, this.activeItem)}
-                style={{ display: this.props.PanelWidth() > 250 ? "inline-flex" : "none" }}>
-                Slide {this.itemIndex + 1} / {this.childDocs.length}
-                {this.playButtonFrames}
-            </div>
-            <div className="presPanel-divider"></div>
-            {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }))}>EXIT</div>
-                : <div className="presPanel-button" onClick={undoBatch(action(() => this.layoutDoc.presStatus = "edit"))}>
-                    <FontAwesomeIcon icon={"times"} />
-                </div>}
-        </div>);
-    }
-
-    @action
-    startOrPause = () => {
-        if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex);
-        else this.pauseAutoPres();
-    }
-
-    render() {
-        // calling this method for keyEvents
-        this.isPres;
-        // needed to ensure that the childDocs are loaded for looking up fields
-        this.childDocs.slice();
-        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
-        const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
-        const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1);
-        const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0);
-        return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ?
-            <div className="miniPres">
-                <div className="presPanelOverlay" style={{ display: "inline-flex", height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + PresColor.DarkBlue : undefined }}>
-                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? PresColor.DarkBlue : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
-                    <div className="presPanel-divider"></div>
-                    <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onClick={() => { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-left"} /></div>
-                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
-                    <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onClick={() => { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-right"} /></div>
-                    <div className="presPanel-divider"></div>
-                    <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}><b>1</b></div></Tooltip>
-                    <div className="presPanel-button-text">
-                        Slide {this.itemIndex + 1} / {this.childDocs.length}
-                        {this.playButtonFrames}
-                    </div>
-                    <div className="presPanel-divider"></div>
-                    <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.updateMinimize(); this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); }))}>EXIT</div>
-                </div>
-            </div>
-            :
-            <div className="presBox-cont" style={{ minWidth: CurrentUserUtils.OverlayDocs.includes(this.layoutDoc) ? 240 : undefined }} >
-                {this.topPanel}
-                {this.toolbar}
-                {this.newDocumentToolbarDropdown}
-                <div className="presBox-listCont">
-                    {mode !== CollectionViewType.Invalid ?
-                        <CollectionView {...this.props}
-                            ContainingCollectionDoc={this.props.Document}
-                            PanelWidth={this.props.PanelWidth}
-                            PanelHeight={this.panelHeight}
-                            childIgnoreNativeSize={true}
-                            moveDocument={returnFalse}
-                            childFitWidth={returnTrue}
-                            childOpacity={returnOne}
-                            childLayoutTemplate={this.childLayoutTemplate}
-                            filterAddDocument={this.addDocumentFilter}
-                            removeDocument={returnFalse}
-                            dontRegisterView={true}
-                            focus={this.selectElement}
-                            ScreenToLocalTransform={this.getTransform}
-                        />
-                        : (null)
-                    }
-                </div>
-            </div>;
-    }
-}
-Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
-    if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
-    if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 35 : 31;
-    if (field === 'presStatus') return container.presStatus;
-    if (field === '_itemIndex') return container._itemIndex;
-    if (field === 'presBox') return container;
-    return undefined;
-});
\ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 59b2d3753..d1c91cbb9 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -963,7 +963,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
             this.createHighlighterButton(),
             this.createLinkButton(),
             this.createBrushButton(),
-            <div className="richTextMenu-divider" key="divider 2" />,
+            <div className="collectionMenu-divider" key="divider 2" />,
             this.createButton("align-left", "Align Left", this.activeAlignment === "left", this.alignLeft),
             this.createButton("align-center", "Align Center", this.activeAlignment === "center", this.alignCenter),
             this.createButton("align-right", "Align Right", this.activeAlignment === "right", this.alignRight),
@@ -976,7 +976,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         const row2 = <div className="antimodeMenu-row row-2" key="row2">
             {this.collapsed ? this.getDragger() : (null)}
             <div key="row 2" style={{ display: this.collapsed ? "none" : undefined }}>
-                <div className="richTextMenu-divider" key="divider 3" />
+                <div className="collectionMenu-divider" key="divider 3" />
                 {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => {
                     this.activeFontSize = val;
                     SelectionManager.Views().map(dv => dv.props.Document._fontSize = val);
@@ -985,12 +985,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
                     this.activeFontFamily = val;
                     SelectionManager.Views().map(dv => dv.props.Document._fontFamily = val);
                 })),
-                <div className="richTextMenu-divider" key="divider 4" />,
+                <div className="collectionMenu-divider" key="divider 4" />,
                 this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", () => ({})),
                 this.createButton("sort-amount-down", "Summarize", undefined, this.insertSummarizer),
                 this.createButton("quote-left", "Blockquote", undefined, this.insertBlockquote),
-                this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule),
-                <div className="richTextMenu-divider" key="divider 5" />,]}
+                this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule)
+                ]}
             </div>
             {/* <div key="collapser">
                 {<div key="collapser">
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
new file mode 100644
index 000000000..06932d145
--- /dev/null
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -0,0 +1,1243 @@
+@import "../../global/globalCssVariables";
+
+.presBox-cont {
+    cursor: auto;
+    position: absolute;
+    display: block;
+    pointer-events: inherit;
+    z-index: 2;
+    font-family: Roboto;
+    width: 100%;
+    min-width: 20px;
+    height: 100%;
+    min-height: 35px;
+    letter-spacing: 2px;
+    overflow: hidden;
+    transition: 0.7s opacity ease;
+
+    .presBox-listCont {
+        position: relative;
+        height: calc(100% - 67px);
+        width: 100%;
+    }
+
+    .presBox-toolbar-dropdown {
+        border-radius: 5px;
+        background-color: white;
+        transform: translate(8px, -5px);
+        box-shadow: 1px 1px 4px 4px rgba(0, 0, 0, 0.25);
+        z-index: 1000;
+        width: calc(100% - 50px);
+        height: max-content;
+        justify-self: center;
+        letter-spacing: normal;
+        height: max-content;
+        font-weight: 500;
+        position: relative;
+        font-size: 13;
+    }
+
+    .presBox-toolbar {
+        position: relative;
+        display: inline-flex;
+        align-items: center;
+        height: 30px;
+        width: 100%;
+        color: $white;
+        background-color: $dark-gray;
+
+        .toolbar-button {
+            cursor: pointer;
+            margin-left: 10px;
+            margin-right: 10px;
+            letter-spacing: 0;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            transition: 0.5s;
+        }
+
+        .toolbar-button.active {
+            color: $light-blue;
+            background-color: white;
+            border-radius: 100%;
+        }
+
+        .toolbar-transitionButtons {
+            display: block;
+
+            .toolbar-transition {
+                display: flex;
+                font-size: 10;
+                width: 100;
+                background-color: rgba(0, 0, 0, 0);
+                min-width: max-content;
+
+                .toolbar-icon {
+                    margin-right: 5px;
+                }
+            }
+        }
+    }
+
+    .toolbar-moreInfo {
+        position: absolute;
+        right: 5px;
+        display: flex;
+        width: max-content;
+        height: 25px;
+        justify-content: center;
+        transform: rotate(90deg);
+        align-items: center;
+        transition: 0.7s ease;
+
+        .toolbar-moreInfoBall {
+            width: 4px;
+            height: 4px;
+            border-radius: 100%;
+            background-color: white;
+            margin: 1px;
+            position: relative;
+        }
+    }
+
+    .toolbar-moreInfo.active {
+        transform: rotate(0deg);
+    }
+
+    .toolbar-divider {
+        border-left: solid $medium-gray 0.5px;
+        height: 20px;
+    }
+}
+
+.dropdown {
+    font-size: 10;
+    margin-left: 5px;
+    color: $medium-gray;
+    transition: 0.5s ease;
+}
+
+.dropdown.active {
+    transform: rotate(180deg);
+    color: $light-blue;
+    opacity: 0.8;
+}
+
+.presBox-radioButtons {
+    font-size: 10px;
+    font-weight: 200;
+    // background-color: rgba(0, 0, 0, 0.1);
+
+    .checkbox-container {
+        margin-left: 10px;
+        display: inline-flex;
+        width: 100%;
+        height: 20px;
+        align-items: center;
+    }
+
+    .checkbox-dropdown {
+        display: flex;
+        width: 100%;
+        align-items: flex-end;
+        gap: 5px;
+
+        .presBox-viewPicker {
+            width: calc(100% - 120px);
+            min-width: 30px;
+        }
+    }
+}
+
+.presBox-ribbon {
+    position: relative;
+    display: inline;
+    font-family: Roboto;
+    z-index: 100;
+    transition: 0.7s;
+
+    .ribbon-doubleButton {
+        display: inline-flex;
+    }
+
+    .presBox-reactiveGrid {
+        display: grid;
+        justify-content: flex-start;
+        align-items: center;
+        grid-template-columns: repeat(auto-fit, 70px);
+    }
+
+    .ribbon-colorBox {
+        cursor: pointer;
+        border: solid 1px $black;
+        display: flex;
+        margin-left: 5px;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        justify-content: center;
+        align-items: center;
+        height: 15px;
+        width: 15px;
+        padding: 0px;
+        transform: translate(2px, 3px);
+    }
+
+    .ribbon-property {
+        font-size: 11;
+        font-weight: 200;
+        height: 20;
+        background-color: $white;
+        color: $black;
+        border: solid 1px $black;
+        display: flex;
+        margin-left: 5px;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        width: max-content;
+        justify-content: center;
+        align-items: center;
+        padding-right: 10px;
+        padding-left: 10px;
+    }
+
+    .ribbon-propertyUpDown {
+        height: 20;
+        width: 20;
+        margin-top: 5px;
+        display: grid;
+        grid-template-rows: 10px 10px;
+
+        .ribbon-propertyUpDownItem {
+            cursor: pointer;
+            color: white;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            height: 100%;
+            width: 100%;
+            background: $black;
+        }
+
+        .ribbon-propertyUpDownItem:hover {
+            background: $medium-gray;
+            transform: scale(1.05);
+        }
+    }
+
+    .presBox-subheading {
+        font-size: 11;
+        font-weight: 400;
+        margin-top: 10px;
+    }
+
+    @media screen and (-webkit-min-device-pixel-ratio:0) {
+
+        .multiThumb-slider {
+            display: grid;
+            background-color: $white;
+            height: 10px;
+            border-radius: 10px;
+            overflow: hidden;
+
+            .toolbar-slider {
+                margin-top: 0px;
+                background: none;
+                -webkit-appearance: none;
+                pointer-events: none;
+            }
+
+            .toolbar-slider.start::-webkit-slider-thumb {
+                width: 10px;
+                pointer-events: auto;
+                -webkit-appearance: none;
+                height: 10px;
+                cursor: ew-resize;
+                background: $medium-blue;
+                box-shadow: -100vw 0 0 100vw $white;
+            }
+
+            .toolbar-slider.end::-webkit-slider-thumb {
+                width: 10px;
+                pointer-events: auto;
+                -webkit-appearance: none;
+                height: 10px;
+                cursor: ew-resize;
+                background: $medium-blue;
+                box-shadow: -100vw 0 0 100vw $light-blue;
+            }
+        }
+
+        .toolbar-slider {
+            margin-top: 5px;
+            position: relative;
+            align-self: center;
+            justify-self: left;
+            overflow: hidden;
+            width: 100%;
+            height: 10px;
+            border-radius: 10px;
+            -webkit-appearance: none;
+            background-color: $white;
+        }
+
+        .toolbar-slider:focus {
+            outline: none;
+        }
+
+        .toolbar-slider::-webkit-slider-runnable-track {
+            height: 10px;
+            -webkit-appearance: none;
+            margin-top: -1px;
+        }
+
+        .toolbar-slider::-webkit-slider-thumb {
+            width: 10px;
+            pointer-events: auto;
+            -webkit-appearance: none;
+            height: 10px;
+            cursor: ew-resize;
+            background: $medium-blue;
+            box-shadow: -100vw 0 0 100vw $light-blue;
+        }
+
+        .presBox-checkbox {
+            -webkit-appearance: none;
+            -webkit-user-select: none;
+            -moz-user-select: none;
+            -ms-user-select: none;
+            user-select: none;
+            margin: 0;
+            margin-right: 3px;
+            border-radius: 100%;
+            height: 15px;
+            width: 15px;
+            min-width: 15px;
+            cursor: pointer;
+            background: $white;
+        }
+
+        .presBox-checkbox:focus {
+            outline: none;
+        }
+
+        .presBox-checkbox:hover {
+            background: $light-gray;
+        }
+
+        .presBox-checkbox:checked {
+            background: $light-blue;
+        }
+    }
+
+
+
+    .slider-headers {
+        position: relative;
+        display: grid;
+        justify-content: space-between;
+        width: 100%;
+        height: max-content;
+        grid-template-columns: auto auto auto;
+        grid-template-rows: max-content;
+        font-weight: 100;
+        margin-top: 3px;
+        font-size: 10px;
+
+        .slider-block {
+            width: 63px;
+            border-radius: 5px;
+            text-align: center;
+            margin-bottom: 8px;
+            margin-top: 8px;
+        }
+
+        .slider-number {
+            border-radius: 3px;
+            width: 30px;
+            margin: auto;
+        }
+    }
+
+    .slider-value {
+        top: -20;
+        color: #2f86a2;
+        position: absolute;
+    }
+
+    .slider-value.none,
+    .slider-headers.none,
+    .toolbar-slider.none {
+        display: none;
+    }
+
+    .dropdown-header {
+        padding-bottom: 10px;
+        font-weight: 800;
+        text-align: center;
+        font-size: 16;
+        width: 90%;
+        color: $black;
+        transform: translate(5%, 0px);
+        border-bottom: solid 2px $medium-gray;
+    }
+
+
+    .ribbon-textInput {
+        border-radius: 2px;
+        height: 20px;
+        font-size: 11.5;
+        font-weight: 100;
+        align-self: center;
+        justify-self: left;
+        margin-top: 5px;
+        padding-left: 10px;
+        background-color: $white;
+        border: solid 1px $black;
+        min-width: 80px;
+        max-width: 200px;
+        width: 100%;
+    }
+
+    .presBox-input {
+        width: 30;
+        height: 100%;
+        background: none;
+        border: none;
+        text-align: right;
+    }
+
+    .presBox-input:focus {
+        outline: none;
+    }
+
+    .ribbon-frameSelector {
+        border: $black solid 1px;
+        width: 60px;
+        height: 20px;
+        margin-top: 5px;
+        display: grid;
+        grid-template-columns: auto 27px auto;
+        position: relative;
+        border-radius: 5px;
+        overflow: hidden;
+        align-items: center;
+        justify-self: left;
+
+        .fwdKeyframe,
+        .backKeyframe {
+            cursor: pointer;
+            position: relative;
+            height: 100%;
+            background: $white;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            text-align: center;
+            color: $black;
+        }
+
+        .numKeyframe {
+            cursor: pointer;
+            font-size: 10;
+            font-weight: 600;
+            position: relative;
+            color: $black;
+            display: flex;
+            width: 100%;
+            height: 100%;
+            text-align: center;
+            align-items: center;
+            justify-content: center;
+        }
+    }
+
+    .ribbon-final-box {
+        align-self: flex-start;
+        justify-self: center;
+        display: grid;
+        margin-top: 10px;
+        grid-template-rows: auto auto;
+        /* padding-left: 10px; */
+        /* padding-right: 10px; */
+        letter-spacing: normal;
+        min-width: max-content;
+        width: 100%;
+        font-size: 13;
+        font-weight: 500;
+        position: relative;
+
+
+        .ribbon-final-button {
+            cursor: pointer;
+            position: relative;
+            font-size: 11;
+            font-weight: normal;
+            letter-spacing: normal;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            margin-bottom: 5px;
+            height: 25px;
+            color: white;
+            width: 100%;
+            max-width: 120;
+            padding-left: 10;
+            padding-right: 10;
+            border-radius: 10px;
+            background-color: $medium-gray;
+        }
+
+        .ribbon-final-button:hover {
+            transform: scale(1.05);
+            transition: all 0.4s;
+        }
+
+        .ribbon-final-button-hidden {
+            cursor: pointer;
+            position: relative;
+            font-size: 11;
+            font-weight: normal;
+            letter-spacing: normal;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            margin-bottom: 5px;
+            height: 25px;
+            color: $light-gray;
+            width: 100%;
+            max-width: 120;
+            padding-left: 10;
+            padding-right: 10;
+            border-radius: 10px;
+            background-color: $black;
+        }
+
+        .ribbon-final-button-hidden:hover {
+            transform: scale(1.05);
+            transition: all 0.4s;
+        }
+
+        .ribbon-frameList {
+            width: calc(100% - 5px);
+            height: 50px;
+            background-color: $white;
+            border: 1px solid $medium-gray;
+            grid-template-rows: max-content;
+
+            .frameList-header {
+                display: grid;
+                width: 100%;
+                height: 20px;
+                background-color: $medium-gray;
+
+                .frameList-headerButtons {
+                    display: flex;
+                    grid-column: 7;
+                    width: 60px;
+                    justify-self: right;
+                    justify-content: flex-end;
+
+                    .headerButton {
+                        cursor: pointer;
+                        position: relative;
+                        border-radius: 100%;
+                        z-index: 300;
+                        width: 15px;
+                        height: 15px;
+                        display: flex;
+                        font-size: 10px;
+                        justify-self: center;
+                        align-self: center;
+                        background-color: rgba(0, 0, 0, 0.5);
+                        color: white;
+                        justify-content: center;
+                        align-items: center;
+                        transition: 0.2s;
+                        margin-right: 3px;
+                    }
+
+                    .headerButton:hover {
+                        background-color: rgba(0, 0, 0, 1);
+                        transform: scale(1.15);
+                    }
+                }
+            }
+        }
+    }
+
+    .selectedList {
+        display: block;
+        min-width: 50;
+        max-width: 120;
+        height: 70;
+        overflow-y: scroll;
+
+        .selectedList-items {
+            font-size: 7;
+            font-weight: normal;
+        }
+    }
+
+    .ribbon-button {
+        cursor: pointer;
+        font-size: 10.5;
+        font-weight: 300;
+        height: 20;
+        background-color: $medium-gray;
+        color: white;
+        display: flex;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        border-radius: 5px;
+        margin-right: 5px;
+        width: max-content;
+        justify-content: center;
+        align-items: center;
+        padding-right: 10px;
+        padding-left: 10px;
+    }
+
+    .ribbon-button:hover {
+        transform: scale(1.03);
+        transition: all 0.4s;
+        font-weight: 400;
+        opacity: 1;
+        color: $white;
+        background-color: $black;
+    }
+
+    .ribbon-toggle {
+        cursor: pointer;
+        font-size: 10.5;
+        font-weight: 200;
+        height: 20;
+        background-color: $white;
+        border: solid 1px rgba(0, 0, 0, 0.5);
+        display: flex;
+        color: $black;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        border-radius: 5px;
+        margin-right: 5px;
+        width: max-content;
+        justify-content: center;
+        align-items: center;
+        padding-right: 10px;
+        padding-left: 10px;
+    }
+
+    .ribbon-toggle.active {
+        background-color: #aedef8;
+    }
+
+    .ribbon-toggle:hover {
+        transform: scale(1.03);
+        transition: all 0.4s;
+        border: solid 1px rgba(0, 0, 0, 0.75);
+    }
+
+    svg.svg-inline--fa.fa-thumbtack.fa-w-12.toolbar-thumbtack {
+        right: 40;
+        position: absolute;
+        transform: rotate(45deg);
+    }
+
+    .ribbon-box {
+        display: grid;
+        grid-template-rows: max-content auto;
+        justify-self: center;
+        margin-top: 10px;
+        padding-right: 10px;
+        letter-spacing: normal;
+        width: 100%;
+        height: max-content;
+        font-weight: 500;
+        position: relative;
+        font-size: 13;
+        padding-bottom: 10px;
+        border-bottom: solid 1px $dark-gray;
+
+        .presBox-dropdown:hover {
+            border: solid 1px $medium-blue;
+
+            .presBox-dropdownIcon {
+                color: $medium-blue;
+            }
+        }
+
+        .presBox-dropdown {
+            cursor: pointer;
+            display: grid;
+            grid-template-columns: auto 20%;
+            position: relative;
+            border: solid 1px $black;
+            background-color: $light-gray;
+            border-radius: 5px;
+            font-size: 10;
+            height: 25;
+            color: $black;
+            padding-left: 5px;
+            align-items: center;
+            margin-top: 5px;
+            margin-bottom: 5px;
+            font-weight: 200;
+            width: 100%;
+            min-width: max-content;
+            max-width: 200px;
+            overflow: visible;
+
+
+            .presBox-dropdownOption {
+                cursor: pointer;
+                font-size: 11;
+                display: block;
+                padding-left: 10px;
+                padding-right: 5px;
+                padding-top: 3;
+                padding-bottom: 3;
+            }
+
+            .presBox-dropdownOption:hover {
+                position: relative;
+                background-color: lightgrey;
+            }
+
+            .presBox-dropdownOption.active {
+                position: relative;
+                background-color: $light-blue;
+            }
+
+            .presBox-dropdownOptions {
+                position: absolute;
+                top: 23px;
+                left: -2px;
+                z-index: 200;
+                width: 85%;
+                min-width: max-content;
+                display: block;
+                background: #FFFFFF;
+                border: 0.5px solid #979797;
+                box-sizing: border-box;
+                box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+            }
+
+            .presBox-dropdownIcon {
+                position: relative;
+                color: black;
+                align-self: center;
+                justify-self: center;
+                margin-right: 2px;
+            }
+        }
+    }
+}
+
+.presBox-ribbon.active {
+    display: grid;
+    grid-template-columns: auto auto auto auto auto;
+    grid-template-rows: 100%;
+    height: 100px;
+    padding-top: 5px;
+    padding-bottom: 5px;
+    border: solid 1px $black;
+    // overflow: auto; 
+
+    ::-webkit-scrollbar {
+        -webkit-appearance: none;
+        height: 3px;
+        width: 8px;
+    }
+
+    ::-webkit-scrollbar-thumb {
+        border-radius: 2px;
+    }
+}
+
+.dropdown-play-button {
+    cursor: pointer;
+    font-size: 12;
+    padding-left: 5px;
+    padding-right: 5px;
+    padding-top: 5px;
+    padding-bottom: 5px;
+    text-align: left;
+    justify-content: left;
+}
+
+.dropdown-play-button:hover {
+    background-color: lightgrey;
+}
+
+.presBox-button-left {
+    cursor: pointer;
+    position: relative;
+    align-self: flex-start;
+    justify-self: flex-start;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 4px;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-bottom-right-radius: 0;
+    border-top-right-radius: 0;
+}
+
+.presBox-button-right {
+    cursor: pointer;
+    position: relative;
+    text-align: center;
+    border-left: solid 1px $medium-gray;
+    width: 20%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 4px;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-bottom-left-radius: 0;
+    border-top-left-radius: 0;
+}
+
+.presBox-button-right.active {
+    background-color: #223063;
+    border: #aedcf6 solid 1px;
+    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
+}
+
+.dropdown-play {
+    cursor: pointer;
+    right: 0px;
+    top: calc(100% + 2px);
+    display: none;
+    border-radius: 5px;
+    width: max-content;
+    min-height: 20px;
+    height: max-content;
+    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
+    z-index: 200;
+    background-color: white;
+    color: $black;
+    position: absolute;
+    overflow: hidden;
+}
+
+.dropdown-play.active {
+    display: block;
+}
+
+.open-layout {
+    cursor: pointer;
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transform: translate(0px, -1px);
+    background-color: $white;
+    width: 40px;
+    height: 15px;
+    align-self: center;
+    justify-self: center;
+    border: solid 1px $black;
+    border-top: 0px;
+    border-bottom-right-radius: 7px;
+    border-bottom-left-radius: 7px;
+}
+
+.layout-container {
+    padding: 5px;
+    display: grid;
+    background-color: $white;
+    grid-template-columns: repeat(auto-fit, minmax(90px, 100px));
+    width: 100%;
+    border: solid 1px $black;
+    min-width: 100px;
+    overflow: hidden;
+
+    .layout:hover {
+        border: solid 2px $medium-blue;
+    }
+
+    .layout {
+        cursor: pointer;
+        align-self: center;
+        justify-self: center;
+        margin-top: 5;
+        margin-bottom: 5;
+        position: relative;
+        height: 55px;
+        min-width: 90px;
+        width: 90px;
+        overflow: hidden;
+        background-color: white;
+        border: solid $medium-gray 1px;
+        display: grid;
+        grid-template-rows: auto;
+        align-items: center;
+        text-align: center;
+
+        .title {
+            position: relative;
+            align-self: end;
+            padding-left: 3px;
+            margin-left: 3px;
+            margin-right: 3px;
+            height: 13;
+            font-size: 12;
+            display: flex;
+            background-color: $white;
+        }
+
+        .subtitle {
+            align-self: flex-start;
+            position: relative;
+            padding-left: 3px;
+            margin-left: 3px;
+            margin-right: 3px;
+            font-weight: 400;
+            height: 13;
+            font-size: 9;
+            display: flex;
+            background-color: $white;
+        }
+
+        .content {
+            position: relative;
+            font-weight: 200;
+            align-self: flex-start;
+            padding-left: 3px;
+            margin-left: 3px;
+            margin-right: 3px;
+            height: 13;
+            font-size: 10;
+            display: flex;
+            background-color: $white;
+            height: 33;
+            text-align: left;
+            font-size: 8px;
+        }
+    }
+}
+
+.presBox-buttons {
+    position: relative;
+    width: 100%;
+    background: $medium-gray;
+    min-height: 35px;
+    padding-top: 5px;
+    padding-bottom: 5px;
+    display: grid;
+    grid-template-columns: auto auto;
+
+    .presBox-viewPicker {
+        cursor: pointer;
+        height: 25;
+        position: relative;
+        display: inline-block;
+        grid-column: 1;
+        border-radius: 5px;
+        min-width: 15px;
+        max-width: 100px;
+        left: 8px;
+    }
+
+    .presBox-presentPanel {
+        display: flex;
+        justify-self: end;
+        width: 100%;
+        max-width: 300px;
+        min-width: 150px;
+    }
+
+
+
+    select {
+        background: $dark-gray;
+        color: $white;
+    }
+
+    .presBox-button {
+        cursor: pointer;
+        height: 25px;
+        border-radius: 5px;
+        display: none;
+        justify-content: center;
+        align-content: center;
+        align-items: center;
+        text-align: center;
+        letter-spacing: normal;
+        width: inherit;
+        background: $dark-gray;
+        color: $white;
+    }
+
+    .presBox-button.active {
+        display: flex;
+    }
+
+    .presBox-button.active:hover {
+        background-color: $medium-blue;
+    }
+
+    .presBox-button.edit {
+        display: flex;
+        max-width: 25px;
+    }
+
+    .presBox-button.present {
+        display: flex;
+        width: max-content;
+        position: absolute;
+        right: 10px;
+
+        .present-icon {
+            margin-right: 7px;
+        }
+    }
+
+
+
+    .collectionViewBaseChrome-viewPicker {
+        min-width: 50;
+        width: 5%;
+        height: 25;
+        position: relative;
+        display: inline-block;
+        left: 8px;
+    }
+}
+
+.presBox-backward,
+.presBox-forward {
+    width: 25px;
+    border-radius: 5px;
+    top: 50%;
+    position: absolute;
+    display: inline-block;
+}
+
+.presBox-backward {
+    left: 5;
+}
+
+.presBox-forward {
+    right: 5;
+}
+
+// CSS adjusted for mobile devices
+@media only screen and (max-device-width: 480px) {
+    .presBox-cont .presBox-buttons {
+        position: absolute;
+        top: 70%;
+        left: 50%;
+        transform: translate(-50%, 0);
+        width: max-content;
+        height: 15%;
+        z-index: 2;
+        align-items: center;
+        background: rgba(0, 0, 0, 0);
+        display: inline-flex;
+
+        .presBox-button {
+            margin-top: 5%;
+            height: 250;
+            width: 300;
+            font-size: 100;
+            display: flex;
+            align-items: center;
+            background: $dark-gray;
+            color: $white;
+        }
+
+        .presBox-viewPicker {
+            top: -70;
+            left: 2.5%;
+            height: 50;
+            width: 95%;
+            font-size: 30px;
+            position: absolute;
+            min-width: 50px;
+        }
+    }
+
+    .presBox-cont .presBox-listCont {
+        top: 50;
+        height: calc(100% - 80px);
+    }
+
+    .input,
+    .select {
+        font-size: 100%;
+    }
+}
+
+.miniPres {
+    cursor: grab;
+    position: absolute;
+    right: 10;
+    top: 10;
+    opacity: 0.1;
+    transition: all 0.4s;
+    color: $white;
+}
+
+.miniPres:hover {
+    opacity: 1;
+}
+
+.presPanelOverlay {
+    background-color: $dark-gray;
+    color: $white;
+    border-radius: 5px;
+    grid-template-rows: 100%;
+    height: 25;
+    width: max-content;
+    min-width: max-content;
+    justify-content: space-evenly;
+    align-items: center;
+    display: flex;
+    position: absolute;
+    right: 10px;
+    transition: all 0.2s;
+
+    .presPanel-button-text {
+        cursor: pointer;
+        display: flex;
+        height: 20;
+        width: max-content;
+        font-family: Roboto;
+        font-weight: 400;
+        margin-left: 3px;
+        margin-right: 3px;
+        padding-right: 3px;
+        padding-left: 3px;
+        letter-spacing: normal;
+        border-radius: 5px;
+        align-items: center;
+        justify-content: center;
+        transition: all 0.3s;
+    }
+
+    .presPanel-divider {
+        width: 0.5px;
+        height: 80%;
+        border-right: solid 1px $medium-gray;
+    }
+
+    .presPanel-button-frame {
+        justify-self: center;
+        align-self: center;
+        align-items: center;
+        display: grid;
+        grid-template-columns: auto auto auto;
+        justify-content: space-around;
+        font-size: 11;
+        margin-left: 7;
+        width: 30;
+        height: 85%;
+        background-color: rgba(91, 157, 221, 0.4);
+        border-radius: 5px;
+    }
+
+    .presPanel-button {
+        cursor: pointer;
+        display: flex;
+        height: 20;
+        min-width: 20;
+        margin-left: 3px;
+        margin-right: 3px;
+        border-radius: 100%;
+        align-items: center;
+        justify-content: center;
+        transition: all 0.3s;
+    }
+
+    .presPanel-button:hover {
+        background-color: $medium-gray;
+        transform: scale(1.2);
+    }
+
+    .presPanel-button-text:hover {
+        background-color: $medium-gray;
+    }
+
+
+}
+
+// .miniPres {
+//     cursor: grab;
+//     position: absolute;
+//     overflow: hidden;
+//     right: 10;
+//     top: 10;
+//     opacity: 0.1;
+//     transition: all 0.4s;
+//     /* border: solid 1px; */
+//     color: white;
+//     /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+
+//     .miniPresOverlay {
+//         display: grid;
+//         grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
+//         grid-template-rows: 100%;
+//         height: 100%;
+//         justify-items: center;
+//         align-items: center;
+
+//         .miniPres-button-text {
+//             cursor: pointer;
+//             display: flex;
+//             height: 20;
+//             font-weight: 400;
+//             min-width: 100%;
+//             border-radius: 5px;
+//             align-items: center;
+//             justify-content: center;
+//             transition: all 0.3s;
+//         }
+
+//         .miniPres-button-frame {
+//             justify-self: center;
+//             align-self: center;
+//             align-items: center;
+//             display: grid;
+//             grid-template-columns: auto auto auto;
+//             justify-content: space-around;
+//             font-size: 11;
+//             margin-left: 7;
+//             width: 30;
+//             height: 85%;
+//             background-color: rgba(91, 157, 221, 0.4);
+//             border-radius: 5px;
+//         }
+
+//         .miniPres-divider {
+//             width: 0.5px;
+//             height: 80%;
+//             border-right: solid 2px #5a5a5a;
+//         }
+
+//         .miniPres-button {
+//             cursor: pointer;
+//             display: flex;
+//             height: 20;
+//             min-width: 20;
+//             border-radius: 100%;
+//             align-items: center;
+//             justify-content: center;
+//             transition: all 0.3s;
+//         }
+
+//         .miniPres-button:hover {
+//             background-color: #5a5a5a;
+//         }
+
+//         .miniPres-button-text:hover {
+//             background-color: #5a5a5a;
+//         }
+//     }
+// }
\ No newline at end of file
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
new file mode 100644
index 000000000..5cb9866f8
--- /dev/null
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -0,0 +1,2440 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { ColorState, SketchPicker } from "react-color";
+import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
+import { Doc, DocListCast, DocListCastAsync, FieldResult } from "../../../../fields/Doc";
+import { documentSchema } from "../../../../fields/documentSchemas";
+import { InkTool } from "../../../../fields/InkField";
+import { List } from "../../../../fields/List";
+import { PrefetchProxy } from "../../../../fields/Proxy";
+import { listSpec, makeInterface } from "../../../../fields/Schema";
+import { ScriptField } from "../../../../fields/ScriptField";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types";
+import { emptyFunction, returnFalse, returnOne, returnTrue } from '../../../../Utils';
+import { Docs } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { Scripting } from "../../../util/Scripting";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
+import { CollectionDockingView } from "../../collections/CollectionDockingView";
+import { CollectionView, CollectionViewType } from "../../collections/CollectionView";
+import { TabDocView } from "../../collections/TabDocView";
+import { ViewBoxBaseComponent } from "../../DocComponent";
+import { Colors } from "../../global/globalEnums";
+import { LightboxView } from "../../LightboxView";
+import { CollectionFreeFormDocumentView } from "../CollectionFreeFormDocumentView";
+import { FieldView, FieldViewProps } from '../FieldView';
+import "./PresBox.scss";
+import Color = require("color");
+import { PresEffect, PresStatus, PresMovement } from "./PresEnums";
+
+export class PinProps {
+    audioRange?: boolean;
+    unpin?: boolean;
+    setPosition?: boolean;
+    hidePresBox?: boolean;
+}
+
+type PresBoxSchema = makeInterface<[typeof documentSchema]>;
+const PresBoxDocument = makeInterface(documentSchema);
+
+@observer
+export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
+
+    static renderEffectsDoc(renderDoc: any, layoutDoc: Doc) {
+        const effectProps = {
+            left: layoutDoc.presEffectDirection === PresEffect.Left,
+            right: layoutDoc.presEffectDirection === PresEffect.Right,
+            top: layoutDoc.presEffectDirection === PresEffect.Top,
+            bottom: layoutDoc.presEffectDirection === PresEffect.Bottom,
+            opposite: true,
+            delay: layoutDoc.presTransition,
+            // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
+        };
+        switch (layoutDoc.presEffect) {
+            case PresEffect.Zoom: return (<Zoom {...effectProps}>{renderDoc}</Zoom>);
+            case PresEffect.Fade: return (<Fade {...effectProps}>{renderDoc}</Fade>);
+            case PresEffect.Flip: return (<Flip {...effectProps}>{renderDoc}</Flip>);
+            case PresEffect.Rotate: return (<Rotate {...effectProps}>{renderDoc}</Rotate>);
+            case PresEffect.Bounce: return (<Bounce {...effectProps}>{renderDoc}</Bounce>);
+            case PresEffect.Roll: return (<Roll {...effectProps}>{renderDoc}</Roll>);
+            case PresEffect.Lightspeed: return (<LightSpeed {...effectProps}>{renderDoc}</LightSpeed>);
+            case PresEffect.None:
+            default: return renderDoc;
+        }
+    }
+    public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
+        return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ?
+            PresBox.renderEffectsDoc(renderDoc, layoutDoc)
+            :
+            renderDoc;
+    }
+
+    @observable public static Instance: PresBox;
+
+    @observable _isChildActive = false;
+    @observable _moveOnFromAudio: boolean = true;
+    @observable _presTimer!: NodeJS.Timeout;
+    @observable _presKeyEventsActive: boolean = false;
+
+    @observable _selectedArray: ObservableMap = new ObservableMap<Doc, any>();
+    @observable _eleArray: HTMLElement[] = [];
+    @observable _dragArray: HTMLElement[] = [];
+    @observable _pathBoolean: boolean = false;
+    @observable _expandBoolean: boolean = false;
+
+    private _disposers: { [name: string]: IReactionDisposer } = {};
+    @observable private transitionTools: boolean = false;
+    @observable private newDocumentTools: boolean = false;
+    @observable private progressivizeTools: boolean = false;
+    @observable private openMovementDropdown: boolean = false;
+    @observable private openEffectDropdown: boolean = false;
+    @observable private presentTools: boolean = false;
+    @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
+    @computed get tagDocs() {
+        const tagDocs: Doc[] = [];
+        for (const doc of this.childDocs) {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            tagDocs.push(tagDoc);
+        }
+        return tagDocs;
+    }
+    @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); }
+    @computed get activeItem() { return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null); }
+    @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); }
+    @computed get scrollable(): boolean {
+        if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
+        else return false;
+    }
+    @computed get panable(): boolean {
+        if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
+        else return false;
+    }
+    @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); }
+    constructor(props: any) {
+        super(props);
+        if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => PresBox.Instance = this);
+        if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations.
+            Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
+                title: "pres element template", type: DocumentType.PRESELEMENT, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
+            }));
+            // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
+            // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
+            // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data
+            // stored on each pres element.
+            (this.presElement as Doc).lookupField = ScriptField.MakeFunction("lookupPresBoxField(container, field, data)",
+                { field: "string", data: Doc.name, container: Doc.name });
+        }
+        this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
+    }
+    @computed get selectedDocumentView() {
+        if (SelectionManager.Views().length) return SelectionManager.Views()[0];
+        if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
+    }
+    @computed get isPres(): boolean {
+        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
+        if (this.selectedDoc?.type === DocumentType.PRES) {
+            document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
+            document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
+            return true;
+        }
+        return false;
+    }
+    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+
+    @action
+    componentWillUnmount() {
+        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
+        this._presKeyEventsActive = false;
+        this.resetPresentation();
+        // Turn of progressivize editors
+        this.turnOffEdit(true);
+        Object.values(this._disposers).forEach(disposer => disposer?.());
+    }
+
+    @action
+    componentDidMount() {
+        this.rootDoc.presBox = this.rootDoc;
+        this.rootDoc._forceRenderEngine = "timeline";
+        this.layoutDoc.presStatus = PresStatus.Edit;
+        this.layoutDoc._gridGap = 0;
+        this.layoutDoc._yMargin = 0;
+        this.turnOffEdit(true);
+        DocListCastAsync((Doc.UserDoc().myPresentations as Doc).data).then(pres =>
+            !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc));
+        this._disposers.selection = reaction(() => SelectionManager.Views(),
+            views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation());
+    }
+
+    @action
+    updateCurrentPresentation = (pres?: Doc) => {
+        if (pres) Doc.UserDoc().activePresentation = pres;
+        else Doc.UserDoc().activePresentation = this.rootDoc;
+        document.removeEventListener("keydown", PresBox.keyEventsWrapper, true);
+        document.addEventListener("keydown", PresBox.keyEventsWrapper, true);
+        this._presKeyEventsActive = true;
+        PresBox.Instance = this;
+    }
+
+    // There are still other internal frames and should go through all frames before going to next slide
+    nextInternalFrame = (targetDoc: Doc, activeItem: Doc) => {
+        const currentFrame = Cast(targetDoc?._currentFrame, "number", null);
+        const childDocs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+        targetDoc._viewTransition = "all 1s";
+        setTimeout(() => targetDoc._viewTransition = undefined, 1010);
+        this.nextKeyframe(targetDoc, activeItem);
+        if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
+        else targetDoc.keyFrameEditing = true;
+    }
+
+    _mediaTimer!: [NodeJS.Timeout, Doc];
+    // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
+    startTempMedia = (targetDoc: Doc, activeItem: Doc) => {
+        const duration: number = NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime);
+        if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
+            const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
+            targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration);
+        }
+        // if (targetDoc.type === DocumentType.AUDIO) {
+        //     if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
+        //     targetDoc._triggerAudio = NumCast(activeItem.presStartTime);
+        //     this._mediaTimer = [setTimeout(() => targetDoc._audioStop = true, duration * 1000), targetDoc];
+        // } else if (targetDoc.type === DocumentType.VID) {
+        //     targetDoc._triggerVideoStop = true;
+        //     setTimeout(() => targetDoc._currentTimecode = NumCast(activeItem.presStartTime), 10);
+        //     setTimeout(() => targetDoc._triggerVideo = true, 20);
+        //     this._mediaTimer = [setTimeout(() => targetDoc._triggerVideoStop = true, (duration * 1000) + 20), targetDoc];
+        // }
+    }
+
+    stopTempMedia = (targetDocField: FieldResult) => {
+        const targetDoc = Cast(targetDocField, Doc, null);
+        if (targetDoc?.type === DocumentType.AUDIO) {
+            if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
+            targetDoc._audioStop = true;
+        } else if (targetDoc?.type === DocumentType.VID) {
+            if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
+            targetDoc._triggerVideoStop = true;
+        }
+    }
+
+    // No more frames in current doc and next slide is defined, therefore move to next slide 
+    nextSlide = (activeNext: Doc) => {
+        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
+        let nextSelected = this.itemIndex + 1;
+        this.gotoDocument(nextSelected, this.activeItem);
+        for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
+            if (!this.childDocs[nextSelected].groupWithUp) {
+                break;
+            } else {
+                console.log("Title: " + this.childDocs[nextSelected].title);
+                this.gotoDocument(nextSelected, this.activeItem, true);
+            }
+        }
+    }
+
+    // Called when the user activates 'next' - to move to the next part of the pres. trail
+    @action
+    next = () => {
+        const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null);
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const lastFrame = Cast(targetDoc?.lastFrame, "number", null);
+        const curFrame = NumCast(targetDoc?._currentFrame);
+        let internalFrames: boolean = false;
+        if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
+        if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
+            // Case 1: There are still other frames and should go through all frames before going to next slide
+            this.nextInternalFrame(targetDoc, activeItem);
+        } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
+            // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide 
+            this.nextSlide(activeNext);
+        } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
+            // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
+            this.gotoDocument(0, this.activeItem);
+        }
+    }
+
+    // Called when the user activates 'back' - to move to the previous part of the pres. trail
+    @action
+    back = () => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null);
+        const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
+        const lastFrame = Cast(targetDoc.lastFrame, "number", null);
+        const curFrame = NumCast(targetDoc._currentFrame);
+        let prevSelected = this.itemIndex;
+        // Functionality for group with up
+        let didZoom = activeItem.presMovement;
+        for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
+            didZoom = this.childDocs[prevSelected].presMovement;
+        }
+        if (lastFrame !== undefined && curFrame >= 1) {
+            // Case 1: There are still other frames and should go through all frames before going to previous slide
+            this.prevKeyframe(targetDoc, activeItem);
+        } else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
+            // Case 2: There are no other frames so it should go to the previous slide
+            prevSelected = Math.max(0, prevSelected - 1);
+            this.gotoDocument(prevSelected, activeItem);
+            if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
+        } else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
+            // Case 3: Pres loop is on so it should go to the last slide
+            this.gotoDocument(this.childDocs.length - 1, activeItem);
+        }
+    }
+
+    //The function that is called when a document is clicked or reached through next or back.
+    //it'll also execute the necessary actions if presentation is playing.
+    public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
+        Doc.UnBrushAllDocs();
+        if (index >= 0 && index < this.childDocs.length) {
+            this.rootDoc._itemIndex = index;
+            const activeItem: Doc = this.activeItem;
+            const targetDoc: Doc = this.targetDoc;
+            if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
+                DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
+            }
+            if (from?.mediaStop === "auto" && this.layoutDoc.presStatus !== PresStatus.Edit) {
+                this.stopTempMedia(from.presentationTargetDoc);
+            }
+            // If next slide is audio / video 'Play automatically' then the next slide should be played
+            if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && (activeItem.mediaStart === "auto")) {
+                this.startTempMedia(targetDoc, activeItem);
+            }
+            if (targetDoc) {
+                targetDoc && runInAction(() => {
+                    if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
+                    else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
+                });
+                setTimeout(() => targetDoc.focusSpeed = 500, this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+            }
+            if (targetDoc?.lastFrame !== undefined) {
+                targetDoc._currentFrame = 0;
+            }
+            if (!group) this._selectedArray.clear();
+            this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
+            if (this.layoutDoc._viewType === "stacking" && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+            this.onHideDocument(); //Handles hide after/before
+        }
+    });
+
+    _navTimer!: NodeJS.Timeout;
+    navigateToView = (targetDoc: Doc, activeItem: Doc) => {
+        clearTimeout(this._navTimer);
+        const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
+        bestTarget && runInAction(() => {
+            if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
+                bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
+                bestTarget._scrollTop = activeItem.presPinViewScroll;
+            } else if (bestTarget.type === DocumentType.COMPARISON) {
+                bestTarget._clipWidth = activeItem.presPinClipWidth;
+            } else if (bestTarget.type === DocumentType.VID) {
+                bestTarget._currentTimecode = activeItem.presPinTimecode;
+            } else {
+                bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
+                bestTarget._panX = activeItem.presPinViewX;
+                bestTarget._panY = activeItem.presPinViewY;
+                bestTarget._viewScale = activeItem.presPinViewScale;
+            }
+            this._navTimer = setTimeout(() => bestTarget._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510);
+        });
+    }
+
+    /**
+     * This method makes sure that cursor navigates to the element that
+     * has the option open and last in the group. 
+     * Design choice: If the next document is not in presCollection or 
+     * presCollection itself then if there is a presCollection it will add
+     * a new tab. If presCollection is undefined it will open the document
+     * on the right. 
+     */
+    navigateToElement = async (curDoc: Doc) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const srcContext = Cast(targetDoc.context, Doc, null);
+        const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
+        const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
+        const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
+        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext);
+        this.turnOffEdit();
+        // Handles the setting of presCollection
+        if (includesDoc) {
+            //Case 1: Pres collection should not change as it is already the same
+        } else if (tab !== undefined) {
+            // Case 2: Pres collection should update
+            this.layoutDoc.presCollection = srcContext;
+        }
+        const presStatus = this.rootDoc.presStatus;
+        const selViewCache = Array.from(this._selectedArray.keys());
+        const dragViewCache = Array.from(this._dragArray);
+        const eleViewCache = Array.from(this._eleArray);
+        const self = this;
+        const resetSelection = action(() => {
+            const presDocView = DocumentManager.Instance.getDocumentView(self.rootDoc);
+            if (presDocView) SelectionManager.SelectView(presDocView, false);
+            self.rootDoc.presStatus = presStatus;
+            self._selectedArray.clear();
+            selViewCache.forEach(doc => self._selectedArray.set(doc, undefined));
+            self._dragArray.splice(0, self._dragArray.length, ...dragViewCache);
+            self._eleArray.splice(0, self._eleArray.length, ...eleViewCache);
+        });
+        const openInTab = (doc: Doc, finished?: () => void) => {
+            collectionDocView ? collectionDocView.props.addDocTab(doc, "") : this.props.addDocTab(doc, ":left");
+            this.layoutDoc.presCollection = targetDoc;
+            // this still needs some fixing
+            setTimeout(resetSelection, 500);
+            if (doc !== targetDoc) {
+                setTimeout(finished ?? emptyFunction, 100); /// give it some time to create the targetDoc if we're opening up its context
+            } else {
+                finished?.();
+            }
+        };
+        // If openDocument is selected then it should open the document for the user
+        if (activeItem.openDocument) {
+            LightboxView.SetLightboxDoc(targetDoc);
+        } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
+            LightboxView.SetLightboxDoc(undefined);
+            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right
+        } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
+            LightboxView.SetLightboxDoc(undefined);
+            //awaiting jump so that new scale can be found, since jumping is async     
+            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right    
+        }
+        // After navigating to the document, if it is added as a presPinView then it will
+        // adjust the pan and scale to that of the pinView when it was added.
+        if (activeItem.presPinView) {
+            // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
+            this.navigateToView(targetDoc, activeItem);
+        }
+        // TODO: Add progressivize for navigating web (storing websites for given frames)
+
+    }
+
+    /**
+     * Uses the viewfinder to progressivize through the different views of a single collection.
+     * @param presTargetDoc: document for which internal zoom is used
+     */
+    zoomProgressivizeNext = (activeItem: Doc) => {
+        const targetDoc: Doc = this.targetDoc;
+        const srcContext = Cast(targetDoc?.context, Doc, null);
+        const docView = DocumentManager.Instance.getDocumentView(targetDoc);
+        const vfLeft = this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
+        const vfWidth = this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
+        const vfTop = this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
+        const vfHeight = this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
+        // Case 1: document that is not a Golden Layout tab
+        if (srcContext) {
+            const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
+            if (srcDocView) {
+                const layoutdoc = Doc.Layout(targetDoc);
+                const panelWidth: number = srcDocView.props.PanelWidth();
+                const panelHeight: number = srcDocView.props.PanelHeight();
+                const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2;
+                const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2;
+                const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
+                srcContext._panX = newPanX + (vfLeft + (vfWidth / 2));
+                srcContext._panY = newPanY + (vfTop + (vfHeight / 2));
+                srcContext._viewScale = newScale;
+            }
+        }
+        // Case 2: document is the containing collection
+        if (docView && !srcContext) {
+            const panelWidth: number = docView.props.PanelWidth();
+            const panelHeight: number = docView.props.PanelHeight();
+            const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
+            targetDoc._panX = vfLeft + (vfWidth / 2);
+            targetDoc._panY = vfTop + (vfWidth / 2);
+            targetDoc._viewScale = newScale;
+        }
+        const resize = document.getElementById('resizable');
+        if (resize) {
+            resize.style.width = vfWidth + 'px';
+            resize.style.height = vfHeight + 'px';
+            resize.style.top = vfTop + 'px';
+            resize.style.left = vfLeft + 'px';
+        }
+    }
+
+    /**
+     * For 'Hide Before' and 'Hide After' buttons making sure that
+     * they are hidden each time the presentation is updated.
+     */
+    @action
+    onHideDocument = () => {
+        this.childDocs.forEach((doc, index) => {
+            const curDoc = Cast(doc, Doc, null);
+            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+            if (tagDoc) tagDoc.opacity = 1;
+            const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
+            const curInd: number = itemIndexes.indexOf(index);
+            if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; }
+            else {
+                if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) { }
+                else if (curDoc.presHideBefore) {
+                    if (index > this.itemIndex) {
+                        tagDoc.opacity = 0;
+                    } else if (!curDoc.presHideAfter) {
+                        tagDoc.opacity = 1;
+                    }
+                }
+                if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== (itemIndexes.length - 1)) { }
+                else if (curDoc.presHideAfter) {
+                    if (index < this.itemIndex) {
+                        tagDoc.opacity = 0;
+                    } else if (!curDoc.presHideBefore) {
+                        tagDoc.opacity = 1;
+                    }
+                }
+            }
+        });
+    }
+
+
+
+    //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
+    @action
+    startAutoPres = (startSlide: number) => {
+        this.updateCurrentPresentation();
+        let activeItem: Doc = this.activeItem;
+        let targetDoc: Doc = this.targetDoc;
+        let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
+        const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
+        const load = async () => { // Wrap the loop into an async function for this to work
+            for (var i = startSlide; i < this.childDocs.length; i++) {
+                activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+                targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+                duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
+                if (duration < 100) { duration = 2500; }
+                if (NumCast(targetDoc.lastFrame) > 0) {
+                    for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
+                        await timer(duration / NumCast(targetDoc.lastFrame));
+                        this.next();
+                    }
+                }
+
+                await timer(duration); this.next(); // then the created Promise can be awaited
+                if (i === this.childDocs.length - 1) {
+                    setTimeout(() => {
+                        clearTimeout(this._presTimer);
+                        if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = PresStatus.Manual;
+                        else if (this.layoutDoc.presLoop) this.startAutoPres(0);
+                    }, duration);
+                }
+            }
+        };
+        this.layoutDoc.presStatus = PresStatus.Autoplay;
+        this.startPresentation(startSlide);
+        this.gotoDocument(startSlide, activeItem);
+        load();
+    }
+
+    @action
+    pauseAutoPres = () => {
+        if (this.layoutDoc.presStatus === PresStatus.Autoplay) {
+            if (this._presTimer) clearTimeout(this._presTimer);
+            this.layoutDoc.presStatus = PresStatus.Manual;
+            this.layoutDoc.presLoop = false;
+            this.childDocs.forEach(this.stopTempMedia);
+        }
+    }
+
+    //The function that resets the presentation by removing every action done by it. It also
+    //stops the presentaton.
+    resetPresentation = () => {
+        this.rootDoc._itemIndex = 0;
+        this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)).filter(doc => doc instanceof Doc).forEach(doc => {
+            try {
+                doc.opacity = 1;
+            } catch (e) {
+                console.log("Reset presentation error: ", e);
+            }
+        });
+    }
+
+    @action togglePath = (srcContext: Doc, off?: boolean) => {
+        if (off) {
+            this._pathBoolean = false;
+            srcContext.presPathView = false;
+        } else {
+            runInAction(() => this._pathBoolean = !this._pathBoolean);
+            srcContext.presPathView = this._pathBoolean;
+        }
+    }
+
+    @action toggleExpandMode = () => {
+        runInAction(() => this._expandBoolean = !this._expandBoolean);
+        this.rootDoc.expandBoolean = this._expandBoolean;
+        this.childDocs.forEach((doc) => {
+            doc.presExpandInlineButton = this._expandBoolean;
+        });
+    }
+
+    /**
+     * The function that starts the presentation at the given index, also checking if actions should be applied
+     * directly at start.
+     * @param startIndex: index that the presentation will start at
+     */
+    startPresentation = (startIndex: number) => {
+        this.updateCurrentPresentation();
+        this.childDocs.map(doc => {
+            const tagDoc = doc.presentationTargetDoc as Doc;
+            if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) {
+                tagDoc.opacity = 0;
+            }
+            if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) {
+                tagDoc.opacity = 0;
+            }
+        });
+    }
+
+    /**
+     * The method called to open the presentation as a minimized view
+     */
+    @action
+    updateMinimize = () => {
+        const docView = DocumentManager.Instance.getDocumentView(this.layoutDoc);
+        if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+            console.log("case 1");
+            this.layoutDoc.presStatus = PresStatus.Edit;
+            Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
+            CollectionDockingView.AddSplit(this.rootDoc, "right");
+        } else if (this.layoutDoc.context && docView) {
+            console.log("case 2");
+            this.layoutDoc.presStatus = PresStatus.Edit;
+            clearTimeout(this._presTimer);
+            const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+            this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
+            this.rootDoc.y = pt[1] + 10;
+            this.rootDoc._height = 35;
+            this.rootDoc._width = 250;
+            docView.props.removeDocument?.(this.layoutDoc);
+            Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
+        } else {
+            console.log("case 3");
+            // TODO glr: fix this case
+        }
+    }
+
+    /**
+     * Called when the user changes the view type
+     * Either 'List' (stacking) or 'Slides' (carousel)
+     */
+    // @undoBatch
+    viewChanged = action((e: React.ChangeEvent) => {
+        //@ts-ignore
+        const viewType = e.target.selectedOptions[0].value as CollectionViewType;
+        // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
+        viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined);
+        this.rootDoc._viewType = viewType;
+        if (viewType === CollectionViewType.Stacking) this.layoutDoc._gridGap = 0;
+    });
+
+    /**
+     * Called when the user changes the view type
+     * Either 'List' (stacking) or 'Slides' (carousel)
+     */
+    // @undoBatch
+    mediaStopChanged = action((e: React.ChangeEvent) => {
+        const activeItem: Doc = this.activeItem;
+        //@ts-ignore
+        const stopDoc = e.target.selectedOptions[0].value as string;
+        const stopDocIndex: number = Number(stopDoc[0]);
+        activeItem.mediaStopDoc = stopDocIndex;
+        if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
+            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
+            list.push(activeItem);
+            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
+            console.log(list);
+        } else {
+            this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List<Doc>();
+            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
+            list.push(activeItem);
+            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
+            console.log(list);
+        }
+    });
+
+
+    setMovementName = action((movement: any, activeItem: Doc): string => {
+        let output: string = 'none';
+        switch (movement) {
+            case PresMovement.Zoom: output = 'Pan & Zoom'; break; //Pan and zoom
+            case PresMovement.Pan: output = 'Pan'; break; //Pan
+            case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut
+            case PresMovement.None: output = 'None'; break; //None
+            default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom
+        }
+        return output;
+    });
+
+    whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive));
+    // For dragging documents into the presentation trail
+    addDocumentFilter = (docs: Doc[]) => {
+        docs.forEach((doc, i) => {
+            if (doc.presentationTargetDoc) return true;
+            if (doc.type === DocumentType.LABEL) {
+                const audio = Cast(doc.annotationOn, Doc, null);
+                if (audio) {
+                    audio.mediaStart = "manual";
+                    audio.mediaStop = "manual";
+                    audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */));
+                    audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */));
+                    audio.presDuration = audio.presStartTime - audio.presEndTime;
+                    TabDocView.PinDoc(audio, { audioRange: true });
+                    setTimeout(() => this.removeDocument(doc), 0);
+                    return false;
+                }
+            } else {
+                if (!doc.aliasOf) {
+                    const original = Doc.MakeAlias(doc);
+                    TabDocView.PinDoc(original);
+                    setTimeout(() => this.removeDocument(doc), 0);
+                    return false;
+                } else {
+                    if (!doc.presentationTargetDoc) doc.title = doc.title + " - Slide";
+                    doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
+                    doc.presMovement = PresMovement.Zoom;
+                    if (this._expandBoolean) doc.presExpandInlineButton = true;
+                }
+            }
+        });
+        return true;
+    }
+    childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement;
+    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
+    getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
+    panelHeight = () => this.props.PanelHeight() - 40;
+    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
+        (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+
+    /**
+     * For sorting the array so that the order is maintained when it is dropped.
+     */
+    @action
+    sortArray = (): Doc[] => {
+        return this.childDocs.filter(doc => this._selectedArray.has(doc));
+    }
+
+    /**
+     * Method to get the list of selected items in the order in which they have been selected
+     */
+    @computed get listOfSelected() {
+        const list = Array.from(this._selectedArray.keys()).map((doc: Doc, index: any) => {
+            const curDoc = Cast(doc, Doc, null);
+            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+            if (curDoc && curDoc === this.activeItem) return <div key={index} className="selectedList-items"><b>{index + 1}.  {curDoc.title}</b></div>;
+            else if (tagDoc) return <div key={index} className="selectedList-items">{index + 1}.  {curDoc.title}</div>;
+            else if (curDoc) return <div key={index} className="selectedList-items">{index + 1}.  {curDoc.title}</div>;
+        });
+        return list;
+    }
+
+    @action
+    selectPres = () => {
+        const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
+        presDocView && SelectionManager.SelectView(presDocView, false);
+    }
+
+    //Regular click
+    @action
+    selectElement = async (doc: Doc) => {
+        const context = Cast(doc.context, Doc, null);
+        this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+        if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
+        else this.updateCurrentPresentation(context);
+
+        if (this.activeItem.setPosition &&
+            this.activeItem.y !== undefined &&
+            this.activeItem.x !== undefined &&
+            this.targetDoc.x !== undefined &&
+            this.targetDoc.y !== undefined) {
+            const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
+            const time = 10;
+            const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y);
+            const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x);
+
+            for (let i = 0; i < time; i++) {
+                this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time;
+                this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time;
+                await timer(0.1);
+            }
+        }
+    }
+
+    //Command click
+    @action
+    multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
+        if (!this._selectedArray.has(doc)) {
+            this._selectedArray.set(doc, undefined);
+            this._eleArray.push(ref);
+            this._dragArray.push(drag);
+        } else {
+            this._selectedArray.delete(doc);
+            this.removeFromArray(this._eleArray, doc);
+            this.removeFromArray(this._dragArray, doc);
+        }
+        this.selectPres();
+    }
+
+    removeFromArray = (arr: any[], val: any) => {
+        const index: number = arr.indexOf(val);
+        const ret: any[] = arr.splice(index, 1);
+        arr = ret;
+    }
+
+    //Shift click
+    @action
+    shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
+        this._selectedArray.clear();
+        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+        if (this.activeItem) {
+            for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
+                this._selectedArray.set(this.childDocs[i], undefined);
+                this._eleArray.push(ref);
+                this._dragArray.push(drag);
+            }
+        }
+        this.selectPres();
+    }
+
+    //regular click
+    @action
+    regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean) => {
+        this._selectedArray.clear();
+        this._selectedArray.set(doc, undefined);
+        this._eleArray.splice(0, this._eleArray.length, ref);
+        this._dragArray.splice(0, this._dragArray.length, drag);
+        focus && this.selectElement(doc);
+        this.selectPres();
+    }
+
+    modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => {
+        if (cmdClick) this.multiSelect(doc, ref, drag);
+        else if (shiftClick) this.shiftSelect(doc, ref, drag);
+        else this.regularSelect(doc, ref, drag, focus);
+    }
+
+    static keyEventsWrapper = (e: KeyboardEvent) => {
+        PresBox.Instance.keyEvents(e);
+    }
+
+    // Key for when the presentaiton is active
+    @action
+    keyEvents = (e: KeyboardEvent) => {
+        if (e.target instanceof HTMLInputElement) return;
+        let handled = false;
+        const anchorNode = document.activeElement as HTMLDivElement;
+        if (anchorNode && anchorNode.className?.includes("lm_title")) return;
+        switch (e.key) {
+            case "Backspace":
+                if (this.layoutDoc.presStatus === "edit") {
+                    undoBatch(action(() => {
+                        for (const doc of Array.from(this._selectedArray.keys())) {
+                            this.removeDocument(doc);
+                        }
+                        this._selectedArray.clear();
+                        this._eleArray.length = 0;
+                        this._dragArray.length = 0;
+                    }))();
+                    handled = true;
+                }
+                break;
+            case "Escape":
+                if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); }
+                else if (this.layoutDoc.presStatus === "edit") { this._selectedArray.clear(); this._eleArray.length = this._dragArray.length = 0; }
+                else this.layoutDoc.presStatus = "edit";
+                if (this._presTimer) clearTimeout(this._presTimer);
+                handled = true;
+                break;
+            case "Down": case "ArrowDown":
+            case "Right": case "ArrowRight":
+                if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) { // TODO: update to work properly
+                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1;
+                    this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
+                } else {
+                    this.next();
+                    if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; }
+                }
+                handled = true;
+                break;
+            case "Up": case "ArrowUp":
+            case "Left": case "ArrowLeft":
+                if (e.shiftKey && this.itemIndex !== 0) { // TODO: update to work properly
+                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1;
+                    this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
+                } else {
+                    this.back();
+                    if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; }
+                }
+                handled = true;
+                break;
+            case "Spacebar": case " ":
+                if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex);
+                else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer);
+                handled = true;
+                break;
+            case "a":
+                if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === "edit") {
+                    this._selectedArray.clear();
+                    this.childDocs.forEach(doc => this._selectedArray.set(doc, undefined));
+                    handled = true;
+                }
+            default:
+                break;
+        }
+        if (handled) {
+            e.stopPropagation();
+            e.preventDefault();
+        }
+    }
+
+    /**
+     * 
+     */
+    @action
+    viewPaths = () => {
+        const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
+        if (srcContext) {
+            this.togglePath(srcContext);
+        }
+    }
+
+    getAllIndexes = (arr: Doc[], val: Doc): number[] => {
+        const indexes = [];
+        for (let i = 0; i < arr.length; i++) {
+            arr[i] === val && indexes.push(i);
+        }
+        return indexes;
+    }
+
+    // Adds the index in the pres path graphically
+    @computed get order() {
+        const order: JSX.Element[] = [];
+        const docs: Doc[] = [];
+        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
+        const dv = DocumentManager.Instance.getDocumentView(presCollection);
+        this.childDocs.filter(doc => Cast(doc.presentationTargetDoc, Doc, null)).forEach((doc, index) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            const srcContext = Cast(tagDoc.context, Doc, null);
+            const width = NumCast(tagDoc._width) / 10;
+            const height = Math.max(NumCast(tagDoc._height) / 10, 15);
+            const edge = Math.max(width, height);
+            const fontSize = edge * 0.8;
+            const gap = 2;
+            if (presCollection === srcContext) {
+                // Case A: Document is contained within the collection
+                if (docs.includes(tagDoc)) {
+                    const prevOccurances: number = this.getAllIndexes(docs, tagDoc).length;
+                    docs.push(tagDoc);
+                    order.push(
+                        <div className="pathOrder"
+                            key={tagDoc.id + 'pres' + index}
+                            style={{ top: NumCast(tagDoc.y) + (prevOccurances * (edge + gap) - (edge / 2)), left: NumCast(tagDoc.x) - (edge / 2), width: edge, height: edge, fontSize: fontSize }}
+                            onClick={() => this.selectElement(doc)}>
+                            <div className="pathOrder-frame">{index + 1}</div>
+                        </div>);
+                } else {
+                    docs.push(tagDoc);
+                    order.push(
+                        <div className="pathOrder"
+                            key={tagDoc.id + 'pres' + index}
+                            style={{ top: NumCast(tagDoc.y) - (edge / 2), left: NumCast(tagDoc.x) - (edge / 2), width: edge, height: edge, fontSize: fontSize }}
+                            onClick={() => this.selectElement(doc)}>
+                            <div className="pathOrder-frame">{index + 1}</div>
+                        </div>);
+                }
+            } else if (doc.presPinView && presCollection === tagDoc && dv) {
+                // Case B: Document is presPinView and is presCollection
+                const scale: number = 1 / NumCast(doc.presPinViewScale);
+                const height: number = dv.props.PanelHeight() * scale;
+                const width: number = dv.props.PanelWidth() * scale;
+                const indWidth = width / 10;
+                const indHeight = Math.max(height / 10, 15);
+                const indEdge = Math.max(indWidth, indHeight);
+                const indFontSize = indEdge * 0.8;
+                const xLoc: number = NumCast(doc.presPinViewX) - (width / 2);
+                const yLoc: number = NumCast(doc.presPinViewY) - (height / 2);
+                docs.push(tagDoc);
+                order.push(
+                    <>
+                        <div className="pathOrder"
+                            key={tagDoc.id + 'pres' + index}
+                            style={{ top: yLoc - (indEdge / 2), left: xLoc - (indEdge / 2), width: indEdge, height: indEdge, fontSize: indFontSize }}
+                            onClick={() => this.selectElement(doc)}
+                        >
+                            <div className="pathOrder-frame">{index + 1}</div>
+                        </div>
+                        <div className="pathOrder-presPinView" style={{ top: yLoc, left: xLoc, width: width, height: height, borderWidth: indEdge / 10 }}></div>
+                    </>);
+            }
+        });
+        return order;
+    }
+
+    /**
+     * Method called for viewing paths which adds a single line with
+     * points at the center of each document added.
+     * Design choice: When this is called it sets _fitToBox as true so the
+     * user can have an overview of all of the documents in the collection.
+     * (Design needed for when documents in presentation trail are in another
+     * collection)
+     */
+    @computed get paths() {
+        let pathPoints = "";
+        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
+        this.childDocs.forEach((doc, index) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            const srcContext = Cast(tagDoc?.context, Doc, null);
+            if (tagDoc && presCollection === srcContext) {
+                const n1x = NumCast(tagDoc.x) + (NumCast(tagDoc._width) / 2);
+                const n1y = NumCast(tagDoc.y) + (NumCast(tagDoc._height) / 2);
+                if (index = 0) pathPoints = n1x + "," + n1y;
+                else pathPoints = pathPoints + " " + n1x + "," + n1y;
+            } else if (doc.presPinView && presCollection === tagDoc) {
+                const n1x = NumCast(doc.presPinViewX);
+                const n1y = NumCast(doc.presPinViewY);
+                if (index = 0) pathPoints = n1x + "," + n1y;
+                else pathPoints = pathPoints + " " + n1x + "," + n1y;
+            }
+        });
+        return (<polyline
+            points={pathPoints}
+            style={{
+                opacity: 1,
+                stroke: "#69a6db",
+                strokeWidth: 5,
+                strokeDasharray: '10 5',
+                boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
+            }}
+            fill="none"
+            markerStart="url(#markerArrow)"
+            markerMid="url(#markerSquare)"
+            markerEnd="url(#markerSquareFilled)"
+        />);
+    }
+
+    // Converts seconds to ms and updates presTransition
+    setTransitionTime = (number: String, change?: number) => {
+        let timeInMS = Number(number) * 1000;
+        if (change) timeInMS += change;
+        if (timeInMS < 100) timeInMS = 100;
+        if (timeInMS > 10000) timeInMS = 10000;
+        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presTransition = timeInMS);
+    }
+
+    // Converts seconds to ms and updates presDuration
+    setDurationTime = (number: String, change?: number) => {
+        let timeInMS = Number(number) * 1000;
+        if (change) timeInMS += change;
+        if (timeInMS < 100) timeInMS = 100;
+        if (timeInMS > 20000) timeInMS = 20000;
+        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presDuration = timeInMS);
+    }
+
+    /**
+     * When the movement dropdown is changes
+     */
+    @undoBatch
+    updateMovement = action((movement: any, all?: boolean) => {
+        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
+        array.forEach((doc) => {
+            switch (movement) {
+                case PresMovement.Zoom: //Pan and zoom
+                    doc.presMovement = PresMovement.Zoom;
+                    break;
+                case PresMovement.Pan: //Pan
+                    doc.presMovement = PresMovement.Pan;
+                    break;
+                case PresMovement.Jump: //Jump Cut
+                    doc.presJump = true;
+                    doc.presMovement = PresMovement.Jump;
+                    break;
+                case PresMovement.None: default:
+                    doc.presMovement = PresMovement.None;
+                    break;
+            }
+        });
+    });
+
+    @undoBatch
+    @action
+    updateHideBefore = (activeItem: Doc) => {
+        activeItem.presHideBefore = !activeItem.presHideBefore;
+        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideBefore = activeItem.presHideBefore);
+    }
+
+    @undoBatch
+    @action
+    updateHideAfter = (activeItem: Doc) => {
+        activeItem.presHideAfter = !activeItem.presHideAfter;
+        Array.from(this._selectedArray.keys()).forEach((doc) => doc.presHideAfter = activeItem.presHideAfter);
+    }
+
+    @undoBatch
+    @action
+    updateOpenDoc = (activeItem: Doc) => {
+        activeItem.openDocument = !activeItem.openDocument;
+        Array.from(this._selectedArray.keys()).forEach((doc) => {
+            doc.openDocument = activeItem.openDocument;
+        });
+    }
+
+    @undoBatch
+    @action
+    updateEffectDirection = (effect: any, all?: boolean) => {
+        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
+        array.forEach((doc) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            switch (effect) {
+                case PresEffect.Left:
+                    tagDoc.presEffectDirection = PresEffect.Left;
+                    break;
+                case PresEffect.Right:
+                    tagDoc.presEffectDirection = PresEffect.Right;
+                    break;
+                case PresEffect.Top:
+                    tagDoc.presEffectDirection = PresEffect.Top;
+                    break;
+                case PresEffect.Bottom:
+                    tagDoc.presEffectDirection = PresEffect.Bottom;
+                    break;
+                case PresEffect.Center: default:
+                    tagDoc.presEffectDirection = PresEffect.Center;
+                    break;
+            }
+        });
+    }
+
+    @undoBatch
+    @action
+    updateEffect = (effect: any, all?: boolean) => {
+        const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
+        array.forEach((doc) => {
+            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            switch (effect) {
+                case PresEffect.Bounce:
+                    tagDoc.presEffect = PresEffect.Bounce;
+                    break;
+                case PresEffect.Fade:
+                    tagDoc.presEffect = PresEffect.Fade;
+                    break;
+                case PresEffect.Flip:
+                    tagDoc.presEffect = PresEffect.Flip;
+                    break;
+                case PresEffect.Roll:
+                    tagDoc.presEffect = PresEffect.Roll;
+                    break;
+                case PresEffect.Rotate:
+                    tagDoc.presEffect = PresEffect.Rotate;
+                    break;
+                case PresEffect.None: default:
+                    tagDoc.presEffect = PresEffect.None;
+                    break;
+            }
+        });
+    }
+
+    _batch: UndoManager.Batch | undefined = undefined;
+
+    @computed get transitionDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const type = targetDoc.type;
+        const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection);
+        const isPinWithView: boolean = BoolCast(activeItem.presPinView);
+        if (activeItem && targetDoc) {
+            const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
+            let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
+            if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
+            const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
+            activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
+            return (
+                <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
+                    <div className="ribbon-box">
+                        Movement
+                        {isPresCollection || (isPresCollection && isPinWithView) ?
+                            <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
+                                {this.scrollable ? "Scroll to pinned view" : !isPinWithView ? "No movement" : "Pan & Zoom to pinned view"}
+                            </div>
+                            :
+                            <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+                                {this.setMovementName(activeItem.presMovement, activeItem)}
+                                <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={"angle-down"} />
+                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
+                                    <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
+                                </div>
+                            </div>
+                        }
+                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "inline-flex" : "none" }}>
+                            <div className="presBox-subheading">Movement Speed</div>
+                            <div className="ribbon-property">
+                                <input className="presBox-input"
+                                    type="number" value={transitionSpeed}
+                                    onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
+                            </div>
+                            <div className="ribbon-propertyUpDown">
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
+                                    <FontAwesomeIcon icon={"caret-up"} />
+                                </div>
+                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
+                                    <FontAwesomeIcon icon={"caret-down"} />
+                                </div>
+                            </div>
+                        </div>
+                        <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed}
+                            className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}
+                            id="toolbar-slider"
+                            onPointerDown={() => this._batch = UndoManager.StartBatch("presTransition")}
+                            onPointerUp={() => this._batch?.end()}
+                            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                e.stopPropagation();
+                                this.setTransitionTime(e.target.value);
+                            }} />
+                        <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                            <div className="slider-text">Fast</div>
+                            <div className="slider-text">Medium</div>
+                            <div className="slider-text">Slow</div>
+                        </div>
+                    </div>
+                    <div className="ribbon-box">
+                        Visibility {"&"} Duration
+                        <div className="ribbon-doubleButton">
+                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideBefore ? "active" : ""}`} onClick={() => this.updateHideBefore(activeItem)}>Hide before</div></Tooltip>}
+                            {isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfter ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>}
+                            <Tooltip title={<><div className="dash-tooltip">{"Open in lightbox view"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? Colors.LIGHT_BLUE : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Lightbox</div></Tooltip>
+                        </div>
+                        {(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) : <>
+                            <div className="ribbon-doubleButton" >
+                                <div className="presBox-subheading">Slide Duration</div>
+                                <div className="ribbon-property">
+                                    <input className="presBox-input"
+                                        type="number" value={duration}
+                                        onChange={action((e) => this.setDurationTime(e.target.value))} /> s
+                            </div>
+                                <div className="ribbon-propertyUpDown">
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
+                                        <FontAwesomeIcon icon={"caret-up"} />
+                                    </div>
+                                    <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
+                                        <FontAwesomeIcon icon={"caret-down"} />
+                                    </div>
+                                </div>
+                            </div>
+                            <input type="range" step="0.1" min="0.1" max="20" value={duration}
+                                style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }}
+                                className={"toolbar-slider"} id="duration-slider"
+                                onPointerDown={() => { this._batch = UndoManager.StartBatch("presDuration"); }}
+                                onPointerUp={() => { if (this._batch) this._batch.end(); }}
+                                onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }}
+                            />
+                            <div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "grid" }}>
+                                <div className="slider-text">Short</div>
+                                <div className="slider-text">Medium</div>
+                                <div className="slider-text">Long</div>
+                            </div>
+                        </>}
+                    </div>
+                    {isPresCollection ? (null) : <div className="ribbon-box">
+                        Effects
+                        <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+                            {effect}
+                            <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={"angle-down"} />
+                            <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.None || !targetDoc.presEffect ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Fade ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Flip ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Rotate ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Bounce ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce</div>
+                                <div className={`presBox-dropdownOption ${targetDoc.presEffect === PresEffect.Roll ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll</div>
+                            </div>
+                        </div>
+                        <div className="ribbon-doubleButton" style={{ display: effect === 'None' ? "none" : "inline-flex" }}>
+                            <div className="presBox-subheading" >Effect direction</div>
+                            <div className="ribbon-property">
+                                {this.effectDirection}
+                            </div>
+                        </div>
+                        <div className="effectDirection" style={{ display: effect === 'None' ? "none" : "grid", width: 40 }}>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Left ? Colors.LIGHT_BLUE : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Left)}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Right ? Colors.LIGHT_BLUE : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Right)}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Top ? Colors.LIGHT_BLUE : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Top)}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === PresEffect.Bottom ? Colors.LIGHT_BLUE : "black", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Bottom)}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection === PresEffect.Center || !targetDoc.presEffectDirection ? `solid 2px ${Colors.LIGHT_BLUE}` : "solid 2px black", borderRadius: "100%", cursor: "pointer" }} onClick={() => this.updateEffectDirection(PresEffect.Center)}></div></Tooltip>
+                        </div>
+                    </div>}
+                    <div className="ribbon-final-box">
+                        <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
+                            Apply to all
+                        </div>
+                    </div>
+                </div >
+            );
+        }
+    }
+
+    @computed get effectDirection(): string {
+        let effect = '';
+        switch (this.targetDoc.presEffectDirection) {
+            case 'left': effect = "Enter from left"; break;
+            case 'right': effect = "Enter from right"; break;
+            case 'top': effect = "Enter from top"; break;
+            case 'bottom': effect = "Enter from bottom"; break;
+            default: effect = "Enter from center"; break;
+        }
+        return effect;
+    }
+
+    @undoBatch
+    @action
+    applyTo = (array: Doc[]) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        this.updateMovement(activeItem.presMovement, true);
+        this.updateEffect(targetDoc.presEffect, true);
+        this.updateEffectDirection(targetDoc.presEffectDirection, true);
+        array.forEach((doc) => {
+            const curDoc = Cast(doc, Doc, null);
+            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+            if (tagDoc && targetDoc) {
+                curDoc.presTransition = activeItem.presTransition;
+                curDoc.presDuration = activeItem.presDuration;
+                curDoc.presHideBefore = activeItem.presHideBefore;
+                curDoc.presHideAfter = activeItem.presHideAfter;
+            }
+        });
+    }
+
+    @computed get presPinViewOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 16, filter: 'invert(1)' }} />;
+        return (
+            <>
+                {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
+                <div className="ribbon-doubleButton">
+                    <Tooltip title={<><div className="dash-tooltip">{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}</div></>}><div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? Colors.LIGHT_BLUE : "" }}
+                        onClick={() => {
+                            activeItem.presPinView = !activeItem.presPinView;
+                            targetDoc.presPinView = activeItem.presPinView;
+                            if (activeItem.presPinView) {
+                                if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+                                    const scroll = targetDoc._scrollTop;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewScroll = scroll;
+                                } else if (targetDoc.type === DocumentType.VID) {
+                                    activeItem.presPinTimecode = targetDoc._currentTimecode;
+                                } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
+                                    const x = targetDoc._panX;
+                                    const y = targetDoc._panY;
+                                    const scale = targetDoc._viewScale;
+                                    activeItem.presPinView = true;
+                                    activeItem.presPinViewX = x;
+                                    activeItem.presPinViewY = y;
+                                    activeItem.presPinViewScale = scale;
+                                } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                    const width = targetDoc._clipWidth;
+                                    activeItem.presPinClipWidth = width;
+                                    activeItem.presPinView = true;
+                                }
+                            }
+                        }}>{presPinWithViewIcon}</div></Tooltip>
+                    {activeItem.presPinView ? <Tooltip title={<><div className="dash-tooltip">{"Update the pinned view with the view of the selected document"}</div></>}><div className="ribbon-button"
+                        onClick={() => {
+                            if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+                                const scroll = targetDoc._scrollTop;
+                                activeItem.presPinViewScroll = scroll;
+                            } else if (targetDoc.type === DocumentType.VID) {
+                                activeItem.presPinTimecode = targetDoc._currentTimecode;
+                            } else if (targetDoc.type === DocumentType.COMPARISON) {
+                                const clipWidth = targetDoc._clipWidth;
+                                activeItem.presPinClipWidth = clipWidth;
+                            } else {
+                                const x = targetDoc._panX;
+                                const y = targetDoc._panY;
+                                const scale = targetDoc._viewScale;
+                                activeItem.presPinViewX = x;
+                                activeItem.presPinViewY = y;
+                                activeItem.presPinViewScale = scale;
+                            }
+                        }}>Update</div></Tooltip> : (null)}
+                </div>
+            </>
+        );
+    }
+
+    @computed get panOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.panable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan X</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewX)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Pan Y</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewY)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+                        </div>
+                    </div>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scale</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScale)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+
+    @computed get scrollOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.scrollable ? <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+                    <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                        <div className="presBox-subheading">Scroll</div>
+                        <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                            <input className="presBox-input"
+                                style={{ textAlign: 'left', width: 50 }}
+                                type="number" value={NumCast(activeItem.presPinViewScroll)}
+                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
+                        </div>
+                    </div>
+                </div> : (null)}
+            </>
+        );
+    }
+
+    @computed get mediaStopSlides() {
+        const activeItem: Doc = this.activeItem;
+        const list = this.childDocs.map((doc, i) => {
+            if (i > this.itemIndex) {
+                return (
+                    <option>{i + 1}. {doc.title}</option>
+                );
+            }
+        });
+        return (
+            list
+        );
+    }
+
+    @computed get mediaOptionsDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10);
+        const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
+        const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + ". " + this.childDocs[mediaStopDocInd - 1].title : "";
+        if (activeItem && targetDoc) {
+            return (
+                <div>
+                    <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                        <div>
+                            <div className="ribbon-box">
+                                Start {"&"} End Time
+                                <div className={"slider-headers"}>
+                                    <div className="slider-block" >
+                                        <div className="slider-text" style={{ fontWeight: 500 }}>
+                                            Start time (s)
+                                        </div>
+                                        <div id={"startTime"} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
+                                            <input className="presBox-input"
+                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+                                                type="number" value={NumCast(activeItem.presStartTime)}
+                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })}
+                                            />
+                                        </div>
+                                    </div>
+                                    <div className="slider-block">
+                                        <div className="slider-text" style={{ fontWeight: 500 }}>
+                                            Duration (s)
+                                        </div>
+                                        <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}>
+                                            {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10}
+                                        </div>
+                                    </div>
+                                    <div className="slider-block">
+                                        <div className="slider-text" style={{ fontWeight: 500 }}>
+                                            End time (s)
+                                        </div>
+                                        <div id={"endTime"} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
+                                            <input className="presBox-input"
+                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+                                                type="number" value={NumCast(activeItem.presEndTime)}
+                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presEndTime = Number(e.target.value); })}
+                                            />
+                                        </div>
+                                    </div>
+                                </div>
+                                <div className="multiThumb-slider">
+                                    <input type="range" step="0.1" min="0" max={duration / 10} value={NumCast(activeItem.presEndTime)}
+                                        style={{ gridColumn: 1, gridRow: 1 }}
+                                        className={`toolbar-slider ${"end"}`}
+                                        id="toolbar-slider"
+                                        onPointerDown={() => {
+                                            this._batch = UndoManager.StartBatch("presEndTime");
+                                            const endBlock = document.getElementById("endTime");
+                                            if (endBlock) {
+                                                endBlock.style.color = Colors.LIGHT_GRAY;
+                                                endBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
+                                            }
+                                        }}
+                                        onPointerUp={() => {
+                                            this._batch?.end();
+                                            const endBlock = document.getElementById("endTime");
+                                            if (endBlock) {
+                                                endBlock.style.color = Colors.BLACK;
+                                                endBlock.style.backgroundColor = Colors.LIGHT_GRAY;
+                                            }
+                                        }}
+                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                            e.stopPropagation();
+                                            activeItem.presEndTime = Number(e.target.value);
+                                        }} />
+                                    <input type="range" step="0.1" min="0" max={duration / 10} value={NumCast(activeItem.presStartTime)}
+                                        style={{ gridColumn: 1, gridRow: 1 }}
+                                        className={`toolbar-slider ${"start"}`}
+                                        id="toolbar-slider"
+                                        onPointerDown={() => {
+                                            this._batch = UndoManager.StartBatch("presStartTime");
+                                            const startBlock = document.getElementById("startTime");
+                                            if (startBlock) {
+                                                startBlock.style.color = Colors.LIGHT_GRAY;
+                                                startBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
+                                            }
+                                        }}
+                                        onPointerUp={() => {
+                                            this._batch?.end();
+                                            const startBlock = document.getElementById("startTime");
+                                            if (startBlock) {
+                                                startBlock.style.color = Colors.BLACK;
+                                                startBlock.style.backgroundColor = Colors.LIGHT_GRAY;
+                                            }
+                                        }}
+                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                                            e.stopPropagation();
+                                            activeItem.presStartTime = Number(e.target.value);
+                                        }} />
+                                </div>
+                                <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
+                                    <div className="slider-text">0 s</div>
+                                    <div className="slider-text"></div>
+                                    <div className="slider-text">{duration / 10} s</div>
+                                </div>
+                            </div>
+                            <div className="ribbon-final-box">
+                                Playback
+                                <div className="presBox-subheading">Start playing:</div>
+                                <div className="presBox-radioButtons">
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStart = "manual"}
+                                            checked={activeItem.mediaStart === "manual"}
+                                        />
+                                        <div>On click</div>
+                                    </div>
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStart = "auto"}
+                                            checked={activeItem.mediaStart === "auto"}
+                                        />
+                                        <div>Automatically</div>
+                                    </div>
+                                </div>
+                                <div className="presBox-subheading">Stop playing:</div>
+                                <div className="presBox-radioButtons">
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStop = "manual"}
+                                            checked={activeItem.mediaStop === "manual"}
+                                        />
+                                        <div>At audio end time</div>
+                                    </div>
+                                    <div className="checkbox-container">
+                                        <input className="presBox-checkbox"
+                                            type="checkbox"
+                                            onChange={() => activeItem.mediaStop = "auto"}
+                                            checked={activeItem.mediaStop === "auto"}
+                                        />
+                                        <div>On slide change</div>
+                                    </div>
+                                    {/* <div className="checkbox-container">
+                                    <input className="presBox-checkbox"
+                                        type="checkbox"
+                                        onChange={() => activeItem.mediaStop = "afterSlide"}
+                                        checked={activeItem.mediaStop === "afterSlide"}
+                                    />
+                                    <div className="checkbox-dropdown">
+                                        After chosen slide
+                                        <select className="presBox-viewPicker"
+                                            style={{ opacity: activeItem.mediaStop === "afterSlide" && this.itemIndex !== this.childDocs.length - 1 ? 1 : 0.3 }}
+                                            onPointerDown={e => e.stopPropagation()}
+                                            onChange={this.mediaStopChanged}
+                                            value={mediaStopDocStr}>
+                                            {this.mediaStopSlides}
+                                        </select>
+                                    </div>
+                                </div> */}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div >
+            );
+        }
+    }
+
+    @computed get newDocumentToolbarDropdown() {
+        return (
+            <div>
+                <div className={'presBox-toolbar-dropdown'} style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                    <div className="layout-container" style={{ height: 'max-content' }}>
+                        <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => { this.layout = 'blank'; this.createNewSlide(this.layout); })} />
+                        <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => { this.layout = 'title'; this.createNewSlide(this.layout); })}>
+                            <div className="title">Title</div>
+                            <div className="subtitle">Subtitle</div>
+                        </div>
+                        <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => { this.layout = 'header'; this.createNewSlide(this.layout); })}>
+                            <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
+                        </div>
+                        <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => { this.layout = 'content'; this.createNewSlide(this.layout); })}>
+                            <div className="title" style={{ alignSelf: 'center' }}>Title</div>
+                            <div className="content">Text goes here</div>
+                        </div>
+                    </div>
+                </div>
+            </div >
+        );
+    }
+
+    @observable openLayouts: boolean = false;
+    @observable addFreeform: boolean = true;
+    @observable layout: string = "";
+    @observable title: string = "";
+
+    @computed get newDocumentDropdown() {
+        return (
+            <div>
+                <div className={"presBox-ribbon"} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                    <div className="ribbon-box">
+                        Slide Title: <br></br>
+                        <input className="ribbon-textInput" placeholder="..." type="text" name="fname"
+                            onChange={(e) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                runInAction(() => this.title = e.target.value);
+                            }}>
+                        </input>
+                    </div>
+                    <div className="ribbon-box">
+                        Choose type:
+                        <div className="ribbon-doubleButton">
+                            <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? "" : Colors.LIGHT_BLUE }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Text</div>
+                            <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : "" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Freeform</div>
+                        </div>
+                    </div>
+                    <div className="ribbon-box" style={{ display: this.addFreeform ? "grid" : "none" }}>
+                        Preset layouts:
+                        <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
+                            <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => this.layout = 'blank')} />
+                            <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => this.layout = 'title')}>
+                                <div className="title">Title</div>
+                                <div className="subtitle">Subtitle</div>
+                            </div>
+                            <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => this.layout = 'header')}>
+                                <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>Section header</div>
+                            </div>
+                            <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => this.layout = 'content')}>
+                                <div className="title" style={{ alignSelf: 'center' }}>Title</div>
+                                <div className="content">Text goes here</div>
+                            </div>
+                            <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => this.layout = 'twoColumns')}>
+                                <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>Title</div>
+                                <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>Column one text</div>
+                                <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>Column two text</div>
+                            </div>
+                        </div>
+                        <div className="open-layout" onClick={action(() => this.openLayouts = !this.openLayouts)}>
+                            <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"caret-down"} size={"lg"} />
+                        </div>
+                    </div>
+                    <div className="ribbon-final-box">
+                        <div className={this.title !== "" && (this.addFreeform && this.layout !== "" || !this.addFreeform) ? "ribbon-final-button-hidden" : "ribbon-final-button"} onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
+                            Create New Slide
+                        </div>
+                    </div>
+                </div>
+            </div >
+        );
+    }
+
+    createNewSlide = (layout?: string, title?: string, freeform?: boolean) => {
+        let doc = undefined;
+        if (layout) doc = this.createTemplate(layout);
+        if (freeform && layout) doc = this.createTemplate(layout, title);
+        if (!freeform && !layout) doc = Docs.Create.TextDocument("", { _nativeWidth: 400, _width: 225, title: title });
+        if (doc) {
+            const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
+            const data = Cast(presCollection?.data, listSpec(Doc));
+            const presData = Cast(this.rootDoc.data, listSpec(Doc));
+            if (data && presData) {
+                data.push(doc);
+                TabDocView.PinDoc(doc);
+                this.gotoDocument(this.childDocs.length, this.activeItem);
+            } else {
+                this.props.addDocTab(doc, "add:right");
+            }
+        }
+    }
+
+    createTemplate = (layout: string, input?: string) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        let x = 0;
+        let y = 0;
+        if (activeItem && targetDoc) {
+            x = NumCast(targetDoc.x);
+            y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20;
+        }
+        let doc = undefined;
+        const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24pt", });
+        const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16pt" });
+        const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20pt" });
+        const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24pt" });
+        const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14pt" });
+        const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14pt" });
+        const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" });
+        switch (layout) {
+            case 'blank':
+                doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y });
+                break;
+            case 'title':
+                doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : "Title slide", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
+                break;
+            case 'header':
+                doc = Docs.Create.FreeformDocument([header], { title: input ? input : "Section header", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
+                break;
+            case 'content':
+                doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : "Title and content", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
+                break;
+            case 'twoColumns':
+                doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : "Title and two columns", _width: 400, _height: 225, _fitToBox: true, x: x, y: y });
+                break;
+            default:
+                break;
+        }
+        return doc;
+    }
+
+    // Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
+    @computed get presentDropdown() {
+        return (
+            <div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.updateMinimize(); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}>
+                    Mini-player
+                </div>
+                <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }))}>
+                    Sidebar player
+                </div>
+            </div>
+        );
+    }
+
+    // Case in which the document has keyframes to navigate to next key frame
+    @action
+    nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
+        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
+        const currentFrame = Cast(tagDoc._currentFrame, "number", null);
+        if (currentFrame === undefined) {
+            tagDoc._currentFrame = 0;
+            // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
+            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
+        }
+        // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
+        CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
+        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1);
+        tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
+    }
+
+    @action
+    prevKeyframe = (tagDoc: Doc, actItem: Doc): void => {
+        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
+        const currentFrame = Cast(tagDoc._currentFrame, "number", null);
+        if (currentFrame === undefined) {
+            tagDoc._currentFrame = 0;
+            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
+        }
+        CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
+        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1);
+    }
+
+    /**
+     * Returns the collection type as a string for headers
+     */
+    @computed get stringType(): string {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        let type: string = '';
+        if (activeItem) {
+            switch (targetDoc.type) {
+                case DocumentType.PDF: type = "PDF"; break;
+                case DocumentType.RTF: type = "Text node"; break;
+                case DocumentType.COL: type = "Collection"; break;
+                case DocumentType.AUDIO: type = "Audio"; break;
+                case DocumentType.VID: type = "Video"; break;
+                case DocumentType.IMG: type = "Image"; break;
+                case DocumentType.WEB: type = "Web page"; break;
+                default: type = "Other node"; break;
+            }
+        }
+        return type;
+    }
+
+    @observable private openActiveColorPicker: boolean = false;
+    @observable private openViewedColorPicker: boolean = false;
+
+
+
+    @computed get progressivizeDropdown() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        if (activeItem && targetDoc) {
+            const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black";
+            const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black";
+            return (
+                <div>
+                    <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+                        <div className="ribbon-box">
+                            {this.stringType} selected
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.progressivizeChild}>Contents</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.editProgressivize}>Edit</div>
+                            </div>
+                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
+                                <div className="presBox-subheading">Active text color</div>
+                                <div className="ribbon-colorBox" style={{ backgroundColor: activeFontColor, height: 15, width: 15 }} onClick={action(() => { this.openActiveColorPicker = !this.openActiveColorPicker; })}>
+                                </div>
+                            </div>
+                            {this.activeColorPicker}
+                            <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
+                                <div className="presBox-subheading">Viewed font color</div>
+                                <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}>
+                                </div>
+                            </div>
+                            {this.viewedColorPicker}
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.progressivizeZoom}>Zoom</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.editZoomProgressivize}>Edit</div>
+                            </div>
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.progressivizeScroll}>Scroll</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : "" }} onClick={this.editScrollProgressivize}>Edit</div>
+                            </div>
+                        </div>
+                        <div className="ribbon-final-box">
+                            Frames
+                            <div className="ribbon-doubleButton">
+                                <div className="ribbon-frameSelector">
+                                    <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc, activeItem); }}>
+                                        <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
+                                    </div>
+                                    <div key="num" title="toggle view all" className="numKeyframe" style={{ color: targetDoc.keyFrameEditing ? "white" : "black", backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
+                                        onClick={action(() => targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing)} >
+                                        {NumCast(targetDoc._currentFrame)}
+                                    </div>
+                                    <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={e => { e.stopPropagation(); this.nextKeyframe(targetDoc, activeItem); }}>
+                                        <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
+                                    </div>
+                                </div>
+                                <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
+                            </div>
+                            <div className="ribbon-frameList">
+                                {this.frameListHeader}
+                                {this.frameList}
+                            </div>
+                            <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(" TODO: play frames")}>Play</div>
+                        </div>
+                    </div>
+                </div>
+            );
+        }
+    }
+
+    @undoBatch
+    @action
+    switchActive = (color: ColorState) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const val = String(color.hex);
+        targetDoc["pres-text-color"] = val;
+        return true;
+    }
+    @undoBatch
+    @action
+    switchPresented = (color: ColorState) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const val = String(color.hex);
+        targetDoc["pres-text-viewed-color"] = val;
+        return true;
+    }
+
+    @computed get activeColorPicker() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return !this.openActiveColorPicker ? (null) : <SketchPicker onChange={this.switchActive}
+            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+                '#FFFFFF', '#f1efeb', 'transparent']}
+            color={StrCast(targetDoc["pres-text-color"])} />;
+    }
+
+    @computed get viewedColorPicker() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        return !this.openViewedColorPicker ? (null) : <SketchPicker onChange={this.switchPresented}
+            presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+                '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+                '#FFFFFF', '#f1efeb', 'transparent']}
+            color={StrCast(targetDoc["pres-text-viewed-color"])} />;
+    }
+
+    @action
+    turnOffEdit = (paths?: boolean) => {
+        // Turn off paths
+        if (paths) {
+            const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
+            if (srcContext) this.togglePath(srcContext, true);
+        }
+        // Turn off the progressivize editors for each document
+        this.childDocs.forEach((doc) => {
+            doc.editSnapZoomProgressivize = false;
+            doc.editZoomProgressivize = false;
+            const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
+            if (targetDoc) {
+                targetDoc.editZoomProgressivize = false;
+                // targetDoc.editScrollProgressivize = false;
+            }
+        });
+    }
+
+    //Toggle whether the user edits or not
+    @action
+    editZoomProgressivize = (e: React.MouseEvent) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        if (!targetDoc.editZoomProgressivize) {
+            if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; targetDoc.zoomProgressivize = true;
+            targetDoc.editZoomProgressivize = true;
+            activeItem.editZoomProgressivize = true;
+        } else {
+            targetDoc.editZoomProgressivize = false;
+            activeItem.editZoomProgressivize = false;
+        }
+    }
+
+    //Toggle whether the user edits or not
+    @action
+    editScrollProgressivize = (e: React.MouseEvent) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        if (!targetDoc.editScrollProgressivize) {
+            if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; activeItem.scrollProgressivize = true; }
+            targetDoc.editScrollProgressivize = true;
+        } else {
+            targetDoc.editScrollProgressivize = false;
+        }
+    }
+
+    //Progressivize Zoom
+    @action
+    progressivizeScroll = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        const activeItem: Doc = this.activeItem;
+        activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
+        const targetDoc: Doc = this.targetDoc;
+        targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
+        // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame));
+        if (targetDoc.editScrollProgressivize) {
+            targetDoc.editScrollProgressivize = false;
+            targetDoc._currentFrame = 0;
+            targetDoc.lastFrame = 0;
+        }
+    }
+
+    //Progressivize Zoom
+    @action
+    progressivizeZoom = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        const activeItem: Doc = this.activeItem;
+        activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
+        const targetDoc: Doc = this.targetDoc;
+        targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
+        CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc);
+        if (activeItem.editZoomProgressivize) {
+            activeItem.editZoomProgressivize = false;
+            targetDoc._currentFrame = 0;
+            targetDoc.lastFrame = 0;
+        }
+    }
+
+    //Progressivize Child Docs
+    @action
+    editProgressivize = (e: React.MouseEvent) => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        targetDoc._currentFrame = targetDoc.lastFrame;
+        if (!targetDoc.editProgressivize) {
+            if (!activeItem.presProgressivize) { activeItem.presProgressivize = true; targetDoc.presProgressivize = true; }
+            targetDoc.editProgressivize = true;
+        } else {
+            targetDoc.editProgressivize = false;
+        }
+    }
+
+    @action
+    progressivizeChild = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+        if (!activeItem.presProgressivize) {
+            targetDoc.keyFrameEditing = false;
+            activeItem.presProgressivize = true;
+            targetDoc.presProgressivize = true;
+            targetDoc._currentFrame = 0;
+            docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
+            targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1;
+        } else {
+            // targetDoc.editProgressivize = false;
+            activeItem.presProgressivize = false;
+            targetDoc.presProgressivize = false;
+            targetDoc._currentFrame = 0;
+            targetDoc.keyFrameEditing = true;
+        }
+    }
+
+    @action
+    checkMovementLists = (doc: Doc, xlist: any, ylist: any) => {
+        const x: List<number> = xlist;
+        const y: List<number> = ylist;
+        const tags: JSX.Element[] = [];
+        let pathPoints = ""; //List of all of the pathpoints that need to be added
+        for (let i = 0; i < x.length - 1; i++) {
+            if (y[i] || x[i]) {
+                if (i === 0) pathPoints = (x[i] - 11) + "," + (y[i] + 33);
+                else pathPoints = pathPoints + " " + (x[i] - 11) + "," + (y[i] + 33);
+                tags.push(<div className="progressivizeMove-frame" style={{ position: 'absolute', top: y[i], left: x[i] }}>{i}</div>);
+            }
+        }
+        tags.push(<svg style={{ overflow: 'visible', position: 'absolute' }}><polyline
+            points={pathPoints}
+            style={{
+                position: 'absolute',
+                opacity: 1,
+                stroke: "#000000",
+                strokeWidth: 2,
+                strokeDasharray: '10 5',
+            }}
+            fill="none"
+        /></svg>);
+        return tags;
+    }
+
+    @observable
+    toggleDisplayMovement = (doc: Doc) => {
+        if (doc.displayMovement) doc.displayMovement = false;
+        else doc.displayMovement = true;
+    }
+
+    @action
+    checkList = (doc: Doc, list: any): number => {
+        const x: List<number> = list;
+        if (x && x.length >= NumCast(doc._currentFrame) + 1) {
+            return x[NumCast(doc._currentFrame)];
+        } else if (x) {
+            x.length = NumCast(doc._currentFrame) + 1;
+            x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1];
+            return x[NumCast(doc._currentFrame)];
+        } else return 100;
+    }
+
+    @computed get progressivizeChildDocs() {
+        const targetDoc: Doc = this.targetDoc;
+        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+        const tags: JSX.Element[] = [];
+        docs.forEach((doc, index) => {
+            if (doc["x-indexed"] && doc["y-indexed"]) {
+                tags.push(<div style={{ position: 'absolute', display: doc.displayMovement ? "block" : "none" }}>{this.checkMovementLists(doc, doc["x-indexed"], doc["y-indexed"])}</div>);
+            }
+            tags.push(
+                <div className="progressivizeButton" key={index} onPointerLeave={() => { if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; }} onPointerOver={() => { if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; }} onClick={e => { this.toggleDisplayMovement(doc); e.stopPropagation(); }} style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : "#c8c8c8", top: NumCast(doc.y), left: NumCast(doc.x) }}>
+                    <div className="progressivizeButton-prev"><FontAwesomeIcon icon={"caret-left"} size={"lg"} onClick={e => { e.stopPropagation(); this.prevAppearFrame(doc, index); }} /></div>
+                    <div className="progressivizeButton-frame">{doc.appearFrame}</div>
+                    <div className="progressivizeButton-next"><FontAwesomeIcon icon={"caret-right"} size={"lg"} onClick={e => { e.stopPropagation(); this.nextAppearFrame(doc, index); }} /></div>
+                </div>);
+        });
+        return tags;
+    }
+
+    @action
+    nextAppearFrame = (doc: Doc, i: number): void => {
+        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+        // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+        const appearFrame = Cast(doc.appearFrame, "number", null);
+        if (appearFrame === undefined) {
+            doc.appearFrame = 0;
+        }
+        doc.appearFrame = appearFrame + 1;
+        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
+    }
+
+    @action
+    prevAppearFrame = (doc: Doc, i: number): void => {
+        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+        // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+        const appearFrame = Cast(doc.appearFrame, "number", null);
+        if (appearFrame === undefined) {
+            doc.appearFrame = 0;
+        }
+        doc.appearFrame = Math.max(0, appearFrame - 1);
+        this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
+    }
+
+    @action
+    updateOpacityList = (list: any, frame: number) => {
+        const x: List<number> = list;
+        if (x && x.length >= frame) {
+            for (let i = 0; i < x.length; i++) {
+                if (i < frame) {
+                    x[i] = 0;
+                } else if (i >= frame) {
+                    x[i] = 1;
+                }
+            }
+            list = x;
+        } else {
+            x.length = frame + 1;
+            for (let i = 0; i < x.length; i++) {
+                if (i < frame) {
+                    x[i] = 0;
+                } else if (i >= frame) {
+                    x[i] = 1;
+                }
+            }
+            list = x;
+        }
+    }
+
+    @computed get moreInfoDropdown() {
+        return (<div></div>);
+    }
+
+    @computed
+    get toolbarWidth(): number {
+        const width = this.props.PanelWidth();
+        return width;
+    }
+
+    @action
+    toggleProperties = () => {
+        if (CurrentUserUtils.propertiesWidth > 0) {
+            CurrentUserUtils.propertiesWidth = 0;
+        } else {
+            CurrentUserUtils.propertiesWidth = 250;
+        }
+    }
+
+    @computed get toolbar() {
+        const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
+        const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel";
+        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
+        const isMini: boolean = this.toolbarWidth <= 100;
+        const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
+        const activeColor = Colors.LIGHT_BLUE;
+        const inactiveColor = Colors.WHITE;
+        return (mode === CollectionViewType.Carousel3D) ? (null) : (
+            <div id="toolbarContainer" className={'presBox-toolbar'}>
+                {/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
+                    <FontAwesomeIcon icon={"plus"} />
+                    <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
+                </div></Tooltip> */}
+                <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}>
+                    <div style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
+                        <FontAwesomeIcon icon={"exchange-alt"} />
+                    </div>
+                </Tooltip>
+                {isMini ? (null) :
+                    <>
+                        <div className="toolbar-divider" />
+                        {/* <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
+                            <div className={"toolbar-button"}
+                                style={{ color: this._expandBoolean ? Colors.MEDIUM_BLUE : 'white' }}
+                                onClick={this.toggleExpandMode}>
+                                <FontAwesomeIcon icon={"eye"} />
+                            </div>
+                        </Tooltip>
+                        <div className="toolbar-divider" /> */}
+                        <Tooltip title={<><div className="dash-tooltip">{presKeyEvents ? "Keys are active" : "Keys are not active - click anywhere on the presentation trail to activate keys"}</div></>}>
+                            <div className="toolbar-button" style={{ cursor: presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
+                                <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"keyboard"} style={{ color: presKeyEvents ? activeColor : inactiveColor }} />
+                            </div>
+                        </Tooltip>
+                        <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}>
+                            <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
+                                <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? activeColor : inactiveColor }} />
+                            </div>
+                        </Tooltip>
+                    </>
+                }
+            </div>
+        );
+    }
+
+    /**
+     * Top panel containes:
+     * viewPicker: The option to choose between List and Slides view for the presentaiton trail
+     * presentPanel: The button to start the presentation / open minimized view of the presentation
+     */
+    @computed get topPanel() {
+        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
+        const isMini: boolean = this.toolbarWidth <= 100;
+        return (
+            <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? "none" : undefined }}>
+                {isMini ? (null) : <select className="presBox-viewPicker"
+                    style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}
+                    onPointerDown={e => e.stopPropagation()}
+                    onChange={this.viewChanged}
+                    value={mode}>
+                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
+                    <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>
+                </select>}
+                <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
+                    <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
+                        <div className="presBox-button-left"
+                            onClick={undoBatch(() => {
+                                if (this.childDocs.length) {
+                                    this.layoutDoc.presStatus = "manual";
+                                    this.gotoDocument(this.itemIndex, this.activeItem);
+                                }
+                            })}>
+                            <FontAwesomeIcon icon={"play-circle"} />
+                            <div style={{ display: this.props.PanelWidth() > 200 ? "inline-flex" : "none" }}>&nbsp; Present</div>
+                        </div>
+                        {(mode === CollectionViewType.Carousel3D || isMini) ? (null) : <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`}
+                            onClick={(action(() => {
+                                if (this.childDocs.length) this.presentTools = !this.presentTools;
+                            }))}>
+                            <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
+                            {this.presentDropdown}
+                        </div>}
+                    </span>
+                    {this.playButtons}
+                </div>
+            </div>
+        );
+    }
+
+    @action
+    getList = (list: any): List<number> => {
+        const x: List<number> = list;
+        return x;
+    }
+
+    @action
+    updateList = (list: any): List<number> => {
+        const targetDoc: Doc = this.targetDoc;
+        const x: List<number> = list;
+        x.length + 1;
+        x[x.length - 1] = NumCast(targetDoc._scrollY);
+        return x;
+    }
+
+    @action
+    newFrame = () => {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const type: string = StrCast(targetDoc.type);
+        if (!activeItem.frameList) activeItem.frameList = new List<number>();
+        switch (type) {
+            case (DocumentType.PDF || DocumentType.RTF || DocumentType.WEB):
+                this.updateList(activeItem.frameList);
+                break;
+            case DocumentType.COL:
+                break;
+            default:
+                break;
+        }
+    }
+
+    @computed get frameListHeader() {
+        return (<div className="frameList-header">
+            &nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : (null)}
+            <div className={"frameList-headerButtons"}>
+                <Tooltip title={<><div className="dash-tooltip">{"Add frame by example"}</div></>}><div className={"headerButton"} onClick={e => { e.stopPropagation(); this.newFrame(); }}>
+                    <FontAwesomeIcon icon={"plus"} onPointerDown={e => e.stopPropagation()} />
+                </div></Tooltip>
+                <Tooltip title={<><div className="dash-tooltip">{"Edit in collection"}</div></>}><div className={"headerButton"} onClick={e => { e.stopPropagation(); console.log('New frame'); }}>
+                    <FontAwesomeIcon icon={"edit"} onPointerDown={e => e.stopPropagation()} />
+                </div></Tooltip>
+            </div>
+        </div>);
+    }
+
+    @computed get frameList() {
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
+        const frameList: List<number> = this.getList(activeItem.frameList);
+        if (frameList) {
+            const frameItems = frameList.map((value) =>
+                <div className="framList-item">
+
+                </div>
+            );
+            return (
+
+                <div className="frameList-container">
+                    {frameItems}
+                </div>
+            );
+        } else return (null);
+
+    }
+
+    @computed get playButtonFrames() {
+        const targetDoc: Doc = this.targetDoc;
+        return (
+            <>
+                {this.targetDoc ? <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? "inline-flex" : "none" }}>
+                    <div>{targetDoc._currentFrame}</div>
+                    <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
+                    <div>{targetDoc.lastFrame}</div>
+                </div> : null}
+            </>
+        );
+    }
+
+    @computed get playButtons() {
+        const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1);
+        const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0);
+        // Case 1: There are still other frames and should go through all frames before going to next slide
+        return (<div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== "edit" ? "inline-flex" : "none" }}>
+            <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
+            <div className="presPanel-divider"></div>
+            <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onClick={() => { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-left"} /></div>
+            <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? "pause" : "play"} /></div></Tooltip>
+            <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onClick={() => { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-right"} /></div>
+            <div className="presPanel-divider"></div>
+            <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}><b>1</b></div></Tooltip>
+            <div
+                className="presPanel-button-text"
+                onClick={() => this.gotoDocument(0, this.activeItem)}
+                style={{ display: this.props.PanelWidth() > 250 ? "inline-flex" : "none" }}>
+                Slide {this.itemIndex + 1} / {this.childDocs.length}
+                {this.playButtonFrames}
+            </div>
+            <div className="presPanel-divider"></div>
+            {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }))}>EXIT</div>
+                : <div className="presPanel-button" onClick={undoBatch(action(() => this.layoutDoc.presStatus = "edit"))}>
+                    <FontAwesomeIcon icon={"times"} />
+                </div>}
+        </div>);
+    }
+
+    @action
+    startOrPause = () => {
+        if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex);
+        else this.pauseAutoPres();
+    }
+
+    render() {
+        // calling this method for keyEvents
+        this.isPres;
+        // needed to ensure that the childDocs are loaded for looking up fields
+        this.childDocs.slice();
+        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
+        const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
+        const presEnd: boolean = !this.layoutDoc.presLoop && (this.itemIndex === this.childDocs.length - 1);
+        const presStart: boolean = !this.layoutDoc.presLoop && (this.itemIndex === 0);
+        return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ?
+            <div className="miniPres">
+                <div className="presPanelOverlay" style={{ display: "inline-flex", height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
+                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
+                    <div className="presPanel-divider"></div>
+                    <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onClick={() => { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-left"} /></div>
+                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
+                    <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onClick={() => { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-right"} /></div>
+                    <div className="presPanel-divider"></div>
+                    <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}><b>1</b></div></Tooltip>
+                    <div className="presPanel-button-text">
+                        Slide {this.itemIndex + 1} / {this.childDocs.length}
+                        {this.playButtonFrames}
+                    </div>
+                    <div className="presPanel-divider"></div>
+                    <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.updateMinimize(); this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); }))}>EXIT</div>
+                </div>
+            </div>
+            :
+            <div className="presBox-cont" style={{ minWidth: CurrentUserUtils.OverlayDocs.includes(this.layoutDoc) ? 240 : undefined }} >
+                {this.topPanel}
+                {this.toolbar}
+                {this.newDocumentToolbarDropdown}
+                <div className="presBox-listCont">
+                    {mode !== CollectionViewType.Invalid ?
+                        <CollectionView {...this.props}
+                            ContainingCollectionDoc={this.props.Document}
+                            PanelWidth={this.props.PanelWidth}
+                            PanelHeight={this.panelHeight}
+                            childIgnoreNativeSize={true}
+                            moveDocument={returnFalse}
+                            childFitWidth={returnTrue}
+                            childOpacity={returnOne}
+                            childLayoutTemplate={this.childLayoutTemplate}
+                            filterAddDocument={this.addDocumentFilter}
+                            removeDocument={returnFalse}
+                            dontRegisterView={true}
+                            focus={this.selectElement}
+                            ScreenToLocalTransform={this.getTransform}
+                        />
+                        : (null)
+                    }
+                </div>
+            </div>;
+    }
+}
+Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
+    if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
+    if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 35 : 31;
+    if (field === 'presStatus') return container.presStatus;
+    if (field === '_itemIndex') return container._itemIndex;
+    if (field === 'presBox') return container;
+    return undefined;
+});
\ No newline at end of file
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
new file mode 100644
index 000000000..1ad4b820e
--- /dev/null
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -0,0 +1,235 @@
+$light-blue: #AEDDF8;
+$dark-blue: #5B9FDD;
+$light-background: #ececec;
+$slide-background: #d5dce2;
+$slide-active: #5B9FDD;
+
+.presItem-container {
+    cursor: grab;
+    display: grid;
+    grid-template-columns: 20px auto;
+    font-family: Roboto;
+    letter-spacing: normal;
+    position: relative;
+    pointer-events: all;
+    width: 100%;
+    height: 100%;
+    font-weight: 400;
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    align-items: center;
+
+    .presItem-number {
+        margin-top: 3.5px;
+        font-size: 12px;
+        font-weight: 700;
+        text-align: center;
+        justify-self: center;
+        align-self: flex-start;
+        position: relative;
+        display: inline-block;
+        overflow: hidden;
+    }
+
+}
+
+.presItem-slide {
+    position: relative;
+    background-color: #d5dce2;
+    border-radius: 5px;
+    height: calc(100% - 7px);
+    width: calc(100% - 15px);
+    display: grid;
+    grid-template-rows: 16px 10px auto;
+    grid-template-columns: max-content max-content max-content max-content auto;
+
+    .presItem-name {
+        min-width: 20px;
+        z-index: 300;
+        top: 2px;
+        align-self: center;
+        font-size: 11px;
+        font-family: Roboto;
+        font-weight: 500;
+        position: relative;
+        padding-left: 10px;
+        padding-right: 10px;
+        letter-spacing: normal;
+        width: max-content;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        white-space: pre;
+    }
+
+    .presItem-docName {
+        min-width: 20px;
+        z-index: 300;
+        align-self: center;
+        font-size: 9px;
+        font-family: Roboto;
+        font-weight: 300;
+        position: relative;
+        padding-left: 10px;
+        padding-right: 10px;
+        letter-spacing: normal;
+        width: max-content;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        white-space: pre;
+        grid-row: 2;
+        grid-column: 1/6;
+    }
+
+    .presItem-time {
+        align-self: center;
+        position: relative;
+        padding-right: 10px;
+        top: 1px;
+        font-size: 10;
+        font-weight: 300;
+        font-family: Roboto;
+        z-index: 300;
+        letter-spacing: normal;
+    }
+
+    .presItem-embedded {
+        overflow: hidden;
+        grid-row: 3;
+        grid-column: 1/8;
+        position: relative;
+        display: flex;
+        width: auto;
+        justify-content: center;
+        margin: auto;
+        margin-bottom: 2px;
+        border-bottom-left-radius: 5px;
+        border-bottom-right-radius: 5px;
+    }
+
+    .presItem-embeddedMask {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        border-radius: 3px;
+        top: 0;
+        left: 0;
+        z-index: 1;
+        overflow: hidden;
+    }
+
+
+    .presItem-slideButtons {
+        display: flex;
+        grid-column: 7;
+        grid-row: 1/3;
+        width: max-content;
+        justify-self: right;
+        justify-content: flex-end;
+
+        .slideButton {
+            cursor: pointer;
+            position: relative;
+            border-radius: 100px;
+            z-index: 300;
+            width: 18px;
+            height: 18px;
+            display: flex;
+            font-size: 12px;
+            justify-self: center;
+            align-self: center;
+            background-color: rgba(0, 0, 0, 0.5);
+            color: white;
+            justify-content: center;
+            align-items: center;
+            transition: 0.2s;
+            margin-right: 3px;
+        }
+
+        .slideButton:hover {
+            background-color: rgba(0, 0, 0, 1);
+            transform: scale(1.2);
+        }
+    }
+}
+
+// .presItem-slide:hover {
+//     .presItem-slideButtons {
+//         display: flex;
+//         grid-column: 7;
+//         grid-row: 1/3;
+//         width: max-content;
+//         justify-self: right;
+//         justify-content: flex-end;
+
+//         .slideButton {
+//             cursor: pointer;
+//             position: relative;
+//             border-radius: 100px;
+//             z-index: 300;
+//             width: 18px;
+//             height: 18px;
+//             display: flex;
+//             font-size: 12px;
+//             justify-self: center;
+//             align-self: center;
+//             background-color: rgba(0, 0, 0, 0.5);
+//             color: white;
+//             justify-content: center;
+//             align-items: center;
+//             transition: 0.2s;
+//             margin-right: 3px;
+//         }
+
+//         .slideButton:hover {
+//             background-color: rgba(0, 0, 0, 1);
+//             transform: scale(1.2);
+//         }
+//     }
+// }
+
+.presItem-slide.active {
+    box-shadow: 0 0 0px 1.5px $dark-blue;
+}
+
+.presItem-multiDrag {
+    font-family: Roboto;
+    font-weight: 600;
+    color: white;
+    text-align: center;
+    justify-content: center;
+    align-content: center;
+    width: 100px;
+    height: 30px;
+    position: absolute;
+    background-color: $dark-blue;
+    z-index: 4000;
+    border-radius: 10px;
+    box-shadow: black 0.4vw 0.4vw 0.8vw;
+    line-height: 30px;
+}
+
+.presItem-miniSlide {
+    font-weight: 700;
+    font-size: 12;
+    grid-column: 1/8;
+    align-self: center;
+    justify-self: center;
+    background-color: #d5dce2;
+    width: 26px;
+    text-align: center;
+    height: 26px;
+    line-height: 28px;
+    border-radius: 100%;
+}
+
+.presItem-miniSlide.active {
+    box-shadow: 0 0 0px 1.5px $dark-blue;
+}
+
+// .presItem-slide:hover {
+//     background: $slide-hover;
+// }
\ No newline at end of file
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
new file mode 100644
index 000000000..5e713c3cf
--- /dev/null
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -0,0 +1,388 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
+import { DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { documentSchema } from '../../../../fields/documentSchemas';
+import { Id } from "../../../../fields/FieldSymbols";
+import { createSchema, makeInterface } from '../../../../fields/Schema';
+import { Cast, NumCast, StrCast } from "../../../../fields/Types";
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath, returnEmptyDoclist } from "../../../../Utils";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
+import { DocumentManager } from "../../../util/DocumentManager";
+import { DragManager } from "../../../util/DragManager";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { ViewBoxBaseComponent } from '../../DocComponent';
+import { EditableView } from "../../EditableView";
+import { DocumentView, DocumentViewProps } from "../../nodes/DocumentView";
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { PresBox } from "./PresBox";
+import { Colors } from "../../global/globalEnums";
+import { StyleProp } from "../../StyleProvider";
+import "./PresElementBox.scss";
+import React = require("react");
+import { DocUtils } from "../../../documents/Documents";
+import { PresMovement } from "./PresEnums";
+
+export const presSchema = createSchema({
+    presentationTargetDoc: Doc,
+    presBox: Doc,
+    presZoomButton: "boolean",
+    presNavButton: "boolean",
+    presHideTillShownButton: "boolean",
+    presFadeButton: "boolean",
+    presHideAfterButton: "boolean",
+    presGroupButton: "boolean",
+    presExpandInlineButton: "boolean"
+});
+
+type PresDocument = makeInterface<[typeof presSchema, typeof documentSchema]>;
+const PresDocument = makeInterface(presSchema, documentSchema);
+/**
+ * This class models the view a document added to presentation will have in the presentation.
+ * It involves some functionality for its buttons and options.
+ */
+@observer
+export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDocument>(PresDocument) {
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
+    _heightDisposer: IReactionDisposer | undefined;
+
+    @observable _dragging = false;
+    // these fields are conditionally computed fields on the layout document that take this document as a parameter
+    @computed get indexInPres() { return Number(this.lookupField("indexInPres")); }  // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
+    @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox.  We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
+    @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
+    @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
+    @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
+    @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
+
+    componentDidMount() {
+        this.layoutDoc.hideLinkButton = true;
+        this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
+            params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+    }
+    componentWillUnmount() {
+        this._heightDisposer?.();
+    }
+
+    /**
+     * Returns a local transformed coordinate array for given coordinates.
+     */
+    ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
+
+    @action
+    presExpandDocumentClick = () => {
+        this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
+    }
+
+    embedHeight = (): number => 97;
+    // embedWidth = () => this.props.PanelWidth();
+    // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
+    embedWidth = (): number => this.props.PanelWidth() - 35;
+    styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+        if (property === StyleProp.Opacity) return 1;
+        return this.props.styleProvider?.(doc, props, property);
+    }
+    /**
+     * The function that is responsible for rendering a preview or not for this
+     * presentation element.
+     */
+    @computed get renderEmbeddedInline() {
+        return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
+            <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
+                <DocumentView
+                    Document={this.targetDoc}
+                    DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
+                    styleProvider={this.styleProvider}
+                    layerProvider={this.props.layerProvider}
+                    docViewPath={returnEmptyDoclist}
+                    rootSelected={returnTrue}
+                    addDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    isContentActive={this.props.isContentActive}
+                    addDocTab={returnFalse}
+                    pinToPres={returnFalse}
+                    PanelWidth={this.embedWidth}
+                    PanelHeight={this.embedHeight}
+                    ScreenToLocalTransform={Transform.Identity}
+                    moveDocument={this.props.moveDocument!}
+                    renderDepth={this.props.renderDepth + 1}
+                    focus={DocUtils.DefaultFocus}
+                    whenChildContentsActiveChanged={returnFalse}
+                    bringToFront={returnFalse}
+                    docFilters={this.props.docFilters}
+                    docRangeFilters={this.props.docRangeFilters}
+                    searchFilterDocs={this.props.searchFilterDocs}
+                    ContainingCollectionView={undefined}
+                    ContainingCollectionDoc={undefined}
+                    hideLinkButton={true}
+                />
+                <div className="presItem-embeddedMask" />
+            </div>;
+    }
+
+    @computed get duration() {
+        let durationInS: number;
+        if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
+        else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
+        else durationInS = 2;
+        return "D: " + durationInS + "s";
+    }
+
+    @computed get transition() {
+        let transitionInS: number;
+        if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
+        else transitionInS = 0.5;
+        return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
+    }
+
+    private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
+    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+    private _titleRef: React.RefObject<EditableView> = React.createRef();
+
+
+    @action
+    headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
+        const element = e.target as any;
+        e.stopPropagation();
+        e.preventDefault();
+        if (element && !(e.ctrlKey || e.metaKey)) {
+            if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
+                PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+                setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+            } else {
+                setupMoveUpEvents(this, e, ((e: PointerEvent) => {
+                    PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+                    return this.startDrag(e);
+                }), emptyFunction, emptyFunction);
+            }
+        }
+    }
+
+    headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
+        e.stopPropagation();
+        e.preventDefault();
+    }
+
+    startDrag = (e: PointerEvent) => {
+        const miniView: boolean = this.toolbarWidth <= 100;
+        const activeItem = this.rootDoc;
+        const dragArray = PresBox.Instance._dragArray;
+        const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
+        const dragItem: HTMLElement[] = [];
+        if (dragArray.length === 1) {
+            const doc = dragArray[0];
+            doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
+            dragItem.push(doc);
+        } else if (dragArray.length >= 1) {
+            const doc = document.createElement('div');
+            doc.className = "presItem-multiDrag";
+            doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
+            doc.style.position = 'absolute';
+            doc.style.top = (e.clientY) + 'px';
+            doc.style.left = (e.clientX - 50) + 'px';
+            dragItem.push(doc);
+        }
+
+        // const dropEvent = () => runInAction(() => this._dragging = false);
+        if (activeItem) {
+            DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
+            // runInAction(() => this._dragging = true);
+            return true;
+        }
+        return false;
+    }
+
+    onPointerOver = (e: any) => {
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.addEventListener("pointermove", this.onPointerMove);
+    }
+
+    onPointerMove = (e: PointerEvent) => {
+        const slide = this._itemRef.current!;
+        let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
+        for (const doc of DragManager.docsBeingDragged) {
+            if (!doc.presentationTargetDoc) dragIsPresItem = false;
+        }
+        if (slide && dragIsPresItem) {
+            const rect = slide.getBoundingClientRect();
+            const y = e.clientY - rect.top;  //y position within the element.
+            const height = slide.clientHeight;
+            const halfLine = height / 2;
+            if (y <= halfLine) {
+                slide.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                slide.style.borderBottom = "0px";
+            } else if (y > halfLine) {
+                slide.style.borderTop = "0px";
+                slide.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            }
+        }
+        document.removeEventListener("pointermove", this.onPointerMove);
+    }
+
+    onPointerLeave = (e: any) => {
+        this._itemRef.current!.style.borderTop = "0px";
+        this._itemRef.current!.style.borderBottom = "0px";
+        document.removeEventListener("pointermove", this.onPointerMove);
+    }
+
+    @action
+    toggleProperties = () => {
+        if (CurrentUserUtils.propertiesWidth < 5) {
+            action(() => (CurrentUserUtils.propertiesWidth = 250));
+        }
+    }
+
+    @undoBatch
+    removeItem = action((e: React.MouseEvent) => {
+        this.props.removeDocument?.(this.rootDoc);
+        if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
+            PresBox.Instance._selectedArray.delete(this.rootDoc);
+        }
+        e.stopPropagation();
+    });
+
+    @undoBatch
+    @action
+    onSetValue = (value: string) => {
+        this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
+        return true;
+    }
+
+    /**
+     * Method called for updating the view of the currently selected document
+     * 
+     * @param targetDoc 
+     * @param activeItem 
+     */
+    @undoBatch
+    @action
+    updateView = (targetDoc: Doc, activeItem: Doc) => {
+        if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+            const scroll = targetDoc._scrollTop;
+            activeItem.presPinViewScroll = scroll;
+        } else if (targetDoc.type === DocumentType.VID) {
+            activeItem.presPinTimecode = targetDoc._currentTimecode;
+        } else if (targetDoc.type === DocumentType.COMPARISON) {
+            const clipWidth = targetDoc._clipWidth;
+            activeItem.presPinClipWidth = clipWidth;
+        } else {
+            const x = targetDoc._panX;
+            const y = targetDoc._panY;
+            const scale = targetDoc._viewScale;
+            activeItem.presPinViewX = x;
+            activeItem.presPinViewY = y;
+            activeItem.presPinViewScale = scale;
+        }
+    }
+
+    @computed
+    get toolbarWidth(): number {
+        const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
+        let width: number = NumCast(this.presBox._width);
+        if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
+        if (width === 0) width = 300;
+        return width;
+    }
+
+    @computed get mainItem() {
+        const isSelected: boolean = PresBox.Instance._selectedArray.has(this.rootDoc);
+        const toolbarWidth: number = this.toolbarWidth;
+        const showMore: boolean = this.toolbarWidth >= 300;
+        const miniView: boolean = this.toolbarWidth <= 110;
+        const presBox: Doc = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presColorBool: boolean = presBoxColor ? (presBoxColor !== Colors.WHITE && presBoxColor !== "transparent") : false;
+        const targetDoc: Doc = this.targetDoc;
+        const activeItem: Doc = this.rootDoc;
+        return (
+            <div className={`presItem-container`}
+                key={this.props.Document[Id] + this.indexInPres}
+                ref={this._itemRef}
+                style={{
+                    backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? Colors.LIGHT_BLUE : "transparent",
+                    opacity: this._dragging ? 0.3 : 1
+                }}
+                onClick={e => {
+                    e.stopPropagation();
+                    e.preventDefault();
+                    PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
+                }}
+                onDoubleClick={action(e => {
+                    this.toggleProperties();
+                    PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
+                })}
+                onPointerOver={this.onPointerOver}
+                onPointerLeave={this.onPointerLeave}
+                onPointerDown={this.headerDown}
+                onPointerUp={this.headerUp}
+            >
+                {miniView ?
+                    // when width is LESS than 110 px 
+                    <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
+                        {`${this.indexInPres + 1}.`}
+                    </div>
+                    :
+                    // when width is MORE than 110 px 
+                    <div className="presItem-number">
+                        {`${this.indexInPres + 1}.`}
+                    </div>}
+                {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
+                    style={{
+                        backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+                        boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
+                    }}>
+                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
+                        <EditableView
+                            ref={this._titleRef}
+                            editing={!isSelected ? false : undefined}
+                            contents={activeItem.title}
+                            overflow={'ellipsis'}
+                            GetValue={() => StrCast(activeItem.title)}
+                            SetValue={this.onSetValue}
+                        />
+                    </div>
+                    <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
+                    <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
+                    <div className={"presItem-slideButtons"}>
+                        <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
+                            <div className="slideButton"
+                                onClick={() => this.updateView(targetDoc, activeItem)}
+                                style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
+                        </Tooltip>
+                        {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
+                            <div className="slideButton"
+                                onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
+                                style={{
+                                    zIndex: 1000 - this.indexInPres,
+                                    fontWeight: 700,
+                                    backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined,
+                                    height: activeItem.groupWithUp ? 53 : 18,
+                                    transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
+                                }}>
+                                <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
+                                    <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
+                                </div>
+                            </div>
+                        </Tooltip>}
+                        <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
+                            <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
+                        </div></Tooltip>
+                        <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
+                            className={"slideButton"}
+                            onClick={this.removeItem}>
+                            <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
+                        </div></Tooltip>
+                    </div>
+                    <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
+                    {this.renderEmbeddedInline}
+                </div>}
+            </div >);
+    }
+
+    render() {
+        return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts
new file mode 100644
index 000000000..93ab323fb
--- /dev/null
+++ b/src/client/views/nodes/trails/PresEnums.ts
@@ -0,0 +1,28 @@
+export enum PresMovement {
+    Zoom = "zoom",
+    Pan = "pan",
+    Jump = "jump",
+    None = "none",
+}
+
+export enum PresEffect {
+    Zoom = "Zoom",
+    Lightspeed = "Lightspeed",
+    Fade = "Fade in",
+    Flip = "Flip",
+    Rotate = "Rotate",
+    Bounce = "Bounce",
+    Roll = "Roll",
+    None = "None",
+    Left = "left",
+    Right = "right",
+    Center = "center",
+    Top = "top",
+    Bottom = "bottom"
+}
+
+export enum PresStatus {
+    Autoplay = "auto",
+    Manual = "manual",
+    Edit = "edit"
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/trails/index.ts b/src/client/views/nodes/trails/index.ts
new file mode 100644
index 000000000..8f3f7b03a
--- /dev/null
+++ b/src/client/views/nodes/trails/index.ts
@@ -0,0 +1,3 @@
+export * from "./PresBox";
+export * from "./PresElementBox";
+export * from "./PresEnums";
\ No newline at end of file
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
deleted file mode 100644
index 1ad4b820e..000000000
--- a/src/client/views/presentationview/PresElementBox.scss
+++ /dev/null
@@ -1,235 +0,0 @@
-$light-blue: #AEDDF8;
-$dark-blue: #5B9FDD;
-$light-background: #ececec;
-$slide-background: #d5dce2;
-$slide-active: #5B9FDD;
-
-.presItem-container {
-    cursor: grab;
-    display: grid;
-    grid-template-columns: 20px auto;
-    font-family: Roboto;
-    letter-spacing: normal;
-    position: relative;
-    pointer-events: all;
-    width: 100%;
-    height: 100%;
-    font-weight: 400;
-    -webkit-touch-callout: none;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-    align-items: center;
-
-    .presItem-number {
-        margin-top: 3.5px;
-        font-size: 12px;
-        font-weight: 700;
-        text-align: center;
-        justify-self: center;
-        align-self: flex-start;
-        position: relative;
-        display: inline-block;
-        overflow: hidden;
-    }
-
-}
-
-.presItem-slide {
-    position: relative;
-    background-color: #d5dce2;
-    border-radius: 5px;
-    height: calc(100% - 7px);
-    width: calc(100% - 15px);
-    display: grid;
-    grid-template-rows: 16px 10px auto;
-    grid-template-columns: max-content max-content max-content max-content auto;
-
-    .presItem-name {
-        min-width: 20px;
-        z-index: 300;
-        top: 2px;
-        align-self: center;
-        font-size: 11px;
-        font-family: Roboto;
-        font-weight: 500;
-        position: relative;
-        padding-left: 10px;
-        padding-right: 10px;
-        letter-spacing: normal;
-        width: max-content;
-        text-overflow: ellipsis;
-        overflow: hidden;
-        white-space: pre;
-    }
-
-    .presItem-docName {
-        min-width: 20px;
-        z-index: 300;
-        align-self: center;
-        font-size: 9px;
-        font-family: Roboto;
-        font-weight: 300;
-        position: relative;
-        padding-left: 10px;
-        padding-right: 10px;
-        letter-spacing: normal;
-        width: max-content;
-        text-overflow: ellipsis;
-        overflow: hidden;
-        white-space: pre;
-        grid-row: 2;
-        grid-column: 1/6;
-    }
-
-    .presItem-time {
-        align-self: center;
-        position: relative;
-        padding-right: 10px;
-        top: 1px;
-        font-size: 10;
-        font-weight: 300;
-        font-family: Roboto;
-        z-index: 300;
-        letter-spacing: normal;
-    }
-
-    .presItem-embedded {
-        overflow: hidden;
-        grid-row: 3;
-        grid-column: 1/8;
-        position: relative;
-        display: flex;
-        width: auto;
-        justify-content: center;
-        margin: auto;
-        margin-bottom: 2px;
-        border-bottom-left-radius: 5px;
-        border-bottom-right-radius: 5px;
-    }
-
-    .presItem-embeddedMask {
-        width: 100%;
-        height: 100%;
-        position: absolute;
-        border-radius: 3px;
-        top: 0;
-        left: 0;
-        z-index: 1;
-        overflow: hidden;
-    }
-
-
-    .presItem-slideButtons {
-        display: flex;
-        grid-column: 7;
-        grid-row: 1/3;
-        width: max-content;
-        justify-self: right;
-        justify-content: flex-end;
-
-        .slideButton {
-            cursor: pointer;
-            position: relative;
-            border-radius: 100px;
-            z-index: 300;
-            width: 18px;
-            height: 18px;
-            display: flex;
-            font-size: 12px;
-            justify-self: center;
-            align-self: center;
-            background-color: rgba(0, 0, 0, 0.5);
-            color: white;
-            justify-content: center;
-            align-items: center;
-            transition: 0.2s;
-            margin-right: 3px;
-        }
-
-        .slideButton:hover {
-            background-color: rgba(0, 0, 0, 1);
-            transform: scale(1.2);
-        }
-    }
-}
-
-// .presItem-slide:hover {
-//     .presItem-slideButtons {
-//         display: flex;
-//         grid-column: 7;
-//         grid-row: 1/3;
-//         width: max-content;
-//         justify-self: right;
-//         justify-content: flex-end;
-
-//         .slideButton {
-//             cursor: pointer;
-//             position: relative;
-//             border-radius: 100px;
-//             z-index: 300;
-//             width: 18px;
-//             height: 18px;
-//             display: flex;
-//             font-size: 12px;
-//             justify-self: center;
-//             align-self: center;
-//             background-color: rgba(0, 0, 0, 0.5);
-//             color: white;
-//             justify-content: center;
-//             align-items: center;
-//             transition: 0.2s;
-//             margin-right: 3px;
-//         }
-
-//         .slideButton:hover {
-//             background-color: rgba(0, 0, 0, 1);
-//             transform: scale(1.2);
-//         }
-//     }
-// }
-
-.presItem-slide.active {
-    box-shadow: 0 0 0px 1.5px $dark-blue;
-}
-
-.presItem-multiDrag {
-    font-family: Roboto;
-    font-weight: 600;
-    color: white;
-    text-align: center;
-    justify-content: center;
-    align-content: center;
-    width: 100px;
-    height: 30px;
-    position: absolute;
-    background-color: $dark-blue;
-    z-index: 4000;
-    border-radius: 10px;
-    box-shadow: black 0.4vw 0.4vw 0.8vw;
-    line-height: 30px;
-}
-
-.presItem-miniSlide {
-    font-weight: 700;
-    font-size: 12;
-    grid-column: 1/8;
-    align-self: center;
-    justify-self: center;
-    background-color: #d5dce2;
-    width: 26px;
-    text-align: center;
-    height: 26px;
-    line-height: 28px;
-    border-radius: 100%;
-}
-
-.presItem-miniSlide.active {
-    box-shadow: 0 0 0px 1.5px $dark-blue;
-}
-
-// .presItem-slide:hover {
-//     background: $slide-hover;
-// }
\ No newline at end of file
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
deleted file mode 100644
index f15d51764..000000000
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ /dev/null
@@ -1,386 +0,0 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip } from "@material-ui/core";
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { DataSym, Doc, Opt } from "../../../fields/Doc";
-import { documentSchema } from '../../../fields/documentSchemas';
-import { Id } from "../../../fields/FieldSymbols";
-import { createSchema, makeInterface } from '../../../fields/Schema';
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath, returnEmptyDoclist } from "../../../Utils";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager } from "../../util/DragManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { ViewBoxBaseComponent } from '../DocComponent';
-import { EditableView } from "../EditableView";
-import { DocumentView, DocumentViewProps } from "../nodes/DocumentView";
-import { FieldView, FieldViewProps } from '../nodes/FieldView';
-import { PresBox, PresColor, PresMovement } from "../nodes/PresBox";
-import { StyleProp } from "../StyleProvider";
-import "./PresElementBox.scss";
-import React = require("react");
-import { DocUtils } from "../../documents/Documents";
-
-export const presSchema = createSchema({
-    presentationTargetDoc: Doc,
-    presBox: Doc,
-    presZoomButton: "boolean",
-    presNavButton: "boolean",
-    presHideTillShownButton: "boolean",
-    presFadeButton: "boolean",
-    presHideAfterButton: "boolean",
-    presGroupButton: "boolean",
-    presExpandInlineButton: "boolean"
-});
-
-type PresDocument = makeInterface<[typeof presSchema, typeof documentSchema]>;
-const PresDocument = makeInterface(presSchema, documentSchema);
-/**
- * This class models the view a document added to presentation will have in the presentation.
- * It involves some functionality for its buttons and options.
- */
-@observer
-export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDocument>(PresDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
-    _heightDisposer: IReactionDisposer | undefined;
-
-    @observable _dragging = false;
-    // these fields are conditionally computed fields on the layout document that take this document as a parameter
-    @computed get indexInPres() { return Number(this.lookupField("indexInPres")); }  // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
-    @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox.  We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
-    @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
-    @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
-    @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
-    @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
-
-    componentDidMount() {
-        this.layoutDoc.hideLinkButton = true;
-        this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
-            params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
-    }
-    componentWillUnmount() {
-        this._heightDisposer?.();
-    }
-
-    /**
-     * Returns a local transformed coordinate array for given coordinates.
-     */
-    ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
-
-    @action
-    presExpandDocumentClick = () => {
-        this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
-    }
-
-    embedHeight = (): number => 97;
-    // embedWidth = () => this.props.PanelWidth();
-    // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
-    embedWidth = (): number => this.props.PanelWidth() - 35;
-    styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
-        if (property === StyleProp.Opacity) return 1;
-        return this.props.styleProvider?.(doc, props, property);
-    }
-    /**
-     * The function that is responsible for rendering a preview or not for this
-     * presentation element.
-     */
-    @computed get renderEmbeddedInline() {
-        return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
-            <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
-                <DocumentView
-                    Document={this.targetDoc}
-                    DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
-                    styleProvider={this.styleProvider}
-                    layerProvider={this.props.layerProvider}
-                    docViewPath={returnEmptyDoclist}
-                    rootSelected={returnTrue}
-                    addDocument={returnFalse}
-                    removeDocument={returnFalse}
-                    isContentActive={this.props.isContentActive}
-                    addDocTab={returnFalse}
-                    pinToPres={returnFalse}
-                    PanelWidth={this.embedWidth}
-                    PanelHeight={this.embedHeight}
-                    ScreenToLocalTransform={Transform.Identity}
-                    moveDocument={this.props.moveDocument!}
-                    renderDepth={this.props.renderDepth + 1}
-                    focus={DocUtils.DefaultFocus}
-                    whenChildContentsActiveChanged={returnFalse}
-                    bringToFront={returnFalse}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
-                    searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    hideLinkButton={true}
-                />
-                <div className="presItem-embeddedMask" />
-            </div>;
-    }
-
-    @computed get duration() {
-        let durationInS: number;
-        if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
-        else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
-        else durationInS = 2;
-        return "D: " + durationInS + "s";
-    }
-
-    @computed get transition() {
-        let transitionInS: number;
-        if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
-        else transitionInS = 0.5;
-        return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
-    }
-
-    private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
-    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-    private _titleRef: React.RefObject<EditableView> = React.createRef();
-
-
-    @action
-    headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
-        const element = e.target as any;
-        e.stopPropagation();
-        e.preventDefault();
-        if (element && !(e.ctrlKey || e.metaKey)) {
-            if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
-                PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
-                setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
-            } else {
-                setupMoveUpEvents(this, e, ((e: PointerEvent) => {
-                    PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
-                    return this.startDrag(e);
-                }), emptyFunction, emptyFunction);
-            }
-        }
-    }
-
-    headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
-        e.stopPropagation();
-        e.preventDefault();
-    }
-
-    startDrag = (e: PointerEvent) => {
-        const miniView: boolean = this.toolbarWidth <= 100;
-        const activeItem = this.rootDoc;
-        const dragArray = PresBox.Instance._dragArray;
-        const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
-        const dragItem: HTMLElement[] = [];
-        if (dragArray.length === 1) {
-            const doc = dragArray[0];
-            doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
-            dragItem.push(doc);
-        } else if (dragArray.length >= 1) {
-            const doc = document.createElement('div');
-            doc.className = "presItem-multiDrag";
-            doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
-            doc.style.position = 'absolute';
-            doc.style.top = (e.clientY) + 'px';
-            doc.style.left = (e.clientX - 50) + 'px';
-            dragItem.push(doc);
-        }
-
-        // const dropEvent = () => runInAction(() => this._dragging = false);
-        if (activeItem) {
-            DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
-            // runInAction(() => this._dragging = true);
-            return true;
-        }
-        return false;
-    }
-
-    onPointerOver = (e: any) => {
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.addEventListener("pointermove", this.onPointerMove);
-    }
-
-    onPointerMove = (e: PointerEvent) => {
-        const slide = this._itemRef.current!;
-        let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
-        for (const doc of DragManager.docsBeingDragged) {
-            if (!doc.presentationTargetDoc) dragIsPresItem = false;
-        }
-        if (slide && dragIsPresItem) {
-            const rect = slide.getBoundingClientRect();
-            const y = e.clientY - rect.top;  //y position within the element.
-            const height = slide.clientHeight;
-            const halfLine = height / 2;
-            if (y <= halfLine) {
-                slide.style.borderTop = "solid 2px #5B9FDD";
-                slide.style.borderBottom = "0px";
-            } else if (y > halfLine) {
-                slide.style.borderTop = "0px";
-                slide.style.borderBottom = "solid 2px #5B9FDD";
-            }
-        }
-        document.removeEventListener("pointermove", this.onPointerMove);
-    }
-
-    onPointerLeave = (e: any) => {
-        this._itemRef.current!.style.borderTop = "0px";
-        this._itemRef.current!.style.borderBottom = "0px";
-        document.removeEventListener("pointermove", this.onPointerMove);
-    }
-
-    @action
-    toggleProperties = () => {
-        if (CurrentUserUtils.propertiesWidth < 5) {
-            action(() => (CurrentUserUtils.propertiesWidth = 250));
-        }
-    }
-
-    @undoBatch
-    removeItem = action((e: React.MouseEvent) => {
-        this.props.removeDocument?.(this.rootDoc);
-        if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
-            PresBox.Instance._selectedArray.delete(this.rootDoc);
-        }
-        e.stopPropagation();
-    });
-
-    @undoBatch
-    @action
-    onSetValue = (value: string) => {
-        this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
-        return true;
-    }
-
-    /**
-     * Method called for updating the view of the currently selected document
-     * 
-     * @param targetDoc 
-     * @param activeItem 
-     */
-    @undoBatch
-    @action
-    updateView = (targetDoc: Doc, activeItem: Doc) => {
-        if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
-            const scroll = targetDoc._scrollTop;
-            activeItem.presPinViewScroll = scroll;
-        } else if (targetDoc.type === DocumentType.VID) {
-            activeItem.presPinTimecode = targetDoc._currentTimecode;
-        } else if (targetDoc.type === DocumentType.COMPARISON) {
-            const clipWidth = targetDoc._clipWidth;
-            activeItem.presPinClipWidth = clipWidth;
-        } else {
-            const x = targetDoc._panX;
-            const y = targetDoc._panY;
-            const scale = targetDoc._viewScale;
-            activeItem.presPinViewX = x;
-            activeItem.presPinViewY = y;
-            activeItem.presPinViewScale = scale;
-        }
-    }
-
-    @computed
-    get toolbarWidth(): number {
-        const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
-        let width: number = NumCast(this.presBox._width);
-        if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
-        if (width === 0) width = 300;
-        return width;
-    }
-
-    @computed get mainItem() {
-        const isSelected: boolean = PresBox.Instance._selectedArray.has(this.rootDoc);
-        const toolbarWidth: number = this.toolbarWidth;
-        const showMore: boolean = this.toolbarWidth >= 300;
-        const miniView: boolean = this.toolbarWidth <= 110;
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
-        const presColorBool: boolean = presBoxColor ? (presBoxColor !== "white" && presBoxColor !== "transparent") : false;
-        const targetDoc: Doc = this.targetDoc;
-        const activeItem: Doc = this.rootDoc;
-        return (
-            <div className={`presItem-container`}
-                key={this.props.Document[Id] + this.indexInPres}
-                ref={this._itemRef}
-                style={{
-                    backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? "#AEDDF8" : "transparent",
-                    opacity: this._dragging ? 0.3 : 1
-                }}
-                onClick={e => {
-                    e.stopPropagation();
-                    e.preventDefault();
-                    PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
-                }}
-                onDoubleClick={action(e => {
-                    this.toggleProperties();
-                    PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
-                })}
-                onPointerOver={this.onPointerOver}
-                onPointerLeave={this.onPointerLeave}
-                onPointerDown={this.headerDown}
-                onPointerUp={this.headerUp}
-            >
-                {miniView ?
-                    // when width is LESS than 110 px 
-                    <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
-                        {`${this.indexInPres + 1}.`}
-                    </div>
-                    :
-                    // when width is MORE than 110 px 
-                    <div className="presItem-number">
-                        {`${this.indexInPres + 1}.`}
-                    </div>}
-                {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
-                    style={{
-                        backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
-                        boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
-                    }}>
-                    <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
-                        <EditableView
-                            ref={this._titleRef}
-                            editing={!isSelected ? false : undefined}
-                            contents={activeItem.title}
-                            overflow={'ellipsis'}
-                            GetValue={() => StrCast(activeItem.title)}
-                            SetValue={this.onSetValue}
-                        />
-                    </div>
-                    <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
-                    <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
-                    <div className={"presItem-slideButtons"}>
-                        <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
-                            <div className="slideButton"
-                                onClick={() => this.updateView(targetDoc, activeItem)}
-                                style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
-                        </Tooltip>
-                        {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
-                            <div className="slideButton"
-                                onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
-                                style={{
-                                    zIndex: 1000 - this.indexInPres,
-                                    fontWeight: 700,
-                                    backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : PresColor.DarkBlue : undefined,
-                                    height: activeItem.groupWithUp ? 53 : 18,
-                                    transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
-                                }}>
-                                <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
-                                    <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
-                                </div>
-                            </div>
-                        </Tooltip>}
-                        <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
-                            <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
-                        </div></Tooltip>
-                        <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
-                            className={"slideButton"}
-                            onClick={this.removeItem}>
-                            <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
-                        </div></Tooltip>
-                    </div>
-                    <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
-                    {this.renderEmbeddedInline}
-                </div>}
-            </div >);
-    }
-
-    render() {
-        return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss
index 324b96dbd..e2d27d5a6 100644
--- a/src/client/views/topbar/TopBar.scss
+++ b/src/client/views/topbar/TopBar.scss
@@ -30,7 +30,7 @@
                 display: flex;
 
                 .topbar-dashboards {
-                    display: none;
+                    display: inline-flex;
                 }
 
                 .topbar-dashSelect {
@@ -46,12 +46,6 @@
                     }
                 }
             }
-
-            .topbar-lozenge-dashboard:hover {
-                .topbar-dashboards {
-                    display: inline-flex;
-                }
-            }
         }
 
         .topBar-icon {
@@ -85,7 +79,7 @@
             .topbar-lozenge {
                 height: 23;
                 font-size: 12;
-                color: black;
+                color: white;
                 font-family: 'Roboto';
                 font-weight: 400;
                 padding: 4px;
@@ -93,7 +87,7 @@
                 margin-right: 7px;
                 display: flex;
                 align-items: center;
-                border: black 1px solid;
+                border: white 1px solid;
 
                 .topbar-logoff {
                     border-radius: 3px;
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 79239d4ea..65da717f8 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,58 +1,67 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { observer } from "mobx-react";
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { StrCast } from '../../../fields/Types';
 import { Utils } from '../../../Utils';
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { ColorScheme, SettingsManager } from "../../util/SettingsManager";
+import { SettingsManager } from "../../util/SettingsManager";
 import { undoBatch } from "../../util/UndoManager";
+import { Borders, Colors } from "../global/globalEnums";
 import "./TopBar.scss";
-import { Colors, Borders } from "../global/globalEnums";
 
-export const TopBar = () => {
-
-    const myDashboards = DocListCast(CurrentUserUtils.MyDashboards.data);
-    return (
-        <div style={{ pointerEvents: "all" }} className="topbar-container">
-            <div className="topbar-bar" style={{ background: Doc.UserDoc().colorScheme === ColorScheme.Dark ? Colors.DARK_GRAY : Colors.LIGHT_GRAY, borderBottom: Borders.STANDARD }}>
-                <div className="topbar-center" >
-                    <div className="topbar-lozenge-dashboard">
-                        <select className="topbar-dashSelect" onChange={e => CurrentUserUtils.openDashboard(Doc.UserDoc(), myDashboards[Number(e.target.value)])}
-                            value={myDashboards.indexOf(CurrentUserUtils.ActiveDashboard)}
-                            style={{ color: Doc.UserDoc().colorScheme === ColorScheme.Dark ? "white" : "black" }}>
-                            {myDashboards.map((dash, i) => <option key={dash[Id]} value={i}> {StrCast(dash.title)} </option>)}
-                        </select>
-                        <div className="topbar-dashboards">
-                            <div className="topbar-icon" onClick={undoBatch(() => CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}
-                                style={{ color: Doc.UserDoc().colorScheme === ColorScheme.Dark ? "white" : "black" }}>
-                                <FontAwesomeIcon icon="plus"></FontAwesomeIcon>
-                            </div>
-                            <div className="topbar-icon" onClick={undoBatch(() => CurrentUserUtils.snapshotDashboard(Doc.UserDoc()))}
-                                style={{ color: Doc.UserDoc().colorScheme === ColorScheme.Dark ? "white" : "black" }}>
-                                <FontAwesomeIcon icon="camera"></FontAwesomeIcon>
+/**
+ * REACT TYPE: FUNCTIONAL
+ * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user
+ * and settings and help buttons. Future scope for this bar is to include the collaborators that are on the same Dashboard. 
+ */
+@observer
+export class TopBar extends React.Component {
+    render() {
+        const myDashboards = DocListCast(CurrentUserUtils.MyDashboards.data);
+        return (
+            //TODO:glr Add support for light / dark mode
+            <div style={{ pointerEvents: "all" }} className="topbar-container">
+                <div className="topbar-bar" style={{ background: Colors.DARK_GRAY, borderBottom: Borders.STANDARD }}>
+                    <div className="topbar-center" >
+                        <div className="topbar-lozenge-dashboard">
+                            <select className="topbar-dashSelect" onChange={e => CurrentUserUtils.openDashboard(Doc.UserDoc(), myDashboards[Number(e.target.value)])}
+                                value={myDashboards.indexOf(CurrentUserUtils.ActiveDashboard)}
+                                style={{ color: Colors.WHITE }}>
+                                {myDashboards.map((dash, i) => <option key={dash[Id]} value={i}> {StrCast(dash.title)} </option>)}
+                            </select>
+                            <div className="topbar-dashboards">
+                                <div className="topbar-icon" onClick={undoBatch(() => CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}
+                                    style={{ color: Colors.WHITE }}>
+                                    <FontAwesomeIcon icon="plus"></FontAwesomeIcon>
+                                </div>
+                                <div className="topbar-icon" onClick={undoBatch(() => CurrentUserUtils.snapshotDashboard(Doc.UserDoc()))}
+                                    style={{ color: Colors.WHITE }}>
+                                    <FontAwesomeIcon icon="camera"></FontAwesomeIcon>
+                                </div>
                             </div>
                         </div>
                     </div>
-                </div>
-                <div className="topbar-right" >
-                    <div className="topbar-icon"
-                        style={{ color: Doc.UserDoc().colorScheme === ColorScheme.Dark ? "white" : "black" }}>
-                        <FontAwesomeIcon icon="question-circle"></FontAwesomeIcon>
-                    </div>
-                    <div className="topbar-icon" onClick={() => SettingsManager.Instance.open()}
-                        style={{ color: Doc.UserDoc().colorScheme === ColorScheme.Dark ? "white" : "black" }}>
-                        <FontAwesomeIcon icon="cog"></FontAwesomeIcon>
-                    </div>
-                    <div className="topbar-lozenge-user">
-                        {`${Doc.CurrentUserEmail}`}
-                        <div className="topbar-logoff" onClick={() => window.location.assign(Utils.prepend("/logout"))}>
-                            Logoff
+                    <div className="topbar-right" >
+                        <div className="topbar-icon"
+                            style={{ color: Colors.WHITE }}>
+                            <FontAwesomeIcon icon="question-circle"></FontAwesomeIcon>
+                        </div>
+                        <div className="topbar-icon" onClick={() => SettingsManager.Instance.open()}
+                            style={{ color: Colors.WHITE }}>
+                            <FontAwesomeIcon icon="cog"></FontAwesomeIcon>
+                        </div>
+                        <div className="topbar-lozenge-user">
+                            {`${Doc.CurrentUserEmail}`}
+                            <div className="topbar-logoff" onClick={() => window.location.assign(Utils.prepend("/logout"))}>
+                                Logoff
+                        </div>
                         </div>
                     </div>
-                </div>
 
+                </div >
             </div >
-        </div >
-    );
+        );
+    }
 }
\ No newline at end of file
diff --git a/tslint.json b/tslint.json
index 0056f4266..83255a798 100644
--- a/tslint.json
+++ b/tslint.json
@@ -1,6 +1,9 @@
 {
     "linterOptions": {
-        "exclude": ["./src/client/northstar/**", "**/*.js"]
+        "exclude": [
+            "./src/client/northstar/**",
+            "**/*.js"
+        ]
     },
     "rules": {
         "no-return-await": true,
@@ -23,41 +26,7 @@
         ],
         "no-tautology-expression": true,
         "unnecessary-constructor": true
-        // "trailing-comma": [
-        //     true,
-        //     {
-        //         "multiline": "always",
-        //         "singleline": "never"
-        //     }
-        // ],
-        // "ordered-imports": true
-        // "quotemark": [
-        //     true,
-        //     "double",
-        //     "jsx-double",
-        //     "avoid-template",
-        //     "avoid-escape"
-        // ],
-        // "object-literal-shorthand": true,
-        // "object-literal-sort-keys": true,
-        // "align": [
-        //     true,
-        //     "parameters",
-        //     "arguments",
-        //     "statements",
-        //     "members",
-        //     "elements"
-        // ],
-        // "no-void-expression": [
-        //     true,
-        //     "ignore-arrow-function-shorthand"
-        // ],
-        // "no-non-null-assertion": true,
-        // "no-var-keyword": true,
-        // "no-var-requires": true,
     },
     "defaultSeverity": "warning",
-    "jsRules": {
-
-    }
+    "jsRules": {}
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

