From b420caf2c7ecd386cae2cc550904522474b541aa Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 26 Mar 2024 22:34:10 -0400
Subject: added empty image tool and click on empty image to select from
 filesystem.   fixed following links in lightbox and showing links to
 stackedTimelines.  fixed embedding docs into text.  fixed not resizing text
 boxes that also show up in pivot view.  prevent context menu from going off
 top of screen.   fixed freeform clustering colors and click to type. fixed
 links to stackedTimeline marks, and titles for marks.  made title editing
 from doc deco and header use same syntax as keyValue.  fixed marquee
 selection on webBoxes.  turn off transitions in freeformdocview after
 timeout. enabled iconifying templates to propagate to "offspring".  fixes
 images in templates.  don't show headr on schema views.

---
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1fd453e96..5495735ea 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -565,7 +565,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     clusterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
         let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props'  used to be renderDepth + 1
         if (doc && this.childDocList?.includes(doc))
-            switch (property) {
+            switch (property.split(':')[0]) {
                 case StyleProp.BackgroundColor:
                     const cluster = NumCast(doc?.layout_cluster);
                     if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) {
@@ -590,7 +590,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
 
     trySelectCluster = (addToSel: boolean) => {
-        if (this._hitCluster !== -1) {
+        if (addToSel && this._hitCluster !== -1) {
             !addToSel && SelectionManager.DeselectAll();
             const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
             this.selectDocuments(eles);
@@ -1288,15 +1288,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const rotation = Cast(_rotation,'number',
             !this.layoutDoc._rotation_jitter ? null
                 : NumCast(this.layoutDoc._rotation_jitter) * random(-1, 1, NumCast(x), NumCast(y)) );
+        const childProps = { ...this._props, styleProvider: this.clusterStyleProvider };
         return {
             x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x),
             y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y),
             z: Cast(z, 'number'),
             autoDim,
             rotation,
-            color: Cast(color, 'string') ? StrCast(color) : this._props.styleProvider?.(childDoc, this._props, StyleProp.Color),
-            backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, this._props, StyleProp.BackgroundColor),
-            opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this._props.styleProvider?.(childDoc, this._props, StyleProp.Opacity),
+            color: Cast(color, 'string') ? StrCast(color) : this.clusterStyleProvider(childDoc, childProps, StyleProp.Color),
+            backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, childProps, StyleProp.BackgroundColor),
+            opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this.clusterStyleProvider?.(childDoc, childProps, StyleProp.Opacity),
             zIndex: Cast(zIndex, 'number'),
             width: _width,
             height: _height,
-- 
cgit v1.2.3-70-g09d2


From ad1b41beaa0c55487d41381bddd80ab1a76e7fb5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 30 Mar 2024 00:36:19 -0400
Subject: added Labels button for turning ink labels on/off.  added Pixels and
 Rotate buttons for images.  enabled ink as template for text : check for ink
 stroke data on layout doc if it's not on data doc & started to have style
 provider check for properties on layout doc instead of data (background
 color, boxShadow).   fixed toggling key/value on and off when node is
 selected.

---
 src/client/documents/Documents.ts                  |  2 ++
 src/client/util/CurrentUserUtils.ts                | 16 ++++++++---
 src/client/views/InkControlPtHandles.tsx           |  4 +--
 src/client/views/InkingStroke.tsx                  | 12 ++++++--
 src/client/views/StyleProvider.tsx                 | 17 ++++++------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  4 +--
 src/client/views/global/globalScripts.ts           | 21 ++++++++++++--
 src/client/views/nodes/DocumentView.scss           |  1 -
 src/client/views/nodes/MapBox/MapBox.tsx           |  3 ++
 .../views/nodes/formattedText/DashFieldView.tsx    | 32 ++++++++++------------
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 .../views/nodes/formattedText/RichTextRules.ts     |  3 +-
 src/client/views/nodes/formattedText/nodes_rts.ts  |  1 -
 13 files changed, 74 insertions(+), 44 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6275de405..6965ae0ce 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1804,10 +1804,12 @@ export namespace DocUtils {
         const iconViews = DocListCast(Cast(Doc.UserDoc()['template_icons'], Doc, null)?.data);
         const templBtns = DocListCast(Cast(Doc.UserDoc()['template_buttons'], Doc, null)?.data);
         const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
+        const userTypes = DocListCast(Cast(Doc.UserDoc()['template_user'], Doc, null)?.data);
         const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
         const allTemplates = iconViews
             .concat(templBtns)
             .concat(noteTypes)
+            .concat(userTypes)
             .concat(clickFuncs)
             .map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc)
             .filter(doc => doc.isTemplateDoc);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 90368c1eb..3855bdeb6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -764,6 +764,7 @@ pie title Minerals in my tap water
             { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square",     toolType:GestureUtils.Gestures.Rectangle,   scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
             { title: "Line",   toolTip: "Line (double tap to lock mode)",   btnType: ButtonType.ToggleButton, icon: "minus",      toolType:GestureUtils.Gestures.Line,        scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
             { title: "Mask",   toolTip: "Mask",                             btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask",                        scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } },
+            { title: "Labels", toolTip: "Lab els",                          btnType: ButtonType.ToggleButton, icon: "text-width", toolType: "labels",                         scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, },
             { title: "Width",  toolTip: "Stroke width",                     btnType: ButtonType.NumberSliderButton,               toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1},
             { title: "Ink",    toolTip: "Stroke color",                     btnType: ButtonType.ColorButton,  icon: "pen",        toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} },
         ];
@@ -772,7 +773,7 @@ pie title Minerals in my tap water
     static schemaTools():Button[] {
         return [
             {title: "Preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, icon: "portrait", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'} },
-            {title: "1 Line",  toolTip: "Single Line Rows",       btnType: ButtonType.ToggleButton, icon: "eye", scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} },
+            {title: "1 Line",  toolTip: "Single Line Rows",       btnType: ButtonType.ToggleButton, icon: "eye",      scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} },
             {title: "DataViz", toolTip: "Turn Schema Table into Data Visualization Doc",       btnType: ButtonType.ClickButton, icon: "chart-bar", scripts:{ onClick: '{ datavizFromSchema()'} }, ];
     }
 
@@ -780,12 +781,18 @@ pie title Minerals in my tap water
         return [
             { title: "Back",    toolTip: "Go back",         btnType: ButtonType.ClickButton,  icon: "arrow-left",              scripts: { onClick: '{ return webBack(); }' }},
             { title: "Forward", toolTip: "Go forward",      btnType: ButtonType.ClickButton,  icon: "arrow-right",             scripts: { onClick: '{ return webForward(); }'}},
-            { title: "URL",     toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script: '{ return webSetURL(value, _readOnly_); }'} },
+            { title: "URL",     toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script:  '{ return webSetURL(value, _readOnly_); }'} },
         ];
     }
     static videoTools() {
         return [
-            { title: "Snapshot",toolTip: "Take snapshot of current frame", btnType: ButtonType.ClickButton,  icon: "camera",                  scripts: { onClick: '{ return videoSnapshot(); }' }},
+            { title: "Snapshot",toolTip: "Take snapshot of current frame", btnType: ButtonType.ClickButton,  icon: "camera",   scripts: { onClick: '{ return videoSnapshot(); }' }},
+        ];
+    }
+    static imageTools() {
+        return [
+            { title: "Pixels",toolTip: "Set Native Pixel Sizze", btnType: ButtonType.ClickButton,  icon: "portrait",  scripts: { onClick: 'imageSetPixelSize();' }},
+            { title: "Rotate",toolTip: "Rotate 90",              btnType: ButtonType.ClickButton,  icon: "redo-alt",  scripts: { onClick: 'imageRotate90();' }},
         ];
     }
     static contextMenuTools():Button[] {
@@ -810,7 +817,8 @@ pie title Minerals in my tap water
             { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
             { title: "Stack",   icon: "View",          toolTip: "Stacking tools",       subMenu: CurrentUserUtils.stackTools(),  expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
             { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
-            { title: "Video",   icon: "Video",         toolTip: "Video functions",      subMenu: CurrentUserUtils.videoTools(),  expertMode: false, toolType:DocumentType.VID,            funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
+            { title: "Video",   icon: "Video",         toolTip: "Video functions",      subMenu: CurrentUserUtils.videoTools(),  expertMode: false, toolType:DocumentType.VID,            funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
+            { title: "Image",   icon: "Image",         toolTip: "Image functions",      subMenu: CurrentUserUtils.imageTools(),  expertMode: false, toolType:DocumentType.IMG,            funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
             { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected
            ];
     }
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index 01d52135a..edc6b404b 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -239,8 +239,8 @@ export class InkEndPtHandles extends ObservableReactComponent<InkEndProps> {
         const hdl = (key: string, pt: PointData, dragFunc: (e: React.PointerEvent) => void) => (
             <circle
                 key={key}
-                cx={pt.X}
-                cy={pt.Y}
+                cx={pt?.X}
+                cy={pt?.Y}
                 r={this._props.screenSpaceLineWidth * 2}
                 fill={this._overStart ? '#aaaaaa' : '#99999977'}
                 stroke={'#00007777'}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 345309b4a..5a9f10ba4 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -217,7 +217,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
      * factor for converting between ink and screen space.
      */
     inkScaledData = () => {
-        const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+        const inkData = Cast(this.dataDoc[this.fieldKey], InkField, Cast(this.layoutDoc[this.fieldKey], InkField, null))?.inkData ?? [];
         const inkStrokeWidth = NumCast(this.layoutDoc.stroke_width, 1);
         const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
         const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
@@ -446,7 +446,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
                     {clickableLine(this.onPointerDown, isInkMask)}
                     {isInkMask ? null : inkLine}
                 </svg>
-                {!closed || (!RTFCast(this.dataDoc.text)?.Text && !this.dataDoc[this.fieldKey + '_showLabel'] && (!this._props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
+                {!closed || this.dataDoc[this.fieldKey + '_showLabel'] === false || (!RTFCast(this.dataDoc.text)?.Text && !this.dataDoc[this.fieldKey + '_showLabel'] && (!this._props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
                     <div
                         className="inkStroke-text"
                         style={{
@@ -464,7 +464,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
                             yPadding={10}
                             xPadding={10}
                             fieldKey="text"
-                            dontRegisterView={true}
+                            //dontRegisterView={true}
                             noSidebar={true}
                             dontScale={true}
                             isContentActive={this._props.isContentActive}
@@ -488,6 +488,9 @@ export function SetActiveInkColor(value: string) {
 export function SetActiveIsInkMask(value: boolean) {
     ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
 }
+export function SetActiveInkHideTextLabels(value: boolean) {
+    ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
+}
 export function SetActiveFillColor(value: string) {
     ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
 }
@@ -515,6 +518,9 @@ export function ActiveFillColor(): string {
 export function ActiveIsInkMask(): boolean {
     return BoolCast(ActiveInkPen()?.activeIsInkMask, false);
 }
+export function ActiveInkHideTextLabels(): boolean {
+    return BoolCast(ActiveInkPen().activeInkHideTextLabels, false);
+}
 export function ActiveArrowStart(): string {
     return StrCast(ActiveInkPen()?.activeArrowStart, '');
 }
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index bf6f2a4fa..8073d0842 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -89,7 +89,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
     const isNonTransparent = property.includes(':nonTransparent');
     const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent');
     const isAnnotated = property.includes(':annotated');
-    const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString;
+    const layoutDoc = doc ? Doc.Layout(doc) : doc;
+    const isInk = () => layoutDoc?._layout_isSvg && !props?.LayoutTemplateString;
     const isOpen = property.includes(':open');
     const isEmpty = property.includes(':empty');
     const boxBackground = property.includes(':box');
@@ -129,7 +130,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                         highlightStyle: doc.isGroup ? "dotted": highlightStyle,
                         highlightColor,
                         highlightIndex,
-                        highlightStroke: doc.layout_isSvg,
+                        highlightStroke: layoutDoc?.layout_isSvg,
                     };
                 }
             }
@@ -203,7 +204,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
             let docColor: Opt<string> = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?.backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
             if (doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc) docColor = StrCast(doc._backgroundColor,docColor)
             // prettier-ignore
-            switch (doc?.type) {
+            switch (layoutDoc?.type) {
                 case DocumentType.PRESELEMENT: docColor = docColor || ""; break;
                 case DocumentType.PRES:        docColor = docColor || 'transparent'; break;
                 case DocumentType.FONTICON:    docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
@@ -220,13 +221,13 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                 case DocumentType.SCREENSHOT:
                 case DocumentType.VID:         docColor = docColor || (Colors.LIGHT_GRAY); break;
                 case DocumentType.COL:
-                    docColor = docColor || (Doc.IsSystem(doc)
+                    docColor = docColor || (doc && Doc.IsSystem(doc)
                             ? SettingsManager.userBackgroundColor
-                            : doc.annotationOn
+                            : doc?.annotationOn
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?.isGroup
                             ? undefined
-                            : doc._type_collection === CollectionViewType.Stacking ?
+                            : doc?._type_collection === CollectionViewType.Stacking ?
                             (Colors.DARK_GRAY)
                             : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (Colors.MEDIUM_GRAY));
                     break;
@@ -241,7 +242,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
             if (doc.layout_boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
-            if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && !doc.layout_isSvg) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
+            if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && !layoutDoc?.layout_isSvg) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
@@ -266,7 +267,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')}`
-                        : DocCast(doc.embedContainer)?.type=== DocumentType.RTF // if doc is embedded in a text document (but not an inline)
+                        : DocCast(doc.embedContainer)?.type === DocumentType.RTF && !isInk() // if doc is embedded in a text document (but not an inline)
                         ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
                         : StrCast(doc.layout_boxShadow, '');
             }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5495735ea..c53bad509 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -649,7 +649,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                       y: B.y - inkWidth / 2,
                       _width: B.width + inkWidth,
                       _height: B.height + inkWidth,
-                      stroke_showLabel: true}, // prettier-ignore
+                      stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
                     inkWidth
                 );
                 if (Doc.ActiveTool === InkTool.Write) {
@@ -1721,7 +1721,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 horizLines.push(topLeftInScreen[1], topLeftInScreen[1] + docSize[1] / 2, topLeftInScreen[1] + docSize[1]); // horiz center line
                 vertLines.push(topLeftInScreen[0], topLeftInScreen[0] + docSize[0] / 2, topLeftInScreen[0] + docSize[0]); // right line
             });
-        SnappingManager.addSnapLines(horizLines, vertLines);
+        this.layoutDoc._freeform_snapLines && SnappingManager.addSnapLines(horizLines, vertLines);
     };
 
     incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0;
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index d785c155b..3ea7bfbcd 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -12,7 +12,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
 import { UndoManager, undoable } from '../../util/UndoManager';
 import { GestureOverlay } from '../GestureOverlay';
-import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke';
+import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm';
 // import { InkTranscription } from '../InkTranscription';
 import { DocData } from '../../../fields/DocSymbols';
@@ -21,6 +21,7 @@ import { DocumentView } from '../nodes/DocumentView';
 import { VideoBox } from '../nodes/VideoBox';
 import { WebBox } from '../nodes/WebBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
+import { ImageBox } from '../nodes/ImageBox';
 
 ScriptingGlobals.add(function IsNoneSelected() {
     return SelectionManager.Views.length <= 0;
@@ -336,15 +337,20 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean,
 ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode');
 
 // toggle: Set overlay status of selected document
-ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) {
+ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) {
     const selected = SelectionManager.Docs.lastElement() ?? Doc.UserDoc();
     // prettier-ignore
-    const map: Map<'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
+    const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
         ['inkMask', {
             checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())),
             setInk: (doc: Doc) => (doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask),
             setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()),
         }],
+        ['labels', {
+            checkResult: () => ((selected?._stroke_showLabel ? BoolCast(selected[DocData].stroke_showLabel) : ActiveInkHideTextLabels())),
+            setInk: (doc: Doc) => (doc[DocData].stroke_showLabel = !doc.stroke_showLabel),
+            setMode: () => selected?.type !== DocumentType.INK && SetActiveInkHideTextLabels(!ActiveInkHideTextLabels()),
+        }],
         ['fillColor', {
             checkResult: () => (selected?._layout_isSvg ? StrCast(selected[DocData].fillColor) : ActiveFillColor() ?? "transparent"),
             setInk: (doc: Doc) => (doc[DocData].fillColor = StrCast(value)),
@@ -399,6 +405,15 @@ ScriptingGlobals.add(function videoSnapshot() {
     selected?.Snapshot();
 });
 
+ScriptingGlobals.add(function imageSetPixelSize() {
+    const selected = SelectionManager.Views.lastElement()?.ComponentView as ImageBox;
+    selected?.setNativeSize();
+});
+ScriptingGlobals.add(function imageRotate90() {
+    const selected = SelectionManager.Views.lastElement()?.ComponentView as ImageBox;
+    selected?.rotate();
+});
+
 /** Schema
  *      toggleSchemaPreview
  **/
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 5421c1b50..4fea6b3c6 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -256,6 +256,5 @@
 
     .documentView-node:first-child {
         position: relative;
-        background: '#B59B66'; //$white;
     }
 }
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 36dad2747..b73898f59 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1161,6 +1161,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
                         <div className="mapBox-searchbar" style={{ width: `${100 / scale}%`, zIndex: 1, position: 'relative', background: 'lightGray' }}>
                             <TextField ref={this._textRef} fullWidth placeholder="Enter a location" onKeyDown={this.searchbarKeyDown} onChange={(e: any) => this.handleSearchChange(e.target.value)} />
                             <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={e => this.toggleSettings()} />
+                            <div style={{ opacity: 0 }}>
+                                <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={e => this.toggleSettings()} />
+                            </div>
                         </div>
                     )}
                     {this._settingsOpen && !this._routeToAnimate && (
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index cdfeebe66..f6ca97ee9 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -29,8 +29,8 @@ export class DashFieldView {
     root: any;
     node: any;
     tbox: FormattedTextBox;
-    @observable expanded = false;
-    Expanded = () => this.expanded;
+    @observable _nodeSelected = false;
+    NodeSelected = () => this._nodeSelected;
 
     unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview);
     constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
@@ -71,8 +71,6 @@ export class DashFieldView {
             e.stopPropagation();
         };
 
-        this.expanded = node.attrs.expanded;
-
         this.root = ReactDOM.createRoot(this.dom);
         this.root.render(
             <DashFieldViewInternal
@@ -86,7 +84,7 @@ export class DashFieldView {
                 hideKey={node.attrs.hideKey}
                 hideValue={node.attrs.hideValue}
                 editable={node.attrs.editable}
-                expanded={this.Expanded}
+                nodeSelected={this.NodeSelected}
                 dataDoc={node.attrs.dataDoc}
                 tbox={tbox}
             />
@@ -100,11 +98,11 @@ export class DashFieldView {
         });
     }
     deselectNode() {
-        runInAction(() => (this.expanded = false));
+        runInAction(() => (this._nodeSelected = false));
         this.dom.classList.remove('ProseMirror-selectednode');
     }
     selectNode() {
-        setTimeout(() => runInAction(() => (this.expanded = true)), 100);
+        setTimeout(() => runInAction(() => (this._nodeSelected = true)), 100);
         this.dom.classList.add('ProseMirror-selectednode');
     }
 }
@@ -118,7 +116,7 @@ interface IDashFieldViewInternal {
     width: number;
     height: number;
     editable: boolean;
-    expanded: () => boolean;
+    nodeSelected: () => boolean;
     dataDoc: boolean;
     node: any;
     getPos: any;
@@ -132,7 +130,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
     _fieldKey: string;
     _fieldRef = React.createRef<HTMLDivElement>();
     @observable _dashDoc: Doc | undefined = undefined;
-    @observable _expanded = this._props.expanded();
+    @observable _expanded = this._props.nodeSelected();
 
     constructor(props: IDashFieldViewInternal) {
         super(props);
@@ -158,7 +156,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
     componentWillUnmount() {
         this._reactionDisposer?.();
     }
-    isRowActive = () => (this._props.expanded() || this._expanded) && this._props.editable;
+    isRowActive = () => (this._props.nodeSelected() || this._expanded) && this._props.editable;
 
     finishEdit = action(() => {
         if (this._expanded) {
@@ -181,7 +179,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
                     deselectCell={emptyFunction}
                     selectCell={emptyFunction}
                     maxWidth={this._props.hideKey || this._hideKey ? undefined : this._props.tbox._props.PanelWidth}
-                    columnWidth={this._expanded || this._props.expanded() ? this.columnWidth : returnZero}
+                    columnWidth={this._expanded || this._props.nodeSelected() ? this.columnWidth : returnZero}
                     selectedCell={this.selectedCell}
                     fieldKey={this._fieldKey}
                     rowHeight={returnZero}
@@ -190,7 +188,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
                     getFinfo={emptyFunction}
                     setColumnValues={returnFalse}
                     allowCRs={true}
-                    oneLine={!this._expanded && !this._props.expanded()}
+                    oneLine={!this._expanded && !this._props.nodeSelected()}
                     finishEdit={this.finishEdit}
                     transform={Transform.Identity}
                     menuTarget={null}
@@ -221,7 +219,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
     toggleFieldHide = undoable(
         action(() => {
             const editor = this._props.tbox.EditorView!;
-            editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideKey: !this._props.node.attrs.hideKey ? true : false }));
+            editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideKey: this._props.node.attrs.hideValue ? false : !this._props.node.attrs.hideKey ? true : false }));
         }),
         'hideKey'
     );
@@ -229,18 +227,17 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
     toggleValueHide = undoable(
         action(() => {
             const editor = this._props.tbox.EditorView!;
-            editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideValue: !this._props.node.attrs.hideValue ? true : false }));
+            editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideValue: this._props.node.attrs.hideKey ? false : !this._props.node.attrs.hideValue ? true : false }));
         }),
         'hideValue'
     );
 
-    @observable _showValue = false;
     @computed get _hideKey() {
         return this._props.hideKey && !this._expanded;
     }
 
     @computed get _hideValue() {
-        return !this._showValue && this._props.hideValue && !this._expanded;
+        return this._props.hideValue && !this._props.nodeSelected();
     }
 
     // clicking on the label creates a pivot view collection of all documents
@@ -251,7 +248,6 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
             DashFieldViewMenu.toggleFieldHide = this.toggleFieldHide;
             DashFieldViewMenu.toggleValueHide = this.toggleValueHide;
             DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16, this._fieldKey);
-            this._dashDoc?.[this._fieldKey + '_hideValue'] && runInAction(() => (this._showValue = !this._showValue));
             const editor = this._props.tbox.EditorView!;
             setTimeout(() => editor.dispatch(editor.state.tr.setSelection(new NodeSelection(editor.state.doc.resolve(this._props.getPos())))), 100);
         });
@@ -263,7 +259,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
     };
 
     @computed get values() {
-        if (this._props.expanded()) return [];
+        if (this._props.nodeSelected()) return [];
         const vals = FilterPanel.gatherFieldValues(DocListCast(Doc.ActiveDashboard?.data), this._fieldKey, []);
 
         return vals.strings.map(facet => ({ value: facet, label: facet }));
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index a0de822ac..3b583771a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1366,7 +1366,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             DocServer.GetRefField(pdfAnchorId).then(pdfAnchor => {
                 if (pdfAnchor instanceof Doc) {
                     const dashField = view.state.schema.nodes.paragraph.create({}, [
-                        view.state.schema.nodes.dashField.create({ fieldKey: 'text', docId: pdfAnchor[Id], hideKey: true, hideValue: false, editable: false, expanded: true }, undefined, [
+                        view.state.schema.nodes.dashField.create({ fieldKey: 'text', docId: pdfAnchor[Id], hideKey: true, hideValue: false, editable: false }, undefined, [
                             view.state.schema.marks.linkAnchor.create({
                                 allAnchors: [{ href: `/doc/${this.Document[Id]}`, title: this.Document.title, anchorId: `${this.Document[Id]}` }],
                                 title: StrCast(pdfAnchor.title),
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 682d4f96f..483035e86 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -250,10 +250,11 @@ export class RichTextRules {
 
                 if (
                     DocListCast((Doc.UserDoc().template_notes as Doc).data)
+                        .concat(DocListCast((Doc.UserDoc().template_user as Doc).data))
                         .map(d => StrCast(d.title))
                         .includes(color)
                 ) {
-                    setTimeout(() => this.TextBox.DocumentView?.().switchViews(true, color));
+                    setTimeout(() => this.TextBox.DocumentView?.().switchViews(true, color, undefined, true));
                     return state.tr.deleteRange(start, end);
                 }
                 if (marks) {
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 6862eecef..e335044ea 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -266,7 +266,6 @@ export const nodes: { [index: string]: NodeSpec } = {
             hideKey: { default: false },
             hideValue: { default: false },
             editable: { default: true },
-            expanded: { default: null },
             dataDoc: { default: false },
         },
         leafText: node => Field.toString((DocServer.GetCachedRefField(node.attrs.docId as string) as Doc)?.[node.attrs.fieldKey as string] as Field),
-- 
cgit v1.2.3-70-g09d2


From a9baa52c557faaa82fd3f696f0d603dd10b982a8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 30 Mar 2024 02:18:07 -0400
Subject: updated mermaids template. updated paintFunc to also render the
 underlying code text so that the paintFunc will update if dashFields in the
 code change.  fixed schema views to render templates properly in preview. 
 fixed text to only modify the data doc.  changed setPixels in imageBox to not
 consider scaling of outer containers.

---
 src/client/util/CurrentUserUtils.ts                          |  4 ++--
 src/client/views/StyleProvider.tsx                           |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  6 ++++--
 .../views/collections/collectionSchema/SchemaTableCell.tsx   |  6 +++---
 src/client/views/nodes/ImageBox.tsx                          |  3 +--
 src/client/views/nodes/formattedText/FormattedTextBox.tsx    | 12 ++++++++----
 6 files changed, 19 insertions(+), 14 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3855bdeb6..dbf9641b6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -321,9 +321,9 @@ export class CurrentUserUtils {
                         {type:"text",text:" "},
                         {type:"text",text:"Minerals in my tap water"},
                         {type:"text",text:"\n    \"Calcium\" : "},
-                        {type:"dashField",attrs:{fieldKey:"calcium",docId:"",hideKey:false,hideValue:false,editable:true}},
+                        {type:"dashField",attrs:{fieldKey:"calcium",docId:"",hideKey:true,hideValue:false,editable:true}},
                         {type:"text",text:"\n    \"Potassium\" : "},
-                        {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:false,hideValue:false,editable:true}},
+                        {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:true,hideValue:false,editable:true}},
                         {type:"text",text:"\n    \"Magnesium\" : 10.01"}
                     ]}
                 ]},
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 8073d0842..c8b0c0560 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -139,7 +139,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
         case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey';
         case StyleProp.Opacity:    return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 :  Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
         case StyleProp.FontSize:   return StrCast(doc?.[fieldKey + 'fontSize'],   StrCast(Doc.UserDoc().fontSize));
-        case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamilyq'], StrCast(Doc.UserDoc().fontFamily));
+        case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(Doc.UserDoc().fontFamily));
         case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'],  StrCast(Doc.UserDoc().fontWeight));
         case StyleProp.FillColor:  return StrCast(doc?._fillColor, StrCast(doc?.fillColor, StrCast(doc?.backgroundColor, 'transparent')));
         case StyleProp.ShowCaption:return props?.hideCaptions || doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c53bad509..1b562939b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -76,7 +76,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, '');
     @computed get paintFunc() {
-        const field = this.layoutDoc[this.fieldKey];
+        const field = this.dataDoc[this.fieldKey];
         const paintFunc = StrCast(Field.toJavascriptString(Cast(field, RichTextField, null)?.Text as Field)).trim();
         return !paintFunc
             ? ''
@@ -1870,7 +1870,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     width: `${100 / (this.nativeDimScaling || 1)}%`,
                     height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
                 }}>
-                {this.paintFunc ? null : this._lightboxDoc ? (
+                {this.paintFunc ? (
+                    <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads
+                ) : this._lightboxDoc ? (
                     <div style={{ padding: 15, width: '100%', height: '100%' }}>
                         <DocumentView
                             {...this._props}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index ab05a62d3..bf36b2668 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -98,7 +98,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
             focus: emptyFunction,
             addDocTab: SchemaTableCell.addFieldDoc,
             pinToPres: returnZero,
-            Document,
+            Document: DocCast(Document.rootDocument, Document),
             fieldKey: fieldKey,
             PanelWidth: columnWidth,
             PanelHeight: props.rowHeight,
@@ -134,14 +134,14 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
                     contents={undefined}
                     fieldContents={fieldProps}
                     editing={this.selected ? undefined : false}
-                    GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey, SnappingManager.MetaKey)}
+                    GetValue={() => Field.toKeyValueString(fieldProps.Document, this._props.fieldKey, SnappingManager.MetaKey)}
                     SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
                             this._props.finishEdit?.();
                             return true;
                         }
-                        const ret = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Document) ? true : undefined);
+                        const ret = KeyValueBox.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(fieldProps.Document) ? true : undefined);
                         this._props.finishEdit?.();
                         return ret;
                     }, 'edit schema cell')}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 86e8ed60a..469869e21 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -165,8 +165,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() impl
 
     @undoBatch
     setNativeSize = action(() => {
-        const scaling = (this.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
-        const nscale = NumCast(this._props.PanelWidth()) / scaling;
+        const nscale = NumCast(this._props.PanelWidth()) * NumCast(this.layoutDoc._freeform_scale, 1);
         const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
         this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
         this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 3b583771a..b815342e3 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -326,10 +326,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
 
     leafText = (node: Node) => {
         if (node.type === this._editorView?.state.schema.nodes.dashField) {
-            const refDoc = !node.attrs.docId ? this.Document : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
+            const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
             const fieldKey = StrCast(node.attrs.fieldKey);
             return (
-                (node.attrs.hideKey ? '' : '"' + fieldKey + '"' + ':') + //
+                (node.attrs.hideKey ? '' : fieldKey + ':') + //
                 (node.attrs.hideValue ? '' : Field.toJavascriptString(refDoc[fieldKey] as Field))
             );
         }
@@ -346,7 +346,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     tryUpdateDoc = (force: boolean) => {
         if (this._editorView && (this._editorView as any).docView) {
             const state = this._editorView.state;
-            const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+            const dataDoc = this.dataDoc;
             const newText = state.doc.textBetween(0, state.doc.content.size, ' \n', this.leafText);
             const newJson = JSON.stringify(state.toJSON());
             const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box
@@ -1608,7 +1608,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
                 while (target && !target.dataset?.targethrefs) target = target.parentElement;
                 FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true');
             } else {
-                editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(xpos))));
+                try {
+                    editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(xpos))));
+                } catch (e) {
+                    editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(xpos - 1))));
+                }
             }
         }
     };
-- 
cgit v1.2.3-70-g09d2


From ccbe6cafa422616ec4ffe5c2d1caed7597719007 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 30 Mar 2024 10:14:19 -0400
Subject: cleanup of import orderings.

---
 src/client/util/CaptureManager.tsx                 |   2 +-
 src/client/views/DocumentDecorations.tsx           |   3 +-
 src/client/views/GlobalKeyHandler.ts               |   8 +-
 src/client/views/LightboxView.tsx                  |   2 +-
 src/client/views/PropertiesView.tsx                |   3 +-
 src/client/views/collections/CollectionMenu.tsx    |  12 +-
 .../views/collections/CollectionNoteTakingView.tsx |   7 +-
 src/client/views/collections/TabDocView.tsx        |   2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  14 +-
 .../views/newlightbox/Header/LightboxHeader.tsx    | 108 ++++----
 .../RecommendationList/RecommendationList.tsx      | 295 +++++++++++----------
 src/client/views/nodes/DocumentView.tsx            |   3 +-
 src/client/views/nodes/EquationBox.tsx             |   2 +-
 src/client/views/nodes/LinkBox.tsx                 |   2 +-
 src/client/views/nodes/WebBox.tsx                  |   4 +-
 src/client/views/nodes/trails/PresBox.tsx          |   4 +-
 src/client/views/topbar/TopBar.tsx                 |   6 +-
 18 files changed, 253 insertions(+), 228 deletions(-)

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

diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index 2e13aff2f..8451357ef 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -2,9 +2,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { addStyleSheet } from '../../Utils';
 import { Doc } from '../../fields/Doc';
 import { DocCast, StrCast } from '../../fields/Types';
-import { addStyleSheet } from '../../Utils';
 import { LightboxView } from '../views/LightboxView';
 import { MainViewModal } from '../views/MainViewModal';
 import './CaptureManager.scss';
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4d9b93896..6698cd5bc 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -10,7 +10,6 @@ import { DateField } from '../../fields/DateField';
 import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
 import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols';
 import { InkField } from '../../fields/InkField';
-import { RichTextField } from '../../fields/RichTextField';
 import { ScriptField } from '../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
 import { GetEffectiveAcl } from '../../fields/util';
@@ -33,8 +32,8 @@ import { CollectionFreeFormView } from './collections/collectionFreeForm';
 import { Colors } from './global/globalEnums';
 import { DocumentView, OpenWhereMod } from './nodes/DocumentView';
 import { ImageBox } from './nodes/ImageBox';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from './nodes/KeyValueBox';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 
 interface DocumentDecorationsProps {
     PanelWidth: number;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 667d8dbb0..2f64ea28c 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -13,18 +13,18 @@ import { SettingsManager } from '../util/SettingsManager';
 import { SharingManager } from '../util/SharingManager';
 import { SnappingManager } from '../util/SnappingManager';
 import { UndoManager } from '../util/UndoManager';
-import { CollectionDockingView } from './collections/CollectionDockingView';
-import { CollectionFreeFormView } from './collections/collectionFreeForm';
-import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline';
 import { ContextMenu } from './ContextMenu';
 import { DocumentDecorations } from './DocumentDecorations';
 import { InkStrokeProperties } from './InkStrokeProperties';
 import { LightboxView } from './LightboxView';
 import { MainView } from './MainView';
+import { CollectionDockingView } from './collections/CollectionDockingView';
+import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline';
+import { CollectionFreeFormView } from './collections/collectionFreeForm';
 import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { OpenWhereMod } from './nodes/DocumentView';
-import { AnchorMenu } from './pdf/AnchorMenu';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { AnchorMenu } from './pdf/AnchorMenu';
 
 const modifiers = ['control', 'meta', 'shift', 'alt'];
 type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo;
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 3d77ee901..ef4b5b4ca 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -19,9 +19,9 @@ import { Transform } from '../util/Transform';
 import { GestureOverlay } from './GestureOverlay';
 import './LightboxView.scss';
 import { ObservableReactComponent } from './ObservableReactComponent';
+import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline';
-import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
 import { TabDocView } from './collections/TabDocView';
 import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
 
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index dc814bb16..ae29382c1 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -10,7 +10,7 @@ import * as React from 'react';
 import { ColorResult, SketchPicker } from 'react-color';
 import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
 import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils';
-import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
+import { Doc, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
 import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { InkField } from '../../fields/InkField';
@@ -41,7 +41,6 @@ import { DocumentView, OpenWhere } from './nodes/DocumentView';
 import { StyleProviderFuncType } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails';
-import { LinkBox } from './nodes/LinkBox';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 interface PropertiesViewProps {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 8729ef549..4f25f69ef 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1,15 +1,16 @@
-import * as React from 'react';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@mui/material';
 import { Toggle, ToggleType, Type } from 'browndash-components';
-import { action, computed, Lambda, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { Lambda, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
 import { RichTextField } from '../../../fields/RichTextField';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -19,11 +20,10 @@ import { undoBatch } from '../../util/UndoManager';
 import { AntimodeMenu } from '../AntimodeMenu';
 import { EditableView } from '../EditableView';
 import { MainView } from '../MainView';
-import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
 import { DefaultStyleProvider } from '../StyleProvider';
-import { CollectionLinearView } from './collectionLinear';
+import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
 import './CollectionMenu.scss';
-import { DocData } from '../../../fields/DocSymbols';
+import { CollectionLinearView } from './collectionLinear';
 
 interface CollectionMenuProps {
     panelHeight: () => number;
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 6318620e0..5b91216cb 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, IReactionDisposer, makeObservable, observable, observe, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Field, Opt } from '../../../fields/Doc';
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { DivHeight, emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils';
+import { DivHeight, emptyFunction, returnZero, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -19,14 +19,13 @@ import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { LightboxView } from '../LightboxView';
 import { DocumentView } from '../nodes/DocumentView';
-import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
+import { FieldViewProps, FocusViewOptions } from '../nodes/FieldView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { StyleProp } from '../StyleProvider';
 import './CollectionNoteTakingView.scss';
 import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn';
 import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider';
 import { CollectionSubView } from './CollectionSubView';
-import { JsxElement } from 'typescript';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 /**
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 699ec3b95..3ff58c326 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -30,7 +30,7 @@ import { ObservableReactComponent } from '../ObservableReactComponent';
 import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
 import { Colors } from '../global/globalEnums';
 import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView';
-import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
+import { FieldViewProps, FocusViewOptions } from '../nodes/FieldView';
 import { KeyValueBox } from '../nodes/KeyValueBox';
 import { DashFieldView } from '../nodes/formattedText/DashFieldView';
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1b562939b..d435173f3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
 import { Bezier } from 'bezier-js';
 import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
@@ -17,7 +17,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../
 import { ImageField } from '../../../../fields/URLField';
 import { TraceMobx } from '../../../../fields/util';
 import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
-import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, numberValue, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 5f4948808..df023b00f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,33 +1,33 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Popup, PopupTrigger, Type } from 'browndash-components';
-import { action, computed, makeObservable, observable, ObservableMap, observe } from 'mobx';
+import { ObservableMap, action, computed, makeObservable, observable, observe } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
 import { Doc, DocListCast, Field, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { DocData } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
-import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
+import { DocUtils, Docs, DocumentOptions, FInfo } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { SettingsManager } from '../../../util/SettingsManager';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoBatch, undoable } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { EditableView } from '../../EditableView';
+import { ObservableReactComponent } from '../../ObservableReactComponent';
+import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
 import { Colors } from '../../global/globalEnums';
 import { DocumentView } from '../../nodes/DocumentView';
 import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
-import { ObservableReactComponent } from '../../ObservableReactComponent';
-import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { DocData } from '../../../../fields/DocSymbols';
 const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
 
 export enum ColumnType {
diff --git a/src/client/views/newlightbox/Header/LightboxHeader.tsx b/src/client/views/newlightbox/Header/LightboxHeader.tsx
index a272ce294..76efe0185 100644
--- a/src/client/views/newlightbox/Header/LightboxHeader.tsx
+++ b/src/client/views/newlightbox/Header/LightboxHeader.tsx
@@ -1,62 +1,70 @@
-import './LightboxHeader.scss';
-import * as React from 'react';
-import { INewLightboxHeader } from "./utils";
-import { NewLightboxView } from '../NewLightboxView';
-import { StrCast } from '../../../../fields/Types';
-import { EditableText } from '../components/EditableText';
-import { getType } from '../utils';
 import { Button, IconButton, Size, Type } from 'browndash-components';
-import { MdExplore, MdTravelExplore } from 'react-icons/md'
-import { BsBookmark, BsBookmarkFill } from 'react-icons/bs'
+import * as React from 'react';
+import { BsBookmark, BsBookmarkFill } from 'react-icons/bs';
+import { MdTravelExplore } from 'react-icons/md';
 import { Doc } from '../../../../fields/Doc';
+import { StrCast } from '../../../../fields/Types';
 import { LightboxView } from '../../LightboxView';
 import { Colors } from '../../global/globalEnums';
-
+import { NewLightboxView } from '../NewLightboxView';
+import { EditableText } from '../components/EditableText';
+import { getType } from '../utils';
+import './LightboxHeader.scss';
+import { INewLightboxHeader } from './utils';
 
 export const NewLightboxHeader = (props: INewLightboxHeader) => {
-    const {height = 100, width} = props;
-    const [doc, setDoc] = React.useState<Doc | undefined>(LightboxView.LightboxDoc)
-    const [editing, setEditing] = React.useState<boolean>(false)
-    const [title, setTitle] = React.useState<JSX.Element | null>(
-        (null)
-    )
+    const { height = 100, width } = props;
+    const [doc, setDoc] = React.useState<Doc | undefined>(LightboxView.LightboxDoc);
+    const [editing, setEditing] = React.useState<boolean>(false);
+    const [title, setTitle] = React.useState<JSX.Element | null>(null);
     React.useEffect(() => {
-        let lbDoc = LightboxView.LightboxDoc
-        setDoc(lbDoc)
+        let lbDoc = LightboxView.LightboxDoc;
+        setDoc(lbDoc);
         if (lbDoc) {
             setTitle(
-                <EditableText 
-                editing={editing}
-                text={StrCast(lbDoc.title)} 
-                onEdit={(newText: string) => {
-                    if(lbDoc) lbDoc.title = newText;
-                }} 
-                setEditing={setEditing}            
-            />)
+                <EditableText
+                    editing={editing}
+                    text={StrCast(lbDoc.title)}
+                    onEdit={(newText: string) => {
+                        if (lbDoc) lbDoc.title = newText;
+                    }}
+                    setEditing={setEditing}
+                />
+            );
         }
-    }, [LightboxView.LightboxDoc])
+    }, [LightboxView.LightboxDoc]);
 
-    const [saved, setSaved] = React.useState<boolean>(false)
+    const [saved, setSaved] = React.useState<boolean>(false);
 
-    if (!doc) return null
-    else return <div className={`newLightboxHeader-container`} onPointerDown={(e) => e.stopPropagation()} style={{ minHeight: height, height: height, width: width }}>
-        <div className={`title-container`}>
-            <div className={`lb-label`}>Title</div>
-            {title}
-        </div>
-        <div className={`type-container`}>
-            <div className={`lb-label`}>Type</div>
-            <div className={`type`}>{getType(StrCast(doc.type))}</div>
-        </div>
-        <div style={{gridColumn: 2, gridRow: 1, height: '100%', display: 'flex', justifyContent: 'flex-end', alignItems: 'center'}}>
-            <IconButton size={Size.XSMALL} onClick={() => setSaved(!saved)} color={Colors.DARK_GRAY} icon={saved ? <BsBookmarkFill/> : <BsBookmark/>}/>
-            <IconButton size={Size.XSMALL} onClick={() => setSaved(!saved)} color={Colors.DARK_GRAY} icon={saved ? <BsBookmarkFill/> : <BsBookmark/>}/>
-        </div>
-        <div  style={{gridColumn: 2, gridRow: 2, height: '100%', display: 'flex', justifyContent: 'flex-end', alignItems: 'center'}}>
-            <Button onClick={() => {
-                console.log(NewLightboxView.ExploreMode)
-                NewLightboxView.SetExploreMode(!NewLightboxView.ExploreMode)
-            }} size={Size.XSMALL} color={Colors.DARK_GRAY} type={Type.SEC} text={"t-SNE 2D Embeddings"} icon={<MdTravelExplore/>}/>
-        </div>
-    </div>
-}
\ No newline at end of file
+    if (!doc) return null;
+    else
+        return (
+            <div className={`newLightboxHeader-container`} onPointerDown={e => e.stopPropagation()} style={{ minHeight: height, height: height, width: width }}>
+                <div className={`title-container`}>
+                    <div className={`lb-label`}>Title</div>
+                    {title}
+                </div>
+                <div className={`type-container`}>
+                    <div className={`lb-label`}>Type</div>
+                    <div className={`type`}>{getType(StrCast(doc.type))}</div>
+                </div>
+                <div style={{ gridColumn: 2, gridRow: 1, height: '100%', display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
+                    <IconButton size={Size.XSMALL} onClick={() => setSaved(!saved)} color={Colors.DARK_GRAY} icon={saved ? <BsBookmarkFill /> : <BsBookmark />} />
+                    <IconButton size={Size.XSMALL} onClick={() => setSaved(!saved)} color={Colors.DARK_GRAY} icon={saved ? <BsBookmarkFill /> : <BsBookmark />} />
+                </div>
+                <div style={{ gridColumn: 2, gridRow: 2, height: '100%', display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
+                    <Button
+                        onClick={() => {
+                            console.log(NewLightboxView.ExploreMode);
+                            NewLightboxView.SetExploreMode(!NewLightboxView.ExploreMode);
+                        }}
+                        size={Size.XSMALL}
+                        color={Colors.DARK_GRAY}
+                        type={Type.SEC}
+                        text={'t-SNE 2D Embeddings'}
+                        icon={<MdTravelExplore />}
+                    />
+                </div>
+            </div>
+        );
+};
diff --git a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
index 9f3c32e4e..1d502b73f 100644
--- a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
+++ b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
@@ -1,74 +1,67 @@
-import { GrClose } from 'react-icons/gr';
-import { IRecommendation, Recommendation } from "../components";
-import './RecommendationList.scss';
+import { IconButton, Size, Type } from 'browndash-components';
 import * as React from 'react';
-import { IRecommendationList } from "./utils";
-import { NewLightboxView } from '../NewLightboxView';
-import { DocCast, StrCast } from '../../../../fields/Types';
 import { FaCaretDown, FaCaretUp } from 'react-icons/fa';
-import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
-import { IDocRequest, fetchKeywords, fetchRecommendations } from '../utils';
-import { IBounds } from '../ExploreView/utils';
+import { GrClose } from 'react-icons/gr';
+import { DocListCast, StrListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
-import { Id } from '../../../../fields/FieldSymbols';
+import { StrCast } from '../../../../fields/Types';
 import { LightboxView } from '../../LightboxView';
-import { IconButton, Size, Type } from 'browndash-components';
 import { Colors } from '../../global/globalEnums';
+import { IBounds } from '../ExploreView/utils';
+import { NewLightboxView } from '../NewLightboxView';
+import { IRecommendation, Recommendation } from '../components';
+import { IDocRequest, fetchKeywords, fetchRecommendations } from '../utils';
+import './RecommendationList.scss';
+import { IRecommendationList } from './utils';
 
 export const RecommendationList = (props: IRecommendationList) => {
-    const {loading, keywords} = props
-    const [loadingKeywords, setLoadingKeywords] = React.useState<boolean>(true)
-    const [showMore, setShowMore] = React.useState<boolean>(false)
-    const [keywordsLoc, setKeywordsLoc] = React.useState<string[]>([])
-    const [update, setUpdate] = React.useState<boolean>(true)
-    const initialRecs: IRecommendation[] = [
-        {loading: true},
-        {loading: true},
-        {loading: true},
-        {loading: true},
-        {loading: true}
-    ];
-    const [recs, setRecs] = React.useState<IRecommendation[]>(initialRecs)
+    const { loading, keywords } = props;
+    const [loadingKeywords, setLoadingKeywords] = React.useState<boolean>(true);
+    const [showMore, setShowMore] = React.useState<boolean>(false);
+    const [keywordsLoc, setKeywordsLoc] = React.useState<string[]>([]);
+    const [update, setUpdate] = React.useState<boolean>(true);
+    const initialRecs: IRecommendation[] = [{ loading: true }, { loading: true }, { loading: true }, { loading: true }, { loading: true }];
+    const [recs, setRecs] = React.useState<IRecommendation[]>(initialRecs);
 
     React.useEffect(() => {
         const getKeywords = async () => {
-            let text = StrCast(LightboxView.LightboxDoc?.text)
-            console.log('[1] fetching keywords')
-            const response = await fetchKeywords(text, 5, true)
-            console.log('[2] response:', response)
+            let text = StrCast(LightboxView.LightboxDoc?.text);
+            console.log('[1] fetching keywords');
+            const response = await fetchKeywords(text, 5, true);
+            console.log('[2] response:', response);
             const kw = response.keywords;
             console.log(kw);
             NewLightboxView.SetKeywords(kw);
             if (LightboxView.LightboxDoc) {
-                console.log('setting keywords on doc')
+                console.log('setting keywords on doc');
                 LightboxView.LightboxDoc.keywords = new List<string>(kw);
                 setKeywordsLoc(NewLightboxView.Keywords);
             }
-            setLoadingKeywords(false)
-        }
-        let keywordsList = StrListCast(LightboxView.LightboxDoc!.keywords)
+            setLoadingKeywords(false);
+        };
+        let keywordsList = StrListCast(LightboxView.LightboxDoc!.keywords);
         if (!keywordsList || keywordsList.length < 2) {
-            setLoadingKeywords(true)
-            getKeywords()
-            setUpdate(!update)
+            setLoadingKeywords(true);
+            getKeywords();
+            setUpdate(!update);
         } else {
-            setKeywordsLoc(keywordsList)
-            setLoadingKeywords(false)
-            setUpdate(!update)
+            setKeywordsLoc(keywordsList);
+            setLoadingKeywords(false);
+            setUpdate(!update);
         }
-    }, [NewLightboxView.LightboxDoc])
+    }, [NewLightboxView.LightboxDoc]);
 
-    // terms: vannevar bush, information spaces, 
+    // terms: vannevar bush, information spaces,
     React.useEffect(() => {
         const getRecommendations = async () => {
-            console.log('fetching recommendations')
-            let query = 'undefined'
-            if (keywordsLoc) query = keywordsLoc.join(',')
-            let src = StrCast(NewLightboxView.LightboxDoc?.text)
-            let dashDocs:IDocRequest[] = [];
+            console.log('fetching recommendations');
+            let query = 'undefined';
+            if (keywordsLoc) query = keywordsLoc.join(',');
+            let src = StrCast(NewLightboxView.LightboxDoc?.text);
+            let dashDocs: IDocRequest[] = [];
             // get linked docs
-            let linkedDocs = DocListCast(NewLightboxView.LightboxDoc?.links)
-            console.log("linked docs", linkedDocs)
+            let linkedDocs = DocListCast(NewLightboxView.LightboxDoc?.links);
+            console.log('linked docs', linkedDocs);
             // get context docs (docs that are also in the collection)
             // let contextDocs: Doc[] = DocListCast(DocCast(LightboxView.LightboxDoc?.context).data)
             // let docId = LightboxView.LightboxDoc && LightboxView.LightboxDoc[Id]
@@ -83,114 +76,142 @@ export const RecommendationList = (props: IRecommendationList) => {
             //         })
             //     }
             // })
-            console.log("dash docs", dashDocs)
+            console.log('dash docs', dashDocs);
             if (query !== undefined) {
-                const response = await fetchRecommendations(src, query, [], true)
-                const num_recs = response.num_recommendations
-                const recs = response.recommendations
-                const keywords = response.keywords
+                const response = await fetchRecommendations(src, query, [], true);
+                const num_recs = response.num_recommendations;
+                const recs = response.recommendations;
+                const keywords = response.keywords;
                 const response_bounds: IBounds = {
-                  max_x: response.max_x,
-                  max_y: response.max_y,
-                  min_x: response.min_x,
-                  min_y: response.min_y
-                }
+                    max_x: response.max_x,
+                    max_y: response.max_y,
+                    min_x: response.min_x,
+                    min_y: response.min_y,
+                };
                 // if (NewLightboxView.NewLightboxDoc) {
                 //     NewLightboxView.NewLightboxDoc.keywords = new List<string>(keywords);
                 //     setKeywordsLoc(NewLightboxView.Keywords);
                 // }
                 // console.log(response_bounds)
-                NewLightboxView.SetBounds(response_bounds)
+                NewLightboxView.SetBounds(response_bounds);
                 const recommendations: IRecommendation[] = [];
                 for (const key in recs) {
-                    console.log(key)
+                    console.log(key);
                     const title = recs[key].title;
-                    const url = recs[key].url
-                    const type = recs[key].type
-                    const text = recs[key].text
-                    const transcript = recs[key].transcript
-                    const previewUrl = recs[key].previewUrl
-                    const embedding = recs[key].embedding
-                    const distance = recs[key].distance
-                    const source = recs[key].source
-                    const related_concepts = recs[key].related_concepts
-                    const docId = recs[key].doc_id
-                    related_concepts.length >= 1 && recommendations.push({
-                        title: title,
-                        data: url,
-                        type: type,
-                        text: text,
-                        transcript: transcript,
-                        previewUrl: previewUrl,
-                        embedding: embedding,
-                        distance: Math.round(distance * 100) / 100,
-                        source: source,
-                        related_concepts: related_concepts,
-                        docId: docId
-                    })
+                    const url = recs[key].url;
+                    const type = recs[key].type;
+                    const text = recs[key].text;
+                    const transcript = recs[key].transcript;
+                    const previewUrl = recs[key].previewUrl;
+                    const embedding = recs[key].embedding;
+                    const distance = recs[key].distance;
+                    const source = recs[key].source;
+                    const related_concepts = recs[key].related_concepts;
+                    const docId = recs[key].doc_id;
+                    related_concepts.length >= 1 &&
+                        recommendations.push({
+                            title: title,
+                            data: url,
+                            type: type,
+                            text: text,
+                            transcript: transcript,
+                            previewUrl: previewUrl,
+                            embedding: embedding,
+                            distance: Math.round(distance * 100) / 100,
+                            source: source,
+                            related_concepts: related_concepts,
+                            docId: docId,
+                        });
                 }
                 recommendations.sort((a, b) => {
                     if (a.distance && b.distance) {
-                        return a.distance - b.distance
-                    } else return 0
-                })
-                console.log("[rec]: ", recommendations)
-                NewLightboxView.SetRecs(recommendations)
-                setRecs(recommendations)
+                        return a.distance - b.distance;
+                    } else return 0;
+                });
+                console.log('[rec]: ', recommendations);
+                NewLightboxView.SetRecs(recommendations);
+                setRecs(recommendations);
             }
-        }
+        };
         getRecommendations();
-    }, [update])
-    
-    
+    }, [update]);
 
-    return <div className={`recommendationlist-container`} onPointerDown={(e) => {e.stopPropagation()}}>
-        <div className={`header`}>
-            <div className={`title`}>
-                Recommendations
-            </div>
-            {NewLightboxView.LightboxDoc && <div style={{fontSize: 10}}>
-                The recommendations are produced based on the text in the document <b><u>{StrCast(NewLightboxView.LightboxDoc.title)}</u></b>. The following keywords are used to fetch the recommendations.
-            </div>}
-            <div className={`lb-label`}>Keywords</div>
-            {loadingKeywords ? <div className={`keywords`}>
-                    <div className={`keyword ${loadingKeywords && 'loading'}`}/>
-                    <div className={`keyword ${loadingKeywords && 'loading'}`}/>
-                    <div className={`keyword ${loadingKeywords && 'loading'}`}/>
-                    <div className={`keyword ${loadingKeywords && 'loading'}`}/>
+    return (
+        <div
+            className={`recommendationlist-container`}
+            onPointerDown={e => {
+                e.stopPropagation();
+            }}>
+            <div className={`header`}>
+                <div className={`title`}>Recommendations</div>
+                {NewLightboxView.LightboxDoc && (
+                    <div style={{ fontSize: 10 }}>
+                        The recommendations are produced based on the text in the document{' '}
+                        <b>
+                            <u>{StrCast(NewLightboxView.LightboxDoc.title)}</u>
+                        </b>
+                        . The following keywords are used to fetch the recommendations.
                     </div>
-                :
-                <div className={`keywords`}>
-                {keywordsLoc && keywordsLoc.map((word, ind) => {
-                    return <div className={`keyword`}>
-                        {word}
-                        <IconButton type={Type.PRIM} size={Size.XSMALL} color={Colors.DARK_GRAY} icon={<GrClose/>} onClick={() => {
-                            let kw = keywordsLoc
-                            kw.splice(ind)
-                            NewLightboxView.SetKeywords(kw)
-                        }}/>
+                )}
+                <div className={`lb-label`}>Keywords</div>
+                {loadingKeywords ? (
+                    <div className={`keywords`}>
+                        <div className={`keyword ${loadingKeywords && 'loading'}`} />
+                        <div className={`keyword ${loadingKeywords && 'loading'}`} />
+                        <div className={`keyword ${loadingKeywords && 'loading'}`} />
+                        <div className={`keyword ${loadingKeywords && 'loading'}`} />
                     </div>
-                })}
-            </div>
-            }
-            {!showMore ?
-            <div className={`lb-caret`} onClick={() => {setShowMore(true)}}>
-                More <FaCaretDown/>
+                ) : (
+                    <div className={`keywords`}>
+                        {keywordsLoc &&
+                            keywordsLoc.map((word, ind) => {
+                                return (
+                                    <div className={`keyword`}>
+                                        {word}
+                                        <IconButton
+                                            type={Type.PRIM}
+                                            size={Size.XSMALL}
+                                            color={Colors.DARK_GRAY}
+                                            icon={<GrClose />}
+                                            onClick={() => {
+                                                let kw = keywordsLoc;
+                                                kw.splice(ind);
+                                                NewLightboxView.SetKeywords(kw);
+                                            }}
+                                        />
+                                    </div>
+                                );
+                            })}
+                    </div>
+                )}
+                {!showMore ? (
+                    <div
+                        className={`lb-caret`}
+                        onClick={() => {
+                            setShowMore(true);
+                        }}>
+                        More <FaCaretDown />
+                    </div>
+                ) : (
+                    <div className={`more`}>
+                        <div
+                            className={`lb-caret`}
+                            onClick={() => {
+                                setShowMore(false);
+                            }}>
+                            Less <FaCaretUp />
+                        </div>
+                        <div className={`lb-label`}>Type</div>
+                        <div className={`lb-label`}>Sources</div>
+                    </div>
+                )}
             </div>
-            :
-            <div className={`more`}>
-                <div className={`lb-caret`} onClick={() => {setShowMore(false)}}>
-                    Less <FaCaretUp/>
-                </div>
-                <div className={`lb-label`}>Type</div>
-                <div className={`lb-label`}>Sources</div>
+            <div className={`recommendations`}>
+                {recs &&
+                    recs.map((rec: IRecommendation) => {
+                        return <Recommendation {...rec} />;
+                    })}
             </div>
-            }
-        </div>
-        <div className={`recommendations`}>
-            {recs && recs.map((rec: IRecommendation) => {
-                return <Recommendation {...rec} />
-            })}
         </div>
-    </div>
-}
\ No newline at end of file
+    );
+};
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 58820a498..a04030a5f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,6 +1,6 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { Howl } from 'howler';
-import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
+import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal';
@@ -50,7 +50,6 @@ import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import { PresEffect, PresEffectDirection } from './trails';
-import { InkingStroke } from '../InkingStroke';
 interface Window {
     MediaRecorder: MediaRecorder;
 }
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index c43f89be1..a557cff4f 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -1,6 +1,7 @@
 import { action, makeObservable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { DivHeight, DivWidth } from '../../../Utils';
 import { Id } from '../../../fields/FieldSymbols';
 import { NumCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
@@ -11,7 +12,6 @@ import { LightboxView } from '../LightboxView';
 import './EquationBox.scss';
 import { FieldView, FieldViewProps } from './FieldView';
 import EquationEditor from './formattedText/EquationEditor';
-import { DivHeight, DivWidth } from '../../../Utils';
 
 @observer
 export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 7ad250714..36bd037ca 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -15,9 +15,9 @@ import { EditableView } from '../EditableView';
 import { LightboxView } from '../LightboxView';
 import { StyleProp } from '../StyleProvider';
 import { ComparisonBox } from './ComparisonBox';
+import { DocumentView } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import './LinkBox.scss';
-import { DocumentView } from './DocumentView';
 
 @observer
 export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index f4d5eef05..434415b96 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { htmlToText } from 'html-to-text';
-import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import * as WebRequest from 'web-request';
@@ -34,7 +34,7 @@ import { GPTPopup } from '../pdf/GPTPopup/GPTPopup';
 import { SidebarAnnos } from '../SidebarAnnos';
 import { StyleProp } from '../StyleProvider';
 import { DocumentView, OpenWhere } from './DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
+import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView';
 import { LinkInfo } from './LinkDocPreview';
 import { PinProps, PresBox } from './trails';
 import './WebBox.scss';
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ae6da8fb0..cd9fec839 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -18,6 +18,7 @@ import { DocServer } from '../../../DocServer';
 import { Docs } from '../../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
+import { dropActionType } from '../../../util/DragManager';
 import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { SerializationHelper } from '../../../util/SerializationHelper';
@@ -32,11 +33,10 @@ import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { LightboxView } from '../../LightboxView';
 import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
+import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView';
 import { ScriptingBox } from '../ScriptingBox';
 import './PresBox.scss';
 import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
-import { dropActionType } from '../../../util/DragManager';
 export interface pinDataTypes {
     scrollable?: boolean;
     dataviz?: number[];
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index addad2bbc..eab33114e 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -3,6 +3,7 @@ import { Button, IconButton, isDark, Size, Type } from 'browndash-components';
 import { action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { Flip } from 'react-awesome-reveal';
 import { FaBug } from 'react-icons/fa';
 import { Doc, DocListCast } from '../../../fields/Doc';
 import { AclAdmin, DashVersion } from '../../../fields/DocSymbols';
@@ -11,6 +12,7 @@ import { GetEffectiveAcl } from '../../../fields/util';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { DocumentManager } from '../../util/DocumentManager';
+import { dropActionType } from '../../util/DragManager';
 import { PingManager } from '../../util/PingManager';
 import { ReportManager } from '../../util/reportManager/ReportManager';
 import { ServerStats } from '../../util/ServerStats';
@@ -23,11 +25,9 @@ import { CollectionLinearView } from '../collections/collectionLinear';
 import { DashboardView } from '../DashboardView';
 import { Colors } from '../global/globalEnums';
 import { DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
+import { ObservableReactComponent } from '../ObservableReactComponent';
 import { DefaultStyleProvider } from '../StyleProvider';
 import './TopBar.scss';
-import { dropActionType } from '../../util/DragManager';
-import { Flip } from 'react-awesome-reveal';
-import { ObservableReactComponent } from '../ObservableReactComponent';
 
 /**
  * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user
-- 
cgit v1.2.3-70-g09d2


From 47ae05389d7ce564efde19b7a639b38842759cc1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 31 Mar 2024 00:09:33 -0400
Subject: fixed dropdown in title bar location.  moved rotate button up to not
 interfere with button bar.  don't blur title when editing it.  fix drawgging
 rotate center on templates.  support setting alternate colors for text docs
 -- pretty hacky.   fixed tabbing through dashFieldViews.

---
 src/client/views/DocumentDecorations.scss           |  2 +-
 src/client/views/DocumentDecorations.tsx            | 21 +++++++++++++++------
 src/client/views/StyleProvider.tsx                  |  5 ++++-
 .../collectionFreeForm/CollectionFreeFormView.tsx   |  2 +-
 src/client/views/global/globalScripts.ts            |  4 +++-
 src/client/views/nodes/DocumentView.scss            |  6 ++++++
 src/client/views/nodes/DocumentView.tsx             |  6 +++++-
 .../views/nodes/formattedText/DashFieldView.tsx     | 17 ++++++++++-------
 .../views/nodes/formattedText/FormattedTextBox.tsx  |  7 +++++--
 9 files changed, 50 insertions(+), 20 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index ac0ef054c..239c0a977 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -14,7 +14,7 @@ $resizeHandler: 8px;
         height: 30;
         width: 30;
         right: -40;
-        bottom: -40;
+        bottom: -20;
         //top: calc(50% - 15px);
         position: absolute;
         pointer-events: all;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6698cd5bc..951e0912c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -73,11 +73,18 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         DocumentDecorations.Instance = this;
         document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds.
             action(e => {
+                let inputting = false;
+                if (this._titleControlString.startsWith('$')) {
+                    const titleFieldKey = this._titleControlString.substring(1);
+                    if (SelectionManager.Views[0]?.Document[titleFieldKey] !== this._accumulatedTitle) {
+                        inputting = true;
+                    }
+                }
                 const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2};
                 const {x,y} = Utils.rotPt(e.clientX - center.x, 
                                           e.clientY - center.y, 
                                           NumCast(SelectionManager.Views.lastElement()?.screenToViewTransform().Rotate));
-                (this._showNothing = !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && //
+                (this._showNothing = !inputting && !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && //
                     (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x || 
                      this.Bounds.y > center.y+y || this.Bounds.b < center.y+y )));
             })); // prettier-ignore
@@ -336,8 +343,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         const newloccentern = seldocview.screenToContentsTransform().transformPoint(rotCenter[0], rotCenter[1]);
         const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2];
         const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI);
-        seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
-        seldocview.Document.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
+        seldocview.Document._rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
+        seldocview.Document._rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
     };
 
     @action
@@ -350,8 +357,10 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
             (e: PointerEvent, down: number[], delta: number[]) => // return false to keep getting events
                 this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean, 
             action(e => (this._isRotating = false)), // upEvent
-            action(e => (seldocview.Document.rotation_centerX = seldocview.Document.rotation_centerY = 0))
+            action(e => (seldocview.Document._rotation_centerX = seldocview.Document._rotation_centerY = 0)),
+            true
         ); // prettier-ignore
+        e.stopPropagation();
     };
 
     @action
@@ -617,7 +626,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         if (lastView) {
             const invXf = lastView.screenToContentsTransform().inverse();
             const seldoc = lastView.layoutDoc;
-            const loccenter = Utils.rotPt(NumCast(seldoc.rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc.rotation_centerY) * NumCast(seldoc._height), invXf.Rotate);
+            const loccenter = Utils.rotPt(NumCast(seldoc._rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc._rotation_centerY) * NumCast(seldoc._height), invXf.Rotate);
             return invXf.transformPoint(loccenter.x + NumCast(seldoc._width) / 2, loccenter.y + NumCast(seldoc._height) / 2);
         }
         return this._rotCenter;
@@ -721,7 +730,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                     value={hideTitle ? '' : this._accumulatedTitle}
                     onBlur={action((e: React.FocusEvent) => {
                         this._editingTitle = false;
-                        !hideTitle && this.titleBlur();
+                        this.titleBlur();
                     })}
                     onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))}
                     onKeyDown={hideTitle ? emptyFunction : this.titleEntered}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 749198fe6..dcec2fe3d 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -200,7 +200,10 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
                 : 0;
         case StyleProp.BackgroundColor: {
             if (SettingsManager.Instance.LastPressedBtn === doc) return SettingsManager.userColor; // hack to indicate active menu panel item
-            let docColor: Opt<string> = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?.backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
+            const dataKey = doc ? Doc.LayoutFieldKey(doc) : "";
+            const usePath = StrCast(doc?.[dataKey + "_usePath"]);
+            const alternate = usePath.includes(":hover") ? ( doc?.isHovering ? '_' + usePath.replace(":hover","") : "") : usePath ? "_" +usePath:usePath;
+            let docColor: Opt<string> = StrCast(doc?.[fieldKey+alternate], StrCast(doc?.['backgroundColor' +alternate], isCaption ? 'rgba(0,0,0,0.4)' : ''));
             if (doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc) docColor = StrCast(doc._backgroundColor,docColor)
             // prettier-ignore
             switch (layoutDoc?.type) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d435173f3..791124f50 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1288,7 +1288,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const rotation = Cast(_rotation,'number',
             !this.layoutDoc._rotation_jitter ? null
                 : NumCast(this.layoutDoc._rotation_jitter) * random(-1, 1, NumCast(x), NumCast(y)) );
-        const childProps = { ...this._props, styleProvider: this.clusterStyleProvider };
+        const childProps = { ...this._props, fieldKey: '', styleProvider: this.clusterStyleProvider };
         return {
             x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x),
             y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y),
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 3ea7bfbcd..dab642499 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -59,7 +59,9 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
                 obj[fieldKey] = color;
                 CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj);
             } else {
-                dv.Document[DocData][fieldKey] = color;
+                const dataKey = Doc.LayoutFieldKey(dv.Document);
+                const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', '');
+                dv.dataDoc[fieldKey + alternate] = color;
             }
         });
     } else {
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 4fea6b3c6..23dada260 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -234,6 +234,12 @@
     }
 }
 
+.documntViewInternal-dropdown {
+    > div {
+        transform-origin: top left !important;
+    }
+}
+
 .contentFittingDocumentView {
     position: relative;
     display: flex;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a04030a5f..fc2da18d9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -843,7 +843,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                     background,
                     pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
                 }}>
-                {!dropdownWidth ? null : <div style={{ width: dropdownWidth }}>{this.fieldsDropdown(showTitle)}</div>}
+                {!dropdownWidth ? null : (
+                    <div className="documntViewInternal-dropdown" style={{ width: dropdownWidth }}>
+                        {this.fieldsDropdown(showTitle)}
+                    </div>
+                )}
                 <div
                     style={{
                         width: `calc(100% - ${dropdownWidth}px)`,
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index f6ca97ee9..22a0cbe5e 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -29,6 +29,7 @@ export class DashFieldView {
     root: any;
     node: any;
     tbox: FormattedTextBox;
+    getpos: any;
     @observable _nodeSelected = false;
     NodeSelected = () => this._nodeSelected;
 
@@ -38,6 +39,7 @@ export class DashFieldView {
         const self = this;
         this.node = node;
         this.tbox = tbox;
+        this.getpos = getPos;
         this.dom = document.createElement('div');
         this.dom.style.width = node.attrs.width;
         this.dom.style.height = node.attrs.height;
@@ -54,13 +56,13 @@ export class DashFieldView {
                 const editor = tbox.EditorView;
                 if (editor) {
                     const state = editor.state;
-                    for (var i = state.selection.to; i < state.doc.content.size; i++) {
+                    for (var i = self.getpos() + 1; i < state.doc.content.size; i++) {
                         if (state.doc.nodeAt(i)?.type.name === state.schema.nodes.dashField.name) {
                             editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(i))));
                             return;
                         }
                     }
-                    tBox.setFocus(state.selection.to);
+                    // tBox.setFocus(state.selection.to);
                 }
             }
         };
@@ -137,7 +139,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
         makeObservable(this);
         this._fieldKey = this._props.fieldKey;
         this._textBoxDoc = this._props.tbox.Document;
-        const setDoc = (doc: Doc) => (this._dashDoc = this._props.dataDoc ? doc[DocData] : doc);
+        const setDoc = action((doc: Doc) => (this._dashDoc = this._props.dataDoc ? doc[DocData] : doc));
 
         if (this._props.docId) {
             DocServer.GetRefField(this._props.docId).then(dashDoc => dashDoc instanceof Doc && setDoc(dashDoc));
@@ -255,7 +257,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
 
     @undoBatch
     selectVal = (event: React.ChangeEvent<HTMLSelectElement> | undefined) => {
-        event && this._dashDoc && (this._dashDoc[this._fieldKey] = event.target.value);
+        event && this._dashDoc && (this._dashDoc[this._fieldKey] = event.target.value === '-unset-' ? undefined : event.target.value);
     };
 
     @computed get values() {
@@ -281,13 +283,14 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
                     </span>
                 )}
                 {this._props.fieldKey.startsWith('#') || this._hideValue ? null : this.fieldValueContent}
-                {/* {!this.values.length ? null : (
-                    <select className="dashFieldView-select" tabIndex={-1} onChange={this.selectVal}>
+                {!this.values.length ? null : (
+                    <select className="dashFieldView-select" tabIndex={-1} defaultValue={Field.toKeyValueString(this._dashDoc!, this._fieldKey)} onChange={this.selectVal}>
+                        <option value="-unset-">-unset-</option>
                         {this.values.map(val => (
                             <option value={val.value}>{val.label}</option>
                         ))}
                     </select>
-                )} */}
+                )}
             </div>
         );
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 66df1eaf2..3700b08d6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2064,8 +2064,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         return styleFromLayoutString?.height === '0px' ? null : (
             <div
                 className="formattedTextBox"
-                onPointerEnter={action(() => (this._isHovering = true))}
-                onPointerLeave={action(() => (this._isHovering = false))}
+                onPointerEnter={action(() => {
+                    this._isHovering = true;
+                    this.layoutDoc[`_${this._props.fieldKey}_usePath`] && (this.Document.isHovering = true);
+                })}
+                onPointerLeave={action(() => (this.Document.isHovering = this._isHovering = false))}
                 ref={r => {
                     this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
                     this._oldWheel = r;
-- 
cgit v1.2.3-70-g09d2


From 059218b567ce57d3afa771bd764cde6f5f55b459 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 14 Apr 2024 17:22:10 -0400
Subject: clean up of freeform centeringShift and nativeScaling

---
 .../CollectionFreeFormBackgroundGrid.tsx           | 10 +++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 37 +++++++++++-----------
 2 files changed, 23 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
index 08dfb32ad..0acc99360 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
@@ -14,8 +14,8 @@ export interface CollectionFreeFormViewBackgroundGridProps {
     nativeDimScaling: () => number;
     zoomScaling: () => number;
     layoutDoc: Doc;
-    cachedCenteringShiftX: number;
-    cachedCenteringShiftY: number;
+    centeringShiftX: number;
+    centeringShiftY: number;
 }
 @observer
 export class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFormViewBackgroundGridProps> {
@@ -32,7 +32,7 @@ export class CollectionFreeFormBackgroundGrid extends React.Component<Collection
         const w = this.props.PanelWidth() / this.props.nativeDimScaling() + 2 * renderGridSpace;
         const h = this.props.PanelHeight() / this.props.nativeDimScaling() + 2 * renderGridSpace;
         const strokeStyle = this.props.color();
-        return !this.props.nativeDimScaling() ? null : (
+        return (
             <canvas
                 className="collectionFreeFormView-grid"
                 width={w}
@@ -41,8 +41,8 @@ export class CollectionFreeFormBackgroundGrid extends React.Component<Collection
                 ref={el => {
                     const ctx = el?.getContext('2d');
                     if (ctx) {
-                        const Cx = this.props.cachedCenteringShiftX % renderGridSpace;
-                        const Cy = this.props.cachedCenteringShiftY % renderGridSpace;
+                        const Cx = this.props.centeringShiftX % renderGridSpace;
+                        const Cy = this.props.centeringShiftY % renderGridSpace;
                         ctx.lineWidth = Math.min(1, Math.max(0.5, this.props.zoomScaling()));
                         ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]);
                         ctx.clearRect(0, 0, w, h);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 791124f50..3fab00968 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -169,17 +169,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @computed get nativeHeight() {
         return this._props.NativeHeight?.() || Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
     }
-    @computed get cachedCenteringShiftX(): number {
-        const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling;
+    @computed get centeringShiftX(): number {
+        const scaling = this.nativeDimScaling;
         return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : this._props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
-    @computed get cachedCenteringShiftY(): number {
+    @computed get centeringShiftY(): number {
+        const panLocAtCenter = !(this._props.isAnnotationOverlay || this._props.originTopLeft);
+        if (!panLocAtCenter) return 0;
         const dv = this.DocumentView?.();
-        const fitWidth = this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth;
-        const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling;
+        const aspect = !(this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth) && dv?.nativeWidth && dv?.nativeHeight;
+        const scaling = this.nativeDimScaling;
         // if freeform has a native aspect, then the panel height needs to be adjusted to match it
-        const aspect = dv?.nativeWidth && dv?.nativeHeight && !fitWidth ? dv.nativeHeight / dv.nativeWidth : this._props.PanelHeight() / this._props.PanelWidth();
-        return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : (aspect * this._props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
+        const height = aspect ? (dv.nativeHeight / dv.nativeWidth) * this._props.PanelWidth() : this._props.PanelHeight();
+        return height / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get panZoomXf() {
         return new Transform(this.panX(), this.panY(), 1 / this.zoomScaling());
@@ -187,7 +189,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @computed get screenToFreeformContentsXf() {
         return this._props
             .ScreenToLocalTransform() //
-            .translate(-this.cachedCenteringShiftX, -this.cachedCenteringShiftY)
+            .translate(-this.centeringShiftX, -this.centeringShiftY)
             .transform(this.panZoomXf);
     }
 
@@ -250,8 +252,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1));
     panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1));
     zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); //, NumCast(DocCast(this.Document.resolvedDataDoc)?.[this.scaleFieldKey], 1));
-    PanZoomCenterXf = () =>
-        this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
+    PanZoomCenterXf = () => (this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.centeringShiftX}px, ${this.centeringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`);
     ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy();
     getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
     isAnyChildContentActive = () => this._props.isAnyChildContentActive();
@@ -1114,9 +1115,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (scale !== undefined) {
             const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
             const newScale =
-                scale === 0
-                    ? NumCast(this.layoutDoc[this.scaleFieldKey])
-                    : Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this._props.PanelWidth() / Math.abs(bounds.width), this._props.PanelHeight() / Math.abs(bounds.height)));
+                scale === 0 ? NumCast(this.layoutDoc[this.scaleFieldKey]) : Math.min(maxZoom, (1 / this.nativeDimScaling) * scale * Math.min(this._props.PanelWidth() / Math.abs(bounds.width), this._props.PanelHeight() / Math.abs(bounds.height)));
             return {
                 panX: this._props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2,
                 panY: this._props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2,
@@ -1763,8 +1762,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     zoomScaling={this.zoomScaling}
                     layoutDoc={this.layoutDoc}
                     isAnnotationOverlay={this.isAnnotationOverlay}
-                    cachedCenteringShiftX={this.cachedCenteringShiftX}
-                    cachedCenteringShiftY={this.cachedCenteringShiftY}
+                    centeringShiftX={this.centeringShiftX}
+                    centeringShiftY={this.centeringShiftY}
                 />
             </div>
         );
@@ -1812,7 +1811,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     @computed get nativeDimScaling() {
-        if (this._firstRender || (this._props.isAnnotationOverlay && !this._props.annotationLayerHostsContent)) return 0;
+        if (this._firstRender || (this._props.isAnnotationOverlay && !this._props.annotationLayerHostsContent)) return 1;
         const nw = this.nativeWidth;
         const nh = this.nativeHeight;
         const hscale = nh ? this._props.PanelHeight() / nh : 1;
@@ -1866,9 +1865,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 style={{
                     pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : (this._props.pointerEvents?.() as any),
                     textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
-                    transform: `scale(${this.nativeDimScaling || 1})`,
-                    width: `${100 / (this.nativeDimScaling || 1)}%`,
-                    height: this._props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
+                    transform: `scale(${this.nativeDimScaling})`,
+                    width: `${100 / this.nativeDimScaling}%`,
+                    height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`,
                 }}>
                 {this.paintFunc ? (
                     <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads
-- 
cgit v1.2.3-70-g09d2


From 2caf7b7bb80b663b6ba585f88cdbd2d725f8505e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 25 Apr 2024 18:49:57 -0400
Subject: pinning freeform contents now captures the layout

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3fab00968..079a5d977 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1412,7 +1412,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             presentation_transition: 500,
             annotationOn: this.Document,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document);
+        PresBox.pinDocView(
+            anchor,
+            { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ? { ...pinProps.pinData, poslayoutview: pinProps.pinData.dataview } : {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } },
+            this.Document
+        );
 
         if (addAsAnnotation) {
             if (Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
-- 
cgit v1.2.3-70-g09d2

