diff options
| author | bobzel <zzzman@gmail.com> | 2025-06-23 13:26:59 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2025-06-23 13:26:59 -0400 |
| commit | 35bd9e51f7cef551382025a5459d68eddd8f028b (patch) | |
| tree | 8edab8e8e283d06bdeba632959fd51e1488c4af5 /src/client/views/collections | |
| parent | e7a96fa043cfc9c3c426e09bbef42c8df88a45f6 (diff) | |
fixed invalidations to not trigger creating new refs when ref= was assigned to an anonymous function. fixed scribble erase to not delete everything it overlaps, just things it intersects with or contains. fixed ink to have a Math mode and fixed math recognition myscript calls.
Diffstat (limited to 'src/client/views/collections')
13 files changed, 91 insertions, 80 deletions
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 7f639a11e..7a4408931 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -256,9 +256,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { const height = () => this.getDocHeight(doc); let dref: Opt<DocumentView>; const noteTakingDocTransform = () => this.getDocTransform(doc, dref); + const setRef = (r: DocumentView | null) => (dref = r || undefined); return ( <DocumentView - ref={r => (dref = r || undefined)} + ref={setRef} Document={doc} TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined} pointerEvents={this.blockPointerEventsWhenDragging} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index bdeb7d944..fbdd23315 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as CSS from 'csstype'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, DivHeight, returnNone, returnZero, setupMoveUpEvents, smoothScroll } from '../../../ClientUtils'; @@ -391,10 +391,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection }); // This following three functions must be from the view Mehek showed - columnDividerDown = (e: React.PointerEvent) => { - runInAction(() => { - this._cursor = 'grabbing'; - }); + columnDividerDown = action((e: React.PointerEvent) => { + this._cursor = 'grabbing'; const batch = UndoManager.StartBatch('stacking width'); setupMoveUpEvents( this, @@ -406,7 +404,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection }), emptyFunction ); - }; + }); @action onDividerMove = (e: PointerEvent) => { this.Document._layout_columnWidth = Math.max(10, (this._props.DocumentView?.().screenToViewTransform().transformPoint(e.clientX, 0)[0] ?? 0) - this.xMargin); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 8c535534a..b5efa7a72 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -304,6 +304,12 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< ContextMenu.Instance.displayMenu(pt[0], pt[1], undefined, true); }; + setRef = (r: HTMLDivElement | null) => { + if (this._headerRef && this._props.colHeaderRefs.includes(this._headerRef)) this._props.colHeaderRefs.splice(this._props.colStackRefs.indexOf(this._headerRef), 1); + r && this._props.colHeaderRefs.push(r); + this._headerRef = r; + }; + @computed get innards() { TraceMobx(); const key = this._props.pivotField; @@ -315,11 +321,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< <div key={heading} className="collectionStackingView-sectionHeader" - ref={r => { - if (this._headerRef && this._props.colHeaderRefs.includes(this._headerRef)) this._props.colHeaderRefs.splice(this._props.colStackRefs.indexOf(this._headerRef), 1); - r && this._props.colHeaderRefs.push(r); - this._headerRef = r; - }} + ref={this.setRef} style={{ marginTop: 0, marginBottom: this._props.gridGap, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index bee5d016d..4625965b4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -407,6 +407,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this._props.fieldKey}_annotations`) || false; moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => this.moveDocument(doc, targetCollection, addDocument) || false; + setRef = (r: HTMLDivElement | null) => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r); @observable _headerHeight = 0; @computed get content() { const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string; @@ -428,7 +429,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree <div className="collectionTreeView-contents" key="tree" - ref={r => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r)} + ref={this.setRef} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), color: color(), diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 5b2f1ff81..f84c7d3c0 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -1294,6 +1294,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return null; } + const setRef = (r: TreeView | null) => treeViewRefs.set(child, r || undefined); const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => { if (parent instanceof TreeView && parent._props.treeView.fileSysMode && !newParent.isFolder) return; const fieldKey = Doc.LayoutDataKey(newParent); @@ -1317,7 +1318,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return ( <TreeView key={child[Id]} - ref={r => treeViewRefs.set(child, r || undefined)} + ref={setRef} Document={pair.layout} dataDoc={pair.data} treeViewParent={treeViewParent} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 32ace463d..6e9e503f4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -562,7 +562,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const B = this.screenToFreeformContentsXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); const inkDoc = this.createInkDoc(points, B); if (Doc.ActiveInk === InkInkTool.Highlight) inkDoc.$backgroundColor = 'transparent'; - if (Doc.ActiveInk === InkInkTool.Write) { + if ([InkInkTool.Write, InkInkTool.Math].includes(Doc.ActiveInk)) { this.unprocessedDocs.push(inkDoc); CollectionFreeFormView.collectionsWithUnprocessedInk.add(this); } @@ -2220,18 +2220,41 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ); }; + @computed get inkEraser() { + return ( + Doc.ActiveTool === InkTool.Eraser && + Doc.ActiveEraser === InkEraserTool.Radius && + this._showEraserCircle && ( + <div + onPointerMove={this.onCursorMove} + style={{ + position: 'fixed', + left: this._eraserX, + top: this._eraserY, + width: (ActiveEraserWidth() + 5) * 2, + height: (ActiveEraserWidth() + 5) * 2, + borderRadius: '50%', + border: '1px solid gray', + transform: 'translate(-50%, -50%)', + }} + /> + ) + ); + } + + setRef = (r: HTMLDivElement | null) => { + this.createDashEventsTarget(r); + this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel); + r?.addEventListener('mouseleave', this.onMouseLeave); + r?.addEventListener('mouseenter', this.onMouseEnter); + }; render() { TraceMobx(); return ( <div className="collectionfreeformview-container" id={this._paintedId} - ref={r => { - this.createDashEventsTarget(r); - this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel); - r?.addEventListener('mouseleave', this.onMouseLeave); - r?.addEventListener('mouseenter', this.onMouseEnter); - }} + ref={this.setRef} onWheel={this.onPointerWheel} onClick={this.onClick} onPointerDown={this.onPointerDown} @@ -2246,21 +2269,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection width: `${100 / this.nativeDimScaling}%`, height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`, }}> - {Doc.ActiveTool === InkTool.Eraser && Doc.ActiveEraser === InkEraserTool.Radius && this._showEraserCircle && ( - <div - onPointerMove={this.onCursorMove} - style={{ - position: 'fixed', - left: this._eraserX, - top: this._eraserY, - width: (ActiveEraserWidth() + 5) * 2, - height: (ActiveEraserWidth() + 5) * 2, - borderRadius: '50%', - border: '1px solid gray', - transform: 'translate(-50%, -50%)', - }} - /> - )} + {this.inkEraser} {this.paintFunc ? ( <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads ) : this._lightboxDoc ? ( diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 142085e14..c31558dff 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -150,6 +150,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document); }, 'remove doc from face'); + setRef = (r: HTMLDivElement | null) => this.fixWheelEvents(r, this._props.isContentActive); render() { return ( <div className="face-document-item" ref={ele => this.createDropTarget(ele!)}> @@ -176,7 +177,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() { style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none', }} - ref={r => this.fixWheelEvents(r, this._props.isContentActive)}> + ref={this.setRef}> {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/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index ff78b332a..4191aaca8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -762,29 +762,26 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps } e.stopPropagation(); }; + setRef = (r: HTMLDivElement | null) => { + r?.addEventListener('dashDragMovePause', this.onDragMovePause as EventListenerOrEventListenerObject); + this.MarqueeRef = r; + }; render() { return ( - <> - <div - className="marqueeView" - ref={r => { - r?.addEventListener('dashDragMovePause', this.onDragMovePause as EventListenerOrEventListenerObject); - this.MarqueeRef = r; - }} - style={{ - overflow: StrCast(this._props.Document._overflow), - cursor: Doc.ActiveTool === InkTool.Ink || this._visible ? 'crosshair' : 'pointer', - }} - onDragOver={e => e.preventDefault()} - onScroll={e => { - e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0; - }} - onClick={this.onClick} - onPointerDown={this.onPointerDown}> - {this._visible ? this.marqueeDiv : null} - {this.props.children} - </div> - </> + <div + className="marqueeView" + ref={this.setRef} + style={{ + overflow: StrCast(this._props.Document._overflow), + cursor: Doc.ActiveTool === InkTool.Ink || this._visible ? 'crosshair' : 'pointer', + }} + onDragOver={e => e.preventDefault()} + onScroll={e => (e.currentTarget.scrollTop = (e.currentTarget.scrollLeft = 0))} // prettier-ignore + onClick={this.onClick} + onPointerDown={this.onPointerDown}> + {this._visible ? this.marqueeDiv : null} + {this.props.children} + </div> ); } } diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index d0a1e6f0d..435f618d9 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -158,14 +158,13 @@ export class CollectionLinearView extends CollectionSubView() { let dref: Opt<HTMLDivElement>; const docXf = () => this.getTransform(dref); + const setRef = (r: HTMLDivElement | null) => (dref = r || undefined); // const scalable = pair.layout.onClick || pair.layout.onDragStart; return hidden ? null : ( <div className={preview ? 'preview' : `collectionLinearView-docBtn`} key={doc[Id]} - ref={r => { - dref = r || undefined; - }} + ref={setRef} style={{ pointerEvents: 'all', width: NumCast(doc._width), diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 6442385c0..2576bdf9b 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1043,17 +1043,16 @@ export class CollectionSchemaView extends CollectionSubView() { if (!this._oldKeysWheel?.scrollTop && e.deltaY <= 0) e.preventDefault(); e.stopPropagation(); }; + setRef = (r: HTMLDivElement | null) => { + this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel); + this._oldKeysWheel = r; + r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false }); + }; _oldKeysWheel: HTMLDivElement | null = null; @computed get keysDropdown() { return ( <div className="schema-key-search"> - <div - className="schema-key-list" - ref={r => { - this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel); - this._oldKeysWheel = r; - r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false }); - }}> + <div className="schema-key-list" ref={this.setRef}> {this._menuKeys.map(key => ( <div key={key} @@ -1294,6 +1293,9 @@ export class CollectionSchemaView extends CollectionSubView() { screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; displayedDocsFunc = () => this.docsWithDrag.docs; + setColHdrRef = (r: SchemaColumnHeader | null) => r && this._headerRefs.push(r); + setPreviewRef = (r: HTMLDivElement | null) => (this._previewRef = r); + render() { return ( <div @@ -1331,7 +1333,7 @@ export class CollectionSchemaView extends CollectionSubView() { {this.columnKeys.map((key, index) => ( <SchemaColumnHeader //cleanupField={this.cleanupComputedField} - ref={r => r && this._headerRefs.push(r)} + ref={this.setColHdrRef} keysDropdown={this.keysDropdown} schemaView={this} columnWidth={() => CollectionSchemaView._minColWidth} //TODO: update @@ -1379,11 +1381,7 @@ export class CollectionSchemaView extends CollectionSubView() { </div> {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown} />} {this.previewWidth > 0 && ( - <div - style={{ width: `${this.previewWidth}px` }} - ref={ref => { - this._previewRef = ref; - }}> + <div style={{ width: `${this.previewWidth}px` }} ref={this.setPreviewRef}> {Array.from(this._selectedDocs).lastElement() && ( <DocumentView Document={Array.from(this._selectedDocs).lastElement()} diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index 9ad94cb31..412daa105 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -341,12 +341,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro return <span className="editableView-static">{this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : ''}</span>; }; + setRef = (r: HTMLDivElement | null) => (this._inputref = r); + renderEditor = () => { return ( <div contentEditable className="schemaField-editing" - ref={r => (this._inputref = r)} + ref={this.setRef} style={{ minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20 }} onBlur={() => (this._props.refSelectModeInfo.enabled ? setTimeout(() => this.setIsFocused(true), 1000) : this.finalizeEdit(false, true, false))} onInput={this.onChange} diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 134f2ed31..64bfab856 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -118,6 +118,10 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea return { color, fieldProps, cursor }; }; + setRef = (r: EditableView | null) => { + this._inputRef = r; + this._props.autoFocus && r?.setIsFocused(true); + }; @computed get editableView() { const { color, fieldProps } = this.renderProps(this._props); @@ -133,10 +137,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea width: '100%', }}> <EditableView - ref={r => { - this._inputRef = r; - this._props.autoFocus && r?.setIsFocused(true); - }} + ref={this.setRef} oneLine={true} allowCRs={false} contents={''} diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 8b34b4139..02e0d8100 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -185,6 +185,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro return eqSymbol + modField; }; + setRef = (r: SchemaCellField | null) => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true); @computed get defaultCellContent() { const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this._props); @@ -204,7 +205,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro Doc={this._props.Doc} highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))} getCells={(text: string) => this._props.eqHighlightFunc(this.adjustSelfReference(text))} - ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)} + ref={this.setRef} oneLine={this._props.oneLine} contents={undefined} fieldContents={fieldProps} |
