From 63f9f9573dab9745d2f570e1917b325a474fdd93 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 28 Oct 2024 20:07:51 -0400
Subject: reworked LabelBox's to be fully editable.  gor rid of singleLine for
 label boxes. made a text_fitBox field to render text with a labelBox. fixed
 styleprovider in freeformview clusters to be untracked() to avoid
 invalidations.  added a default text color to Settings panel.   fixed
 clicking text buttons to not lose focus in labelBox.

---
 .../views/nodes/formattedText/RichTextMenu.tsx     | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 55e6a3a5b..65a415a23 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@mui/material';
-import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { lift, toggleMark, wrapIn } from 'prosemirror-commands';
 import { Mark, MarkType } from 'prosemirror-model';
@@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
     public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable
     private _linkToRef = React.createRef<HTMLInputElement>();
 
-    layoutDoc: Doc | undefined;
+    dataDoc: Doc | undefined;
     @observable public view?: EditorView & { TextView?: FormattedTextBox } = undefined;
     public editorProps: FieldViewProps | AntimodeMenuProps | undefined;
 
@@ -49,6 +49,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     @observable private _activeFontSize: string = '13px';
     @observable private _activeFontFamily: string = '';
+    @observable private _activeFitBox: boolean = false;
     @observable private _activeListType: string = '';
     @observable private _activeAlignment: string = 'left';
 
@@ -64,13 +65,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
     @observable private currentLink: string | undefined = '';
     @observable private showLinkDropdown: boolean = false;
 
-    _reaction: IReactionDisposer | undefined;
     constructor(props: AntimodeMenuProps) {
         super(props);
         makeObservable(this);
         runInAction(() => {
             RichTextMenu._instance.menu = this;
-            this.updateMenu(undefined, undefined, props, this.layoutDoc);
+            this.updateMenu(undefined, undefined, props, this.dataDoc);
             this._canFade = false;
             this.Pinned = true;
         });
@@ -101,6 +101,9 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
     @computed get fontHighlight() {
         return this._activeHighlightColor;
     }
+    @computed get fitBox() {
+        return this._activeFitBox;
+    }
     @computed get fontFamily() {
         return this._activeFontFamily;
     }
@@ -114,26 +117,16 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
         return this._activeAlignment;
     }
     @computed get textVcenter() {
-        return BoolCast(this.layoutDoc?._layout_centered);
-    }
-    _disposer: IReactionDisposer | undefined;
-    componentDidMount() {
-        // this._disposer = reaction(
-        //     () => DocumentView.Selected().slice(),
-        //     () => this.updateMenu(undefined, undefined, undefined, undefined)
-        // );
-    }
-    componentWillUnmount() {
-        this._disposer?.();
+        return BoolCast(this.dataDoc?._layout_centered, BoolCast(Doc.UserDoc().layout_centered));
     }
 
     @action
-    public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps | AntimodeMenuProps | undefined, layoutDoc: Doc | undefined) {
+    public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps | AntimodeMenuProps | undefined, dataDoc: Doc | undefined) {
         if (this._linkToRef.current?.getBoundingClientRect().width) {
             return;
         }
         this.view = view;
-        this.layoutDoc = layoutDoc;
+        this.dataDoc = dataDoc;
         props && (this.editorProps = props);
 
         // Don't do anything if the document/selection didn't change
@@ -147,12 +140,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
         const { activeSizes } = active;
         const { activeColors } = active;
         const { activeHighlights } = active;
-        const refDoc = DocumentView.Selected().lastElement()?.layoutDoc ?? Doc.UserDoc();
+        const refDoc = DocumentView.Selected().lastElement()?.dataDoc ?? Doc.UserDoc();
         const refField = (pfx => (pfx ? pfx + '_' : ''))(DocumentView.Selected().lastElement()?.LayoutFieldKey);
         const refVal = (field: string, dflt: string) => StrCast(refDoc[refField + field], StrCast(Doc.UserDoc()[field], dflt));
 
         this._activeListType = this.getActiveListStyle();
         this._activeAlignment = this.getActiveAlignment();
+        this._activeFitBox = BoolCast(refDoc[refField + 'fitBox'], BoolCast(Doc.UserDoc().fitBox));
         this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document._text_fontFamily, refVal('fontFamily', 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various';
         this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, refVal('fontSize', '10px')) : activeSizes[0];
         this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, refVal('fontColor', 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...';
@@ -181,7 +175,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                     toggleMark(mark.type, mark.attrs)(state, dispatch);
                 }
             }
-            //    this.updateMenu(this.view, undefined, undefined, this.layoutDoc);
         }
     };
 
@@ -195,8 +188,10 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                     return node.attrs.align || 'left';
                 }
             }
+        } else if (this.dataDoc) {
+            return StrCast(this.dataDoc.text_align) || 'left';
         }
-        return 'left';
+        return StrCast(Doc.UserDoc().textAlign) || 'left';
     };
 
     // finds font sizes and families in selection
@@ -330,6 +325,17 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
             this.view.focus();
         }
     };
+    toggleFitBox = () => {
+        if (this.dataDoc) {
+            const doc = this.dataDoc;
+            (document.activeElement as HTMLElement)?.blur();
+            doc.text_fitBox = !doc.text_fitBox;
+        } else {
+            Doc.UserDoc().fitBox = !Doc.UserDoc().fitBox;
+            Doc.UserDoc().textAlign = Doc.UserDoc().fitBox ? 'center' : undefined;
+        }
+        this.updateMenu(undefined, undefined, undefined, this.dataDoc);
+    };
     toggleBold = () => {
         if (this.view) {
             const mark = this.view.state.schema.mark(this.view.state.schema.marks.strong);
@@ -354,11 +360,14 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
         }
     };
 
-    setFontField = (value: string, fontField: 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => {
-        if (this.TextView && this.view) {
+    setFontField = (value: string, fontField: 'fitBox' | 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => {
+        if (this.dataDoc) {
+            this.dataDoc[`text_${fontField}`] = value;
+            this.updateMenu(undefined, undefined, undefined, this.dataDoc);
+        } else if (this.TextView && this.view) {
             const { text, paragraph } = this.view.state.schema.nodes;
             const selNode = this.view.state.selection.$anchor.node();
-            if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) {
+            if ((fontField === 'fontSize' && value === '0px') || (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type))) {
                 this.TextView.dataDoc[this.TextView.fieldKey + `_${fontField}`] = value;
                 this.view.focus();
             }
@@ -369,7 +378,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
             this.view.focus();
         } else {
             Doc.UserDoc()[fontField] = value;
-            // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
         }
     };
 
@@ -395,7 +403,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                 this.view!.dispatch(tx3);
             });
         this.view.focus();
-        // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
     };
 
     insertSummarizer(state: EditorState, dispatch: (tr: Transaction) => void) {
@@ -410,10 +417,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
     }
 
     vcenterToggle = () => {
-        this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered);
+        if (this.dataDoc) this.dataDoc._layout_centered = !this.dataDoc._layout_centered;
+        else Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered;
     };
-    align = (view: EditorView, dispatch: (tr: Transaction) => void, alignment: 'left' | 'right' | 'center') => {
-        if (this.RootSelected) {
+    align = (view: EditorView | undefined, dispatch: undefined | ((tr: Transaction) => void), alignment: 'left' | 'right' | 'center') => {
+        if (view && dispatch && this.RootSelected) {
             let { tr } = view.state;
             view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos) => {
                 if ([schema.nodes.paragraph, schema.nodes.heading].includes(node.type)) {
@@ -425,6 +433,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
             });
             view.focus();
             dispatch?.(tr);
+        } else {
+            if (this.dataDoc) {
+                this.dataDoc.text_align = alignment;
+            } else Doc.UserDoc().textAlign = alignment;
+            this.updateMenu(undefined, undefined, undefined, this.dataDoc);
         }
     };
 
@@ -702,7 +715,7 @@ interface RichTextMenuPluginProps {
 }
 export class RichTextMenuPlugin extends React.Component<RichTextMenuPluginProps> {
     update(view: EditorView & { TextView?: FormattedTextBox }, lastState: EditorState | undefined) {
-        RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.layoutDoc);
+        RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.dataDoc);
     }
     render() {
         return null;
-- 
cgit v1.2.3-70-g09d2

