From 40b8e5c30e7251db6258cac5b4ed5fb4a6a2418d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 7 Apr 2025 15:20:36 -0400
Subject: added multiToggle option to allow popup to stay up until explicitly
 untoggled. fixed multitoggle to honor toggleStatus.  fixed popup to follow
 target.   fixed setting text highlight background fro popup menu. fixed
 flashcardui buttons to have background sized properly.

---
 src/client/views/collections/CollectionCardDeckView.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 756b37f99..50de7c601 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -23,7 +23,8 @@ import { undoable, UndoManager } from '../../util/UndoManager';
 import { PinDocView, PinProps } from '../PinFuncs';
 import { StyleProp } from '../StyleProp';
 import { TagItem } from '../TagsView';
-import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { DocumentViewProps } from '../nodes/DocumentContentsView';
+import { DocumentView } from '../nodes/DocumentView';
 import { FocusViewOptions } from '../nodes/FocusViewOptions';
 import './CollectionCardDeckView.scss';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-- 
cgit v1.2.3-70-g09d2


From d993a3a389464773d04b31de5d427ec4eb5e3d5b Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 1 May 2025 15:32:10 -0400
Subject: cleaned up, a bit, how wheel events are blocked from propagating.

---
 src/client/views/collections/CollectionCardDeckView.tsx      | 10 +---------
 src/client/views/collections/CollectionCarousel3DView.tsx    |  9 ++-------
 src/client/views/collections/CollectionCarouselView.tsx      |  7 +------
 src/client/views/collections/CollectionStackingView.tsx      |  7 +------
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  5 +----
 .../collections/collectionFreeForm/FaceCollectionBox.tsx     | 12 +-----------
 .../collections/collectionSchema/CollectionSchemaView.tsx    | 11 +----------
 src/client/views/nodes/DiagramBox.tsx                        | 12 +-----------
 src/client/views/nodes/calendarBox/CalendarBox.tsx           |  7 +------
 src/client/views/nodes/formattedText/FormattedTextBox.tsx    |  6 +-----
 10 files changed, 11 insertions(+), 75 deletions(-)

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

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 50de7c601..d5edc3e0b 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -40,7 +40,6 @@ import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 export class CollectionCardView extends CollectionSubView() {
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _disposers: { [key: string]: IReactionDisposer } = {};
-    private _oldWheel: HTMLElement | null = null;
     private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
     private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!;
     private _draggerRef = React.createRef<HTMLDivElement>();
@@ -56,13 +55,7 @@ export class CollectionCardView extends CollectionSubView() {
     }
     protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
         this._dropDisposer?.();
-        if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
-        }
-        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-        this._oldWheel = ele;
-        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-        ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+        this.fixWheelEvents(ele, this._props.isContentActive);
     };
     @computed get cardWidth() {
         return NumCast(this.layoutDoc._cardWidth, 50);
@@ -487,7 +480,6 @@ export class CollectionCardView extends CollectionSubView() {
             );
         });
     }
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
 
     contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
     docViewProps = (): DocumentViewProps => ({
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 9c8ef5519..755e31925 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -25,7 +25,6 @@ const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = requi
 @observer
 export class CollectionCarousel3DView extends CollectionSubView() {
     private _dropDisposer?: DragManager.DragDropDisposer;
-    private _oldWheel: HTMLElement | null = null;
 
     constructor(props: SubCollectionViewProps) {
         super(props);
@@ -44,10 +43,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
         if (ele) {
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
         }
-        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-        this._oldWheel = ele;
-        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-        ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+        this.fixWheelEvents(ele, this._props.isContentActive);
     };
 
     @computed get scrollSpeed() {
@@ -101,7 +97,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
     focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => {
         const docs = DocListCast(this.Document[this.fieldKey]);
         if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
-            const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor));
+            const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor)!);
             options.didMove = newIndex !== this.layoutDoc._carousel_index;
             options.didMove && (this.layoutDoc._carousel_index = newIndex);
         }
@@ -221,7 +217,6 @@ export class CollectionCarousel3DView extends CollectionSubView() {
         return this.panelWidth() * (1 - index);
     }
 
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
     curDoc = () => this.carouselItems[NumCast(this.layoutDoc._carousel_index)]?.layout;
     answered = (correct: boolean) => (!correct || !this.curDoc() || NumCast(this.layoutDoc._carousel_index) === this.carouselItems.length - 1) && this.changeSlide(1);
     docViewProps = () => ({
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 975dc52fe..ac1981012 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -21,7 +21,6 @@ import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 export class CollectionCarouselView extends CollectionSubView() {
     private _dropDisposer?: DragManager.DragDropDisposer;
 
-    _oldWheel: HTMLElement | null = null;
     _fadeTimer: NodeJS.Timeout | undefined;
     @observable _last_index = this.carouselIndex;
     @observable _last_opacity = 1;
@@ -43,10 +42,7 @@ export class CollectionCarouselView extends CollectionSubView() {
         if (ele) {
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
         }
-        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-        this._oldWheel = ele;
-        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-        ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+        this.fixWheelEvents(ele, this._props.isContentActive);
     };
 
     @computed get captionMarginX(){ return NumCast(this.layoutDoc.caption_xMargin, 50); } // prettier-ignore
@@ -115,7 +111,6 @@ export class CollectionCarouselView extends CollectionSubView() {
               : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
                 ? false
                 : undefined; // prettier-ignore
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
 
     renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => {
         return (
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index f11e646cc..be570564b 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -55,7 +55,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
     // Doesn't look like this field is being used anywhere. Obsolete?
     _columnStart: number = 0;
-    _oldWheel: HTMLElement | null = null;
 
     @observable _refList: HTMLElement[] = [];
     // map of node headers to their heights. Used in Masonry
@@ -721,7 +720,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         return this._props.isContentActive() === false ? 'none' : undefined;
     }
 
-    onPassiveWheel = (e: WheelEvent) => this._props.isContentActive() && e.stopPropagation();
     render() {
         TraceMobx();
         const editableViewProps = {
@@ -744,10 +742,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         ref={ele => {
                             this._masonryGridRef = ele;
                             this.createDashEventsTarget(ele); // so the whole grid is the drop target?
-                            this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                            this._oldWheel = ele;
-                            // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-                            ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+                            this.fixWheelEvents(ele, this._props.isContentActive);
                         }}
                         style={{
                             overflowY: this.isContentActive() ? 'auto' : 'hidden',
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c4971c204..2364fd74a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -2268,10 +2268,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 id={this._paintedId}
                 ref={r => {
                     this.createDashEventsTarget(r);
-                    this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                    this._oldWheel = r;
-                    // prevent wheel events from passivly propagating up through containers
-                    r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+                    this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel);
                     r?.addEventListener('mouseleave', this.onMouseLeave);
                     r?.addEventListener('mouseenter', this.onMouseEnter);
                 }}
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index 624c85beb..142085e14 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -150,11 +150,6 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
         FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document);
     }, 'remove doc from face');
 
-    /**
-     * This stops scroll wheel events when they are used to scroll the face collection.
-     */
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
-
     render() {
         return (
             <div className="face-document-item" ref={ele => this.createDropTarget(ele!)}>
@@ -181,12 +176,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         style={{
                             pointerEvents: this._props.isContentActive() ? undefined : 'none',
                         }}
-                        ref={action((ele: HTMLDivElement | null) => {
-                            this._listRef?.removeEventListener('wheel', this.onPassiveWheel);
-                            this._listRef = ele;
-                            // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-                            ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
-                        })}>
+                        ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
                         {FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
                             const [name, type] = ImageCastToNameType(doc?.[Doc.LayoutDataKey(doc)]) ?? ['-missing-', '.png'];
                             return (
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 82ca96839..c06391f35 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1293,7 +1293,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     isContentActive = () => this._props.isSelected() || this._props.isContentActive();
     screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0);
     previewWidthFunc = () => this.previewWidth;
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
     displayedDocsFunc = () => this.docsWithDrag.docs;
     render() {
         return (
@@ -1307,15 +1306,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this.setColDrag(false);
                 }}>
                 <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} />
-                <div
-                    className="schema-table"
-                    style={{ width: `calc(100% - ${this.previewWidth}px)` }}
-                    onWheel={e => this._props.isContentActive() && e.stopPropagation()}
-                    ref={ele => {
-                        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-                        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                        (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
-                    }}>
+                <div className="schema-table" style={{ width: `calc(100% - ${this.previewWidth}px)` }} onWheel={e => this._props.isContentActive() && e.stopPropagation()} ref={ele => this.fixWheelEvents(ele, this._props.isContentActive)}>
                     <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
                             <IconButton
diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx
index 3b666bad5..7cfccf0dc 100644
--- a/src/client/views/nodes/DiagramBox.tsx
+++ b/src/client/views/nodes/DiagramBox.tsx
@@ -185,11 +185,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return '( )';
     };
 
-    /**
-     * This stops scroll wheel events when they are used to scroll the face collection.
-     */
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
-
     render() {
         return (
             <div
@@ -197,12 +192,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 style={{
                     pointerEvents: this._props.isContentActive() ? undefined : 'none',
                 }}
-                ref={action((ele: HTMLDivElement | null) => {
-                    this._boxRef?.removeEventListener('wheel', this.onPassiveWheel);
-                    this._boxRef = ele;
-                    // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-                    ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
-                })}>
+                ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
                 <div className="DIYNodeBox-searchbar">
                     <input type="text" value={this._inputValue} onKeyDown={action(e => e.key === 'Enter' && this.generateMermaidCode())} onChange={action(e => (this._inputValue = e.target.value))} />
                     <button type="button" onClick={this.generateMermaidCode}>
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index fa863e123..2b20a666d 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -24,7 +24,6 @@ type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDa
 export class CalendarBox extends CollectionSubView() {
     _calendarRef: HTMLDivElement | null = null;
     _calendar: Calendar | undefined;
-    _oldWheel: HTMLElement | null = null;
     _observer: ResizeObserver | undefined;
     _eventsDisposer: IReactionDisposer | undefined;
     _selectDisposer: IReactionDisposer | undefined;
@@ -194,7 +193,6 @@ export class CalendarBox extends CollectionSubView() {
         setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end));
     };
 
-    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
     render() {
         return (
             <div
@@ -218,10 +216,7 @@ export class CalendarBox extends CollectionSubView() {
                 }}
                 ref={r => {
                     this.createDashEventsTarget(r);
-                    this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                    this._oldWheel = r;
-                    // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
-                    r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+                    this.fixWheelEvents(r, this._props.isContentActive);
 
                     if (r) {
                         this._observer?.disconnect();
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d6fa3172d..c51f6c38b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2120,11 +2120,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         ) : styleFromLayout?.height === '0px' ? null : (
             <div
                 className="formattedTextBox"
-                ref={r => {
-                    this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
-                    this._oldWheel = r;
-                    r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
-                }}
+                ref={r => this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel)}
                 style={{
                     ...(this._props.dontScale
                         ? {}
-- 
cgit v1.2.3-70-g09d2

