From a3eab5f2b8eca6ff7a21ea9d043b90c953c35f03 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 26 Mar 2025 16:36:15 -0400
Subject: fix so that views use don't use the rootDocument, but rather the
 current rendering document.  got rid of resolvedDataDoc -- just use
 rootDocument[DocData]

---
 .../collections/collectionMulticolumn/CollectionMultirowView.tsx     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bda8e91ac..f95928cf6 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -2,7 +2,7 @@ import { action, computed, makeObservable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { dropActionType } from '../../../util/DropActionTypes';
 import { Transform } from '../../../util/Transform';
@@ -11,6 +11,7 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'
 import './CollectionMultirowView.scss';
 import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
+import { DocData } from '../../../../fields/DocSymbols';
 
 interface HeightSpecifier {
     magnitude: number;
@@ -253,7 +254,7 @@ export class CollectionMultirowView extends CollectionSubView() {
         return (
             <DocumentView
                 Document={layout}
-                TemplateDataDocument={layout.resolvedDataDoc as Doc}
+                TemplateDataDocument={DocCast(layout.rootDocument)?.[DocData]}
                 styleProvider={this._props.styleProvider}
                 containerViewPath={this.childContainerViewPath}
                 LayoutTemplate={this._props.childLayoutTemplate}
-- 
cgit v1.2.3-70-g09d2


From b0bb28202fa77556768d1da93bf9ea879c6ba2e5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 10 Apr 2025 12:05:55 -0400
Subject: performance fixes for text boxes to not call screenToLocal
 unnecessarily.  simplifications to template data docs

---
 src/client/views/DocumentDecorations.scss          |   2 +-
 src/client/views/DocumentDecorations.tsx           |   2 +-
 src/client/views/StyleProvider.tsx                 |  24 +++--
 src/client/views/TagsView.scss                     |   3 +
 .../views/collections/CollectionCarouselView.scss  |   2 +
 .../views/collections/CollectionCarouselView.tsx   |  14 ++-
 .../views/collections/CollectionNoteTakingView.tsx |   6 +-
 .../views/collections/CollectionStackingView.tsx   |  13 ++-
 src/client/views/collections/CollectionSubView.tsx |   7 +-
 .../views/collections/CollectionTreeView.tsx       |  14 +--
 .../collectionGrid/CollectionGridView.tsx          |  11 +--
 .../CollectionMulticolumnView.tsx                  | 106 ++++++++++-----------
 .../CollectionMultirowView.tsx                     | 106 ++++++++++-----------
 src/client/views/nodes/DocumentView.scss           |   6 ++
 src/client/views/nodes/DocumentView.tsx            |  87 ++++++++++-------
 src/client/views/nodes/FieldView.tsx               |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  16 ++--
 .../formattedText/ProsemirrorExampleTransfer.ts    |   3 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |   2 +-
 19 files changed, 229 insertions(+), 197 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 28cebe23c..09a13634f 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -40,10 +40,10 @@ $resizeHandler: 8px;
     }
     .documentDecorations-tagsView {
         position: absolute;
-        height: 100%;
         width: 100%;
         pointer-events: all;
         border-radius: 50%;
+        top: 30; // offset by height of documentButtonBar so that items can be clicked without overlap interference
         color: black;
     }
 }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 452dd60ee..0756d3d9e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -863,7 +863,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                             <div
                                 className="documentDecorations-tagsView"
                                 style={{
-                                    top: 30, // offset by height of documentButtonBar so that items can be clicked without overlap interference
+                                    display: DocumentView.Selected().length > 1 || !seldocview.showTags ? 'none' : undefined,
                                     transform: `translate(${-this._resizeBorderWidth + 10}px, ${2 * this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
                                 }}>
                                 {DocumentView.Selected().length > 1 ? <TagsView Views={DocumentView.Selected()} background={SnappingManager.userBackgroundColor ?? ''} /> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index a3067907d..e8876f96f 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -327,7 +327,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                         ? undefined // if it's a background & has a cluster color, make the shadow spread really big
                         : fieldKey.includes('_inline')  // if doc is an inline document in a text box
                         ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0vw 0vw 0.1vw')}`
-                        :doc.rootDocument !== doc.embedContainer && DocCast(doc.embedContainer)?.type === DocumentType.RTF && !isInk() // if doc is embedded in a text document (but not an inline) and this isn't a simple text template (where the layoutDoc's rootDocument is its embed container)
+                        : doc.rootDocument !== doc.embedContainer && DocCast(doc.embedContainer)?.type === DocumentType.RTF && !isInk() // if doc is embedded in a text document (but not an inline) and this isn't a simple text template (where the layoutDoc's rootDocument is its embed container)
                         ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
                         : StrCast(doc.layout_boxShadow, '');
             }
@@ -342,25 +342,28 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             if (isDocumentActive?.()) return isInk() ? 'visiblePainted' : 'all';
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations: {
-            const lock = () => doc?.pointerEvents !== 'none' ? null : (
+            const showLock = doc?.pointerEvents === 'none'
+            const lock = () =>  !showLock ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                             <FontAwesomeIcon icon='lock' size="lg" />
                         </div>
                     );
-            const paint = () => !doc?.onPaint ? null : (
+            const showPaint = doc?.onPaint;
+            const paint = () => !showPaint ? null : (
                         <div className={`styleProvider-paint${isSelected?.() ? "-selected":""}`} onClick={e => togglePaintView(e, doc, props)}>
                             <FontAwesomeIcon icon='pen' size="lg" />
                         </div>
                     );
+            const showFilterIcon =
+                StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
+                    ? 'green' // #18c718bd' //'hasFilter'
+                    : childFilters?.().filter(f => ClientUtils.IsRecursiveFilter(f) && f !== ClientUtils.noDragDocsFilter).length || childFiltersByRanges?.().length
+                    ? 'orange' // 'inheritsFilter'
+                    : undefined;
+            const showFilter = showFilterIcon && !hideFilterStatus;
             const filter = () => {
                 const dashView = untracked(() => DocumentView.getDocumentView(Doc.ActiveDashboard));
-                const showFilterIcon =
-                    StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
-                        ? 'green' // #18c718bd' //'hasFilter'
-                        : childFilters?.().filter(f => ClientUtils.IsRecursiveFilter(f) && f !== ClientUtils.noDragDocsFilter).length || childFiltersByRanges?.().length
-                        ? 'orange' // 'inheritsFilter'
-                        : undefined;
-                return !showFilterIcon || hideFilterStatus ? null : (
+                return !showFilter ? null : (
                     <div className="styleProvider-filter">
                         <Dropdown
                             type={Type.TERT}
@@ -394,6 +397,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             };
         
             return (
+                !showPaint && !showLock && !showFilter ? null:
                 <>
                     {paint()}
                     {lock()}
diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss
index d58b55ab5..a940502d4 100644
--- a/src/client/views/TagsView.scss
+++ b/src/client/views/TagsView.scss
@@ -16,6 +16,9 @@
                 min-height: unset !important;
             }
         }
+        .tagsView-editing-box {
+            pointer-events: all;
+        }
     }
 }
 
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index 1080aa703..962b590c8 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -9,6 +9,8 @@
         height: 50;
         display: inline-block;
         width: 100%;
+        bottom: 0;
+        position: absolute;
     }
     .collectionCarouselView-image {
         height: calc(100% - 50px);
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index c80ac23eb..2d3f8cb0e 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -16,7 +16,6 @@ import { FocusViewOptions } from '../nodes/FocusViewOptions';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import './CollectionCarouselView.scss';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-import { DocData } from '../../../fields/DocSymbols';
 
 @observer
 export class CollectionCarouselView extends CollectionSubView() {
@@ -116,12 +115,14 @@ export class CollectionCarouselView extends CollectionSubView() {
                 ? false
                 : undefined; // prettier-ignore
     onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
+
     renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => {
         return (
             <DocumentView
                 {...this._props}
                 ref={overlayFunc}
                 Document={doc}
+                TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined}
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
                 fitWidth={this._props.childLayoutFitWidth}
@@ -137,7 +138,6 @@ export class CollectionCarouselView extends CollectionSubView() {
                 renderDepth={this._props.renderDepth + 1}
                 LayoutTemplate={this._props.childLayoutTemplate}
                 LayoutTemplateString={this._props.childLayoutString}
-                TemplateDataDocument={doc[DocData]}
                 childFilters={this.childDocFilters}
                 focus={this.focus}
                 hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)}
@@ -183,7 +183,15 @@ export class CollectionCarouselView extends CollectionSubView() {
     }
 
     @computed get content() {
-        const captionProps = { ...this._props, NativeScaling: returnOne, PanelWidth: this.captionWidth, fieldKey: 'caption', setHeight: undefined, setContentView: undefined };
+        const captionProps = {
+            ...this._props, //
+            NativeScaling: returnOne,
+            PanelWidth: this.captionWidth,
+            fieldKey: 'caption',
+            setHeight: undefined,
+            setContentView: undefined,
+            noSidebar: true,
+        };
         const carouselShowsCaptions = StrCast(this.layoutDoc._layout_showCaption);
         return !this.curDoc() ? null : (
             <>
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 01695dbaf..173147f64 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -258,11 +258,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const noteTakingDocTransform = () => this.getDocTransform(doc, dref);
         return (
             <DocumentView
-                ref={r => {
-                    dref = r || undefined;
-                }}
+                ref={r => (dref = r || undefined)}
                 Document={doc}
-                TemplateDataDocument={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)}
+                TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined}
                 pointerEvents={this.blockPointerEventsWhenDragging}
                 renderDepth={this._props.renderDepth + 1}
                 PanelWidth={width}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d7cf0ffc2..4f60acb18 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -675,12 +675,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     }
 
     return35 = () => 35;
+    @computed get menuBtnDoc() { return DocCast(this.layoutDoc.layout_headerButton); } // prettier-ignore
     @computed get buttonMenu() {
-        const menuDoc = DocCast(this.layoutDoc.layout_headerButton);
-        return !menuDoc ? null : (
-            <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
+        return !this.menuBtnDoc ? null : (
+            <div className="buttonMenu-docBtn" style={{ width: NumCast(this.menuBtnDoc._width, 30), height: NumCast(this.menuBtnDoc._height, 30) }}>
                 <DocumentView
-                    Document={menuDoc}
+                    Document={this.menuBtnDoc}
                     isContentActive={this.isContentActive}
                     isDocumentActive={this.isContentActive}
                     addDocument={this._props.addDocument}
@@ -728,13 +728,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             SetValue: this.addGroup,
             contents: '+ ADD A GROUP',
         };
-        const buttonMenu = this.layoutDoc.layout_headerButton;
         const noviceExplainer = this.layoutDoc.layout_explainer;
         return (
             <>
-                {buttonMenu || noviceExplainer ? (
+                {this.menuBtnDoc || noviceExplainer ? (
                     <div className="documentButtonMenu">
-                        {buttonMenu ? this.buttonMenu : null}
+                        {this.menuBtnDoc ? this.buttonMenu : null}
                         {Doc.noviceMode && noviceExplainer ? <div className="documentExplanation">{StrCast(noviceExplainer)}</div> : null}
                     </div>
                 ) : null}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a88707c6f..375c0fe53 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -603,7 +603,12 @@ export function CollectionSubView<X>() {
          */
         @computed get uiBtnScaling() { return this.maxWidgetSize / this._sideBtnWidth; } // prettier-ignore
 
-        screenXPadding = () => (this.uiBtnScaling * this._sideBtnWidth - NumCast(this.layoutDoc.xMargin)) / this._props.ScreenToLocalTransform().Scale;
+        screenXPadding = (docView?: DocumentView) => {
+            if (!docView) return 0;
+            const diff = this._props.PanelWidth() - docView.PanelWidth();
+            const xpad1 = this.uiBtnScaling * (this._sideBtnWidth - NumCast(this.layoutDoc.xMargin)) - diff / 2; // this._sideBtnWidth;
+            return xpad1 / (docView.NativeDimScaling?.() || 1);
+        };
         filteredChildDocs = () => this.childLayoutPairs.map(pair => pair.layout);
         childDocsFunc = () => this.childDocs;
         @action setFilterFunc = (func?: (doc: Doc) => boolean) => { this._filterFunc = func; }; // prettier-ignore
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 418c437d5..962fbdcd7 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -8,7 +8,7 @@ import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction, Utils } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
@@ -200,7 +200,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     onContextMenu = (): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
         const layoutItems: ContextMenuProps[] = [];
-        const menuDoc = ScriptCast(Cast(this.layoutDoc.layout_headerButton, Doc, null)?.onClick)?.script.originalScript === CollectionTreeView.AddTreeFunc;
+        const menuDoc = ScriptCast(this.menuBtnDoc?.onClick)?.script.originalScript === CollectionTreeView.AddTreeFunc;
         menuDoc && layoutItems.push({ description: 'Create new folder', event: () => CollectionTreeView.addTreeFolder(this.Document), icon: 'paint-brush' });
         if (!Doc.noviceMode) {
             layoutItems.push({
@@ -347,14 +347,14 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     }
 
     return35 = () => 35;
+    @computed get menuBtnDoc() { return DocCast(this.layoutDoc.layout_headerButton); } // prettier-ignore
     @computed get buttonMenu() {
-        const menuDoc = Cast(this.layoutDoc.layout_headerButton, Doc, null);
         // To create a multibutton menu add a CollectionLinearView
-        return !menuDoc ? null : (
-            <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
+        return !this.menuBtnDoc ? null : (
+            <div className="buttonMenu-docBtn" style={{ width: NumCast(this.menuBtnDoc._width, 30), height: NumCast(this.menuBtnDoc._height, 30) }}>
                 <DocumentView
-                    Document={menuDoc}
-                    TemplateDataDocument={menuDoc}
+                    Document={this.menuBtnDoc}
+                    TemplateDataDocument={this.menuBtnDoc}
                     isContentActive={this._props.isContentActive}
                     isDocumentActive={returnTrue}
                     addDocument={this._props.addDocument}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 8393c719b..a7603a45b 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { returnFalse, returnZero, setupMoveUpEvents } from '../../../../ClientUtils';
 import { Doc, Opt } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
-import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
@@ -16,7 +16,6 @@ import { DocumentView } from '../../nodes/DocumentView';
 import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
 import './CollectionGridView.scss';
 import Grid, { Layout } from './Grid';
-import { DocData } from '../../../../fields/DocSymbols';
 
 @observer
 export class CollectionGridView extends CollectionSubView() {
@@ -183,17 +182,17 @@ export class CollectionGridView extends CollectionSubView() {
     isChildContentActive = () => (this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) ? true : undefined);
     /**
      *
-     * @param layout
+     * @param childLayout
      * @param dxf the x- and y-translations of the decorations box as a transform i.e. this.lookupIndividualTransform
      * @param width
      * @param height
      * @returns the `ContentFittingDocumentView` of the node
      */
-    getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => (
+    getDisplayDoc = (childLayout: Doc, dxf: () => Transform, width: () => number, height: () => number) => (
         <DocumentView
             {...this._props}
-            Document={layout}
-            TemplateDataDocument={DocCast(layout.rootDocument)?.[DocData]}
+            Document={childLayout}
+            TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
             NativeWidth={returnZero}
             NativeHeight={returnZero}
             fitWidth={this._props.childLayoutFitWidth}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index f27398427..42b093cc7 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { FaChevronRight } from 'react-icons/fa';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SettingsManager } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
@@ -18,7 +18,7 @@ import ResizeBar from './MulticolumnResizer';
 import WidthLabel from './MulticolumnWidthLabel';
 import { dropActionType } from '../../../util/DropActionTypes';
 import { SnappingManager } from '../../../util/SnappingManager';
-import { DocData } from '../../../../fields/DocSymbols';
+import { computedFn } from 'mobx-utils';
 
 interface WidthSpecifier {
     magnitude: number;
@@ -198,15 +198,14 @@ export class CollectionMulticolumnView extends CollectionSubView() {
      * documents before the target.
      */
     private lookupIndividualTransform = (layout: Doc) => {
-        if (this.columnUnitLength === undefined) {
-            return Transform.Identity(); // we're still waiting on promises to resolve
-        }
-        let offset = 0;
-        for (const { layout: candidate } of this.childLayoutPairs) {
-            if (candidate === layout) {
-                return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0);
+        if (this.columnUnitLength !== undefined) {
+            let offset = 0;
+            for (const { layout: candidate } of this.childLayoutPairs) {
+                if (candidate === layout) {
+                    return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0);
+                }
+                offset += this.lookupPixels(candidate) + resizerWidth;
             }
-            offset += this.lookupPixels(candidate) + resizerWidth;
         }
         return Transform.Identity();
     };
@@ -262,50 +261,51 @@ export class CollectionMulticolumnView extends CollectionSubView() {
               ? true
               : undefined;
     };
-    getDisplayDoc = (childLayout: Doc) => {
-        const width = () => this.lookupPixels(childLayout);
-        const height = () => this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0);
-        const dxf = () =>
-            this.lookupIndividualTransform(childLayout)
+    childHeight = () => this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0);
+    childWidth = computedFn((childDoc: Doc) => () => this.lookupPixels(childDoc));
+    childXf = computedFn(
+        (childDoc: Doc) => () =>
+            this.lookupIndividualTransform(childDoc)
                 .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin))
-                .scale(this._props.NativeDimScaling?.() || 1);
-        return (
-            <DocumentView
-                Document={childLayout}
-                TemplateDataDocument={DocCast(childLayout.rootDocument)?.[DocData]}
-                styleProvider={this._props.styleProvider}
-                containerViewPath={this.childContainerViewPath}
-                LayoutTemplate={this._props.childLayoutTemplate}
-                LayoutTemplateString={this._props.childLayoutString}
-                renderDepth={this._props.renderDepth + 1}
-                PanelWidth={width}
-                PanelHeight={height}
-                rootSelected={this.rootSelected}
-                dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
-                onClickScript={this.onChildClickHandler}
-                onDoubleClickScript={this.onChildDoubleClickHandler}
-                suppressSetHeight
-                ScreenToLocalTransform={dxf}
-                isContentActive={this.isChildContentActive}
-                isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
-                hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
-                hideDecorationTitle={this._props.childHideDecorationTitle}
-                fitContentsToBox={this._props.fitContentsToBox}
-                focus={this._props.focus}
-                childFilters={this.childDocFilters}
-                childFiltersByRanges={this.childDocRangeFilters}
-                searchFilterDocs={this.searchFilterDocs}
-                dontRegisterView={this._props.dontRegisterView}
-                addDocument={this._props.addDocument}
-                moveDocument={this._props.moveDocument}
-                removeDocument={this._props.removeDocument}
-                whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
-                addDocTab={this._props.addDocTab}
-                pinToPres={this._props.pinToPres}
-                dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
-            />
-        );
-    };
+                .scale(this._props.NativeDimScaling?.() || 1)
+    );
+    getDisplayDoc = (childLayout: Doc) => (
+        <DocumentView
+            Document={childLayout}
+            TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
+            styleProvider={this._props.styleProvider}
+            containerViewPath={this.childContainerViewPath}
+            LayoutTemplate={this._props.childLayoutTemplate}
+            LayoutTemplateString={this._props.childLayoutString}
+            renderDepth={this._props.renderDepth + 1}
+            PanelWidth={this.childWidth(childLayout)}
+            PanelHeight={this.childHeight}
+            rootSelected={this.rootSelected}
+            dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+            onClickScript={this.onChildClickHandler}
+            onDoubleClickScript={this.onChildDoubleClickHandler}
+            suppressSetHeight
+            ScreenToLocalTransform={this.childXf(childLayout)}
+            isContentActive={this.isChildContentActive}
+            isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+            hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
+            hideDecorationTitle={this._props.childHideDecorationTitle}
+            fitContentsToBox={this._props.fitContentsToBox}
+            focus={this._props.focus}
+            childFilters={this.childDocFilters}
+            childFiltersByRanges={this.childDocRangeFilters}
+            searchFilterDocs={this.searchFilterDocs}
+            dontRegisterView={this._props.dontRegisterView}
+            addDocument={this._props.addDocument}
+            moveDocument={this._props.moveDocument}
+            removeDocument={this._props.removeDocument}
+            whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+            addDocTab={this._props.addDocTab}
+            pinToPres={this._props.pinToPres}
+            dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
+        />
+    );
+
     /**
      * @returns the resolved list of rendered child documents, displayed
      * at their resolved pixel widths, each separated by a resizer.
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index f95928cf6..6bbe55f54 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -2,7 +2,7 @@ import { action, computed, makeObservable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { dropActionType } from '../../../util/DropActionTypes';
 import { Transform } from '../../../util/Transform';
@@ -11,7 +11,7 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'
 import './CollectionMultirowView.scss';
 import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
-import { DocData } from '../../../../fields/DocSymbols';
+import { computedFn } from 'mobx-utils';
 
 interface HeightSpecifier {
     magnitude: number;
@@ -179,16 +179,14 @@ export class CollectionMultirowView extends CollectionSubView() {
      * documents before the target.
      */
     private lookupIndividualTransform = (layout: Doc) => {
-        if (this.rowUnitLength === undefined) {
-            return Transform.Identity(); // we're still waiting on promises to resolve
-        }
-        let offset = 0;
-        // eslint-disable-next-line no-restricted-syntax
-        for (const { layout: candidate } of this.childLayoutPairs) {
-            if (candidate === layout) {
-                return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1));
+        if (this.rowUnitLength !== undefined) {
+            let offset = 0;
+            for (const { layout: candidate } of this.childLayoutPairs) {
+                if (candidate === layout) {
+                    return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1));
+                }
+                offset += this.lookupPixels(candidate) + resizerHeight;
             }
-            offset += this.lookupPixels(candidate) + resizerHeight;
         }
         return Transform.Identity(); // type coersion, this case should never be hit
     };
@@ -244,49 +242,51 @@ export class CollectionMultirowView extends CollectionSubView() {
               ? true
               : undefined;
     };
-    getDisplayDoc = (layout: Doc) => {
-        const height = () => this.lookupPixels(layout);
-        const width = () => this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0);
-        const dxf = () =>
-            this.lookupIndividualTransform(layout)
+    childHeight = computedFn((childDoc: Doc) => () => this.lookupPixels(childDoc));
+    childWidth = () => this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0);
+    childXf = computedFn(
+        (childDoc: Doc) => () =>
+            this.lookupIndividualTransform(childDoc)
                 .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin))
-                .scale(this._props.NativeDimScaling?.() || 1);
-        return (
-            <DocumentView
-                Document={layout}
-                TemplateDataDocument={DocCast(layout.rootDocument)?.[DocData]}
-                styleProvider={this._props.styleProvider}
-                containerViewPath={this.childContainerViewPath}
-                LayoutTemplate={this._props.childLayoutTemplate}
-                LayoutTemplateString={this._props.childLayoutString}
-                renderDepth={this._props.renderDepth + 1}
-                PanelWidth={width}
-                PanelHeight={height}
-                rootSelected={this.rootSelected}
-                dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
-                onClickScript={this.onChildClickHandler}
-                onDoubleClickScript={this.onChildDoubleClickHandler}
-                ScreenToLocalTransform={dxf}
-                isContentActive={this.isChildContentActive}
-                isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
-                hideResizeHandles={!!(layout.layout_fitWidth || this._props.childHideResizeHandles)}
-                hideDecorationTitle={this._props.childHideDecorationTitle}
-                fitContentsToBox={this._props.fitContentsToBox}
-                focus={this._props.focus}
-                childFilters={this.childDocFilters}
-                childFiltersByRanges={this.childDocRangeFilters}
-                searchFilterDocs={this.searchFilterDocs}
-                dontRegisterView={this._props.dontRegisterView}
-                addDocument={this._props.addDocument}
-                moveDocument={this._props.moveDocument}
-                removeDocument={this._props.removeDocument}
-                whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
-                addDocTab={this._props.addDocTab}
-                pinToPres={this._props.pinToPres}
-                dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'y' | 'x' | 'xy'}
-            />
-        );
-    };
+                .scale(this._props.NativeDimScaling?.() || 1)
+    );
+
+    getDisplayDoc = (childLayout: Doc) => (
+        <DocumentView
+            Document={childLayout}
+            TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
+            styleProvider={this._props.styleProvider}
+            containerViewPath={this.childContainerViewPath}
+            LayoutTemplate={this._props.childLayoutTemplate}
+            LayoutTemplateString={this._props.childLayoutString}
+            renderDepth={this._props.renderDepth + 1}
+            PanelWidth={this.childWidth}
+            PanelHeight={this.childHeight(childLayout)}
+            rootSelected={this.rootSelected}
+            dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+            onClickScript={this.onChildClickHandler}
+            onDoubleClickScript={this.onChildDoubleClickHandler}
+            ScreenToLocalTransform={this.childXf(childLayout)}
+            isContentActive={this.isChildContentActive}
+            isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+            hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
+            hideDecorationTitle={this._props.childHideDecorationTitle}
+            fitContentsToBox={this._props.fitContentsToBox}
+            focus={this._props.focus}
+            childFilters={this.childDocFilters}
+            childFiltersByRanges={this.childDocRangeFilters}
+            searchFilterDocs={this.searchFilterDocs}
+            dontRegisterView={this._props.dontRegisterView}
+            addDocument={this._props.addDocument}
+            moveDocument={this._props.moveDocument}
+            removeDocument={this._props.removeDocument}
+            whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+            addDocTab={this._props.addDocTab}
+            pinToPres={this._props.pinToPres}
+            dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'y' | 'x' | 'xy'}
+        />
+    );
+
     /**
      * @returns the resolved list of rendered child documents, displayed
      * at their resolved pixel widths, each separated by a resizer.
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index f60f33608..5ac66f2cd 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -277,6 +277,12 @@
     bottom: 0;
     pointer-events: none;
 }
+.documentView-widgetDecorations {
+    transform-origin: top right;
+    position: absolute;
+    top: 0;
+    right: 0;
+}
 
 .documentView-editorView-history {
     position: absolute;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b03dd3944..bec5ea5c1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -712,6 +712,54 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
 
     aiContentsWidth = () => (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1);
     aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling);
+    aiEditor = () => (
+        <>
+            <div
+                className="documentView-editorView-history"
+                ref={r => this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))}
+                style={{
+                    transform: `scale(${this.uiBtnScaling})`,
+                    height: this.aiContentsHeight() / this.uiBtnScaling,
+                    width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling,
+                }}>
+                {this._componentView?.componentAIViewHistory?.() ?? null}
+            </div>
+            <div
+                className="documentView-editorView"
+                style={{
+                    background: SnappingManager.userVariantColor,
+                    width: `${100 / this.uiBtnScaling}%`, //
+                    transform: `scale(${this.uiBtnScaling})`,
+                }}
+                ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
+                <div className="documentView-editorView-resizer" />
+                {this._componentView?.componentAIView?.() ?? null}
+                {this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
+            </div>
+        </>
+    );
+    @computed get tagsOverlay() {
+        return (
+            <div
+                className="documentView-noAiWidgets"
+                style={{
+                    width: `${100 / this.uiBtnScaling}%`, //
+                    transform: `scale(${this.uiBtnScaling})`,
+                    height: Number.isNaN(this.maxWidgetSize) ? undefined : this.TagsBtnHeight * this.uiBtnScaling,
+                }}>
+                {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
+            </div>
+        );
+    }
+    tagsOverlayFunc = () => (this._props.DocumentView?.().showTags ? this.tagsOverlay : null);
+    @computed get widgetOverlay() {
+        return (
+            <div className="documentView-widgetDecorations" style={{ transform: `scale(${this.uiBtnScaling})` }}>
+                {this.widgetDecorations}
+            </div>
+        );
+    }
+    widgetOverlayFunc = () => (this.widgetDecorations ? this.widgetOverlay : null);
     @computed get viewBoxContents() {
         TraceMobx();
         const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
@@ -742,43 +790,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
                         hideClickBehaviors={BoolCast(this.Document.hideClickBehaviors)}
                     />
                 </div>
-                {!this._props.showAIEditor ? (
-                    <div
-                        className="documentView-noAiWidgets"
-                        style={{
-                            width: `${100 / this.uiBtnScaling}%`, //
-                            transform: `scale(${this.uiBtnScaling})`,
-                            height: Number.isNaN(this.maxWidgetSize) ? undefined : this.TagsBtnHeight * this.uiBtnScaling,
-                        }}>
-                        {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
-                    </div>
-                ) : (
-                    <>
-                        <div
-                            className="documentView-editorView-history"
-                            ref={r => this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))}
-                            style={{
-                                transform: `scale(${this.uiBtnScaling})`,
-                                height: this.aiContentsHeight() / this.uiBtnScaling,
-                                width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling,
-                            }}>
-                            {this._componentView?.componentAIViewHistory?.() ?? null}
-                        </div>
-                        <div
-                            className="documentView-editorView"
-                            style={{
-                                background: SnappingManager.userVariantColor,
-                                width: `${100 / this.uiBtnScaling}%`, //
-                                transform: `scale(${this.uiBtnScaling})`,
-                            }}
-                            ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
-                            <div className="documentView-editorView-resizer" />
-                            {this._componentView?.componentAIView?.() ?? null}
-                            {this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
-                        </div>
-                    </>
-                )}
-                <div style={{ transformOrigin: 'top right', transform: `scale(${this.uiBtnScaling})`, position: 'absolute', top: 0, right: 0 }}>{this.widgetDecorations ?? null}</div>
+                {this._props.showAIEditor ? this.aiEditor() : this.tagsOverlayFunc()}
+                {this.widgetOverlayFunc()}
             </>
         );
     }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 74059bd12..ad6d93d43 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -50,7 +50,7 @@ export interface FieldViewSharedProps {
     TemplateDataDocument?: Doc;
     renderDepth: number;
     scriptContext?: unknown; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
-    screenXPadding?: () => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView)
+    screenXPadding?: (view: DocumentView | undefined) => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView)
     xPadding?: number;
     yPadding?: number;
     dontRegisterView?: boolean;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6fced76bd..a45b8a488 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -215,7 +215,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     }
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
-        const rootDoc: Doc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : DocCast(this.Document.rootDocument, this.Document);
+        const rootDoc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : this.rootDoc;
         if (!pinProps && this.EditorView?.state.selection.empty) return rootDoc;
         const anchor = Docs.Create.ConfigDocument({ title: StrCast(rootDoc.title), annotationOn: rootDoc });
         this.addDocument(anchor);
@@ -308,7 +308,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
 
     leafText = (node: Node) => {
         if (node.type === this.EditorView?.state.schema.nodes.dashField) {
-            const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
+            const refDoc = !node.attrs.docId ? this.rootDoc : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
             const fieldKey = StrCast(node.attrs.fieldKey);
             return (
                 (node.attrs.hideKey ? '' : fieldKey + ':') + //
@@ -316,7 +316,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             );
         }
         if (node.type === this.EditorView?.state.schema.nodes.dashDoc) {
-            const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
+            const refDoc = !node.attrs.docId ? this.rootDoc : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
             return refDoc[ToString]();
         }
         return '';
@@ -1522,8 +1522,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             this._editorView.TextView = this;
         }
 
-        const selectOnLoad =
-            Doc.AreProtosEqual(this._props.TemplateDataDocument ?? DocCast(this.Document.rootDocument, this.Document), DocumentView.SelectOnLoad) && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()));
+        const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.rootDoc, DocumentView.SelectOnLoad) && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()));
         const selLoadChar = FormattedTextBox.SelectOnLoadChar;
         if (selectOnLoad) {
             DocumentView.SetSelectOnLoad(undefined);
@@ -2102,11 +2101,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         const rounded = StrCast(this.layoutDoc._layout_borderRounding) === '100%' ? '-rounded' : '';
         setTimeout(() => !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
 
-        const scrSize = (which: number, view = this._props.docViewPath().slice(-which)[0]) => 
-                [view?._props.PanelWidth() /(view?.screenToLocalScale()??1), view?._props.PanelHeight() / (view?.screenToLocalScale()??1)]; // prettier-ignore
-        const scrMargin = [Math.max(0, (scrSize(2)[0] - scrSize(1)[0]) / 2), Math.max(0, (scrSize(2)[1] - scrSize(1)[1]) / 2)];
-        const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), this._props.xPadding ?? 0, 0, ((this._props.screenXPadding?.() ?? 0) - scrMargin[0]) * this.ScreenToLocalBoxXf().Scale);
-        const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, ((this._props.yPadding ?? 0) - scrMargin[1]) * this.ScreenToLocalBoxXf().Scale);
+        const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), 0, this._props.xPadding ?? 0, this._props.screenXPadding?.(this._props.DocumentView?.()) ?? 0);
+        const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, this._props.yPadding ?? 0); // prettier-ignore
         const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props.  e.g., <FormattedTextBox height='{this._header_height}px' >
         return this.isLabel ? (
             <LabelBox {...this._props} />
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index eabc6455f..7ae1fc202 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -50,8 +50,7 @@ export function buildKeymap<S extends Schema<string>>(schema: S, tbox?: Formatte
 
     const canEdit = (state: EditorState) => {
         if (!tbox) return true;
-        const permissions = GetEffectiveAcl(tbox._props.TemplateDataDocument ?? tbox.Document[DocData]);
-        switch (permissions) {
+        switch (GetEffectiveAcl(tbox.dataDoc)) {
             case AclAugment:
                 {
                     // previously used hack: (state.selection as any).$cursor.nodeBefore;
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 31cd1603f..7e0375275 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -67,7 +67,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // Since this node is being rendered with a template, this method retrieves
     // the actual slide being rendered from the auto-generated rendering template
     @computed get slideDoc() {
-        return DocCast(this.Document.rootDocument, this.Document);
+        return this.rootDoc;
     }
 
     // this is the document in the workspaces that is targeted by the slide
-- 
cgit v1.2.3-70-g09d2


From 463cd15186a3463897d977bfa11af5c4929798ae Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 10 Apr 2025 12:13:05 -0400
Subject: from last

---
 .../collectionMulticolumn/CollectionMulticolumnView.tsx           | 8 ++++----
 .../collections/collectionMulticolumn/CollectionMultirowView.tsx  | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 42b093cc7..adaceb053 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,14 +1,17 @@
+import { Button, IconButton } from '@dash/components';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@mui/material';
-import { Button, IconButton } from '@dash/components';
 import { action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
 import * as React from 'react';
 import { FaChevronRight } from 'react-icons/fa';
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
+import { dropActionType } from '../../../util/DropActionTypes';
 import { SettingsManager } from '../../../util/SettingsManager';
+import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoable } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
@@ -16,9 +19,6 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'
 import './CollectionMulticolumnView.scss';
 import ResizeBar from './MulticolumnResizer';
 import WidthLabel from './MulticolumnWidthLabel';
-import { dropActionType } from '../../../util/DropActionTypes';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { computedFn } from 'mobx-utils';
 
 interface WidthSpecifier {
     magnitude: number;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 6bbe55f54..27c41583c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,5 +1,6 @@
 import { action, computed, makeObservable } from 'mobx';
 import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -11,7 +12,6 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'
 import './CollectionMultirowView.scss';
 import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
-import { computedFn } from 'mobx-utils';
 
 interface HeightSpecifier {
     magnitude: number;
-- 
cgit v1.2.3-70-g09d2

