diff options
| author | bobzel <zzzman@gmail.com> | 2024-08-08 12:27:40 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-08-08 12:27:40 -0400 |
| commit | 4574b7f03ccc85c4bebdbfd9475788456086704f (patch) | |
| tree | d23d30343541b9af029ef418492d629d3cc710d7 /src/client/views/collections | |
| parent | e1db06d59d580aa640212a0d3a6aeecb9122bdf0 (diff) | |
many changes to add typing in place of 'any's etc
Diffstat (limited to 'src/client/views/collections')
20 files changed, 231 insertions, 275 deletions
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index a08a7c7c1..9eb16917b 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -6,11 +6,11 @@ import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { CollectionStackingView } from './CollectionStackingView'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; @observer export class CollectionCalendarView extends CollectionSubView() { - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index de46180e6..28a769896 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -18,7 +18,7 @@ import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import './CollectionCardDeckView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; enum cardSortings { Time = 'time', @@ -68,7 +68,7 @@ export class CollectionCardView extends CollectionSubView() { } }; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -86,11 +86,11 @@ export class CollectionCardView extends CollectionSubView() { } @computed get cardSort_customField() { - return StrCast(this.Document.cardSort_customField) as any as 'chat' | 'star' | 'idea' | 'like'; + return StrCast(this.Document.cardSort_customField) as 'chat' | 'star' | 'idea' | 'like'; } @computed get cardSort() { - return StrCast(this.Document.cardSort) as any as cardSortings; + return StrCast(this.Document.cardSort) as cardSortings; } /** * how much to scale down the contents of the view so that everything will fit @@ -428,7 +428,6 @@ export class CollectionCardView extends CollectionSubView() { return ( <div className="card-button-container" style={{ width: `${totalWidth}px` }}> {numberRange(amButtons).map(i => ( - // eslint-disable-next-line jsx-a11y/control-has-associated-label <button key={i} type="button" @@ -496,8 +495,8 @@ export class CollectionCardView extends CollectionSubView() { className="collectionCardView-outer" ref={this.createDashEventsTarget} style={{ - background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor), - color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color), + background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, + color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string, }}> <div className="card-wrapper" diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 2adad68e0..c969c39e5 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { computed, makeObservable } from 'mobx'; @@ -18,7 +16,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; enum cardMode { PRACTICE = 'practice', @@ -35,7 +33,7 @@ export class CollectionCarouselView extends CollectionSubView() { get practiceField() { return this.fieldKey + "_practice"; } // prettier-ignore get starField() { return this.fieldKey + "_star"; } // prettier-ignore - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -124,7 +122,7 @@ export class CollectionCarouselView extends CollectionSubView() { this.advance(e); }; - captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string): any => { + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string) => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption_' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property); @@ -161,7 +159,7 @@ export class CollectionCarouselView extends CollectionSubView() { onDoubleClickScript={this.onContentDoubleClick} onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} - isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction} + isContentActive={(this._props.childContentsActive ?? this._props.isContentActive() === false) ? returnFalse : emptyFunction} hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions renderDepth={this._props.renderDepth + 1} LayoutTemplate={this._props.childLayoutTemplate} @@ -177,7 +175,7 @@ export class CollectionCarouselView extends CollectionSubView() { key="caption" onWheel={StopEvent} style={{ - borderRadius: this._props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding), + borderRadius: this._props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding) as string, marginRight: this.marginX, marginLeft: this.marginX, width: `calc(100% - ${this.marginX * 2}px)`, @@ -218,8 +216,8 @@ export class CollectionCarouselView extends CollectionSubView() { ref={this.createDashEventsTarget} onContextMenu={this.specificMenu} style={{ - background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor), - color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color), + background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, + color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string, }}> {this.content} {/* Displays a message to the user to add more flashcards if they are in practice mode and no flashcards are there. */} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5a142cc6e..e0aa79c7b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,14 +1,15 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; +import ResizeObserver from 'resize-observer-polyfill'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, DivWidth, incrementTitleCopy, returnTrue, UpdateIcon } from '../../../ClientUtils'; import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; +import { FieldType } from '../../../fields/ObjectField'; import { ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { GetEffectiveAcl, inheritParentAcls, SetPropSetterCb } from '../../../fields/util'; @@ -31,17 +32,15 @@ import { UndoStack } from '../UndoStack'; import './CollectionDockingView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; -const _global = (window /* browser */ || global) /* node */ as any; - @observer export class CollectionDockingView extends CollectionSubView() { - static tabClass: JSX.Element | null = null; + static tabClass: unknown = null; /** * Initialize by assigning the add split method to DocumentView and by * configuring golden layout to render its documents using the specified React component * @param ele - typically would be set to TabDocView */ - public static Init(ele: JSX.Element | null) { + public static Init(ele: unknown) { this.tabClass = ele; DocumentView.addSplit = CollectionDockingView.AddSplit; } @@ -54,11 +53,13 @@ export class CollectionDockingView extends CollectionSubView() { private _flush: UndoManager.Batch | undefined; private _unmounting = false; private _ignoreStateChange = ''; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private _goldenLayout: any = null; + // eslint-disable-next-line @typescript-eslint/no-explicit-any public tabMap: Set<any> = new Set(); public get HasFullScreen() { return this._goldenLayout._maximisedItem !== null; } - private _goldenLayout: any = null; static _highlightStyleSheet = addStyleSheet(); constructor(props: SubCollectionViewProps) { @@ -66,8 +67,8 @@ export class CollectionDockingView extends CollectionSubView() { makeObservable(this); if (this._props.renderDepth < 0) CollectionDockingView.Instance = this; // Why is this here? - (window as any).React = React; - (window as any).ReactDOM = ReactDOM; + (window as unknown as { React: unknown }).React = React; + (window as unknown as { ReactDOM: unknown }).ReactDOM = ReactDOM; DragManager.StartWindowDrag = this.StartOtherDrag; this.Document.myTrails; // this is equivalent to having a prefetchProxy for myTrails which is needed for the My Trails button in the UI which assumes that Doc.ActiveDashboard.myTrails is legit... } @@ -89,10 +90,11 @@ export class CollectionDockingView extends CollectionSubView() { }; tabItemDropped = () => DragManager.CompleteWindowDrag?.(false); + // eslint-disable-next-line @typescript-eslint/no-explicit-any tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => { this._flush = this._flush ?? UndoManager.StartBatch('tab move'); - const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc; - dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc])); + //const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc; + //dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc])); DragManager.CompleteWindowDrag = (aborted: boolean) => { if (aborted) { proxy._dragListener.AbortDrag(); @@ -130,12 +132,13 @@ export class CollectionDockingView extends CollectionSubView() { } @undoBatch + // eslint-disable-next-line @typescript-eslint/no-explicit-any public static ReplaceTab(document: Doc, mods: OpenWhereMod, stack: any, panelName: string, addToSplit?: boolean, keyValue?: boolean): boolean { const instance = CollectionDockingView.Instance; if (!instance) return false; const newConfig = DashboardView.makeDocumentConfig(document, panelName, undefined, keyValue); if (!panelName && stack) { - const activeContentItemIndex = stack.contentItems.findIndex((item: any) => item.config === stack._activeContentItem.config); + const activeContentItemIndex = stack.contentItems.findIndex((item: { config: unknown }) => item.config === stack._activeContentItem.config); const newContentItem = stack.layoutManager.createContentItem(newConfig, instance._goldenLayout); stack.addChild(newContentItem.contentItems[0], undefined); stack.contentItems[activeContentItemIndex].remove(); @@ -155,6 +158,7 @@ export class CollectionDockingView extends CollectionSubView() { } @undoBatch + // eslint-disable-next-line @typescript-eslint/no-explicit-any public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) { return Array.from(CollectionDockingView.Instance?.tabMap.keys() ?? []).findIndex(tab => tab.DashDoc === doc) !== -1 ? CollectionDockingView.CloseSplit(doc) : CollectionDockingView.AddSplit(doc, location, stack, panelName, keyValue); } @@ -163,6 +167,7 @@ export class CollectionDockingView extends CollectionSubView() { // Creates a split on any side of the docking view based on the passed input pullSide and then adds the Document to the requested side // @action + // eslint-disable-next-line @typescript-eslint/no-explicit-any public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) { if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document); if (!CollectionDockingView.Instance) return false; @@ -321,7 +326,7 @@ export class CollectionDockingView extends CollectionSubView() { * @param target * @param title */ - titleChanged = (target: any, value: any) => { + titleChanged = (target: Doc, value: FieldType) => { const title = Field.toString(value); if (title.startsWith('@') && !title.substring(1).match(/[()[\]@]/) && title.length > 1) { const embedding = DocListCast(target.proto_embeddings).lastElement(); @@ -340,7 +345,7 @@ export class CollectionDockingView extends CollectionSubView() { () => DocumentView.LightboxDoc(), doc => setTimeout(() => !doc && this.onResize()) ); - new _global.ResizeObserver(this.onResize).observe(this._containerRef.current); + new ResizeObserver(this.onResize).observe(this._containerRef.current); this._reactionDisposer = reaction( () => StrCast(this.Document.dockingConfig), config => { @@ -429,7 +434,7 @@ export class CollectionDockingView extends CollectionSubView() { @action onPointerDown = (e: React.PointerEvent): void => { let hitFlyout = false; - for (let par = e.target as any; !hitFlyout && par; par = par.parentElement) { + for (let par = e.target as HTMLElement | null; !hitFlyout && par; par = par.parentElement) { hitFlyout = par.className === 'dockingViewButtonSelector'; } if (!hitFlyout) { @@ -514,6 +519,7 @@ export class CollectionDockingView extends CollectionSubView() { return changesMade; }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any tabDestroyed = (tab: any) => { this._flush = this._flush ?? UndoManager.StartBatch('tab movement'); const dashDoc = tab.DashDoc; @@ -531,18 +537,21 @@ export class CollectionDockingView extends CollectionSubView() { const { fieldKey } = CollectionDockingView.Instance.props; Doc.RemoveDocFromList(dview, fieldKey, dashDoc); this.tabMap.delete(tab); - tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); + tab._disposers && Object.values(tab._disposers).forEach(disposer => (disposer as () => void)()); this.stateChanged(); } }; - tabCreated = (tab: any) => { + tabCreated = (tab: { contentItem: { element: HTMLElement[] } }) => { this.tabMap.add(tab); - tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content) + // InitTab is added to the tab's HTMLElement in TabDocView + const tabdocviewContent = tab.contentItem.element[0]?.firstChild?.firstChild as unknown as { InitTab?: (tab: object) => void }; + tabdocviewContent?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content) }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any stackCreated = (stackIn: any) => { const stack = stackIn.header ? stackIn : stackIn.origin; - stack.header?.element.on('mousedown', (e: any) => { + stack.header?.element.on('mousedown', (e: MouseEvent) => { const dashboard = Doc.ActiveDashboard; if (dashboard && e.target === stack.header?.element[0] && e.button === 2) { dashboard.pane_count = NumCast(dashboard.pane_count) + 1; @@ -595,7 +604,7 @@ export class CollectionDockingView extends CollectionSubView() { }) ); - stack.element.click((e: any) => { + stack.element.click((e: { originalEvent: MouseEvent }) => { if (stack.contentItems.length === 0 && Array.from(document.elementsFromPoint(e.originalEvent.x, e.originalEvent.y)).some(ele => ele?.className === 'empty-tabs-message')) { addNewDoc(); } @@ -633,7 +642,7 @@ export class CollectionDockingView extends CollectionSubView() { ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function openInLightbox(doc: any) { + function openInLightbox(doc: Doc) { CollectionDockingView.Instance?._props.addDocTab(doc, OpenWhere.lightboxAlways); }, 'opens up document in a lightbox', @@ -641,33 +650,22 @@ ScriptingGlobals.add( ); ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function openDoc(doc: any, where: OpenWhere) { + function openDoc(doc: Doc | string, where: OpenWhere) { switch (where) { case OpenWhere.addRight: - return CollectionDockingView.AddSplit(doc, OpenWhereMod.right); + return doc instanceof Doc && CollectionDockingView.AddSplit(doc, OpenWhereMod.right); case OpenWhere.overlay: default: - // prettier-ignore switch (doc) { case '<ScriptingRepl />': return OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); case "<UndoStack />": return OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Undo stack' }); - default: - } - Doc.AddToMyOverlay(doc); - return true; + default: return doc instanceof Doc && Doc.AddToMyOverlay(doc); + } // prettier-ignore } }, 'opens up document in location specified', '(doc: any)' ); -ScriptingGlobals.add( - // eslint-disable-next-line prefer-arrow-callback - function openRepl() { - return 'openRepl'; - }, - 'opens up document in screen overlay layer', - '(doc: any)' -); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(async function snapshotDashboard() { const batch = UndoManager.StartBatch('snapshot'); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 9a6f1e2eb..710c00841 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/control-has-associated-label */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -16,7 +13,7 @@ import { DragManager } from '../../util/DragManager'; import { CompileScript } from '../../util/Scripting'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; +import { undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; @@ -37,13 +34,13 @@ interface CMVFieldRowProps { createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; setDocHeight: (key: string, thisHeight: number) => void; - refList: any[]; + refList: Element[]; showHandle: boolean; } @observer export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVFieldRowProps> { - constructor(props: any) { + constructor(props: CMVFieldRowProps) { super(props); makeObservable(this); } @@ -73,7 +70,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF private _dropDisposer?: DragManager.DragDropDisposer; private _headerRef: React.RefObject<HTMLDivElement> = React.createRef(); private _contRef: React.RefObject<HTMLDivElement> = React.createRef(); - private _ele: any; + private _ele: HTMLDivElement | null = null; createRowDropRef = (ele: HTMLDivElement | null) => { this._dropDisposer?.(); @@ -118,7 +115,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF return false; }); - getValue = (value: string): any => { + getValue = (value: string) => { const parsed = parseInt(value); if (!isNaN(parsed)) return parsed; if (value.toLowerCase().indexOf('true') > -1) return true; @@ -173,7 +170,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF return docs ? !!docs.splice(0, 0, newDoc) : this._props.parent._props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list) }; - deleteRow = undoBatch( + deleteRow = undoable( action(() => { this._createEmbeddingSelected = false; const key = this._props.pivotField; @@ -182,11 +179,12 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF const index = this._props.parent.colHeaderData.indexOf(this._props.headingObject); this._props.parent.colHeaderData.splice(index, 1); } - }) + }), + 'delete row' ); @action - collapseSection = (e: any) => { + collapseSection = (e: PointerEvent) => { this._createEmbeddingSelected = false; this.toggleVisibility(); e.stopPropagation(); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index b2f0280a5..7b9475590 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,7 +1,3 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable react/no-unused-class-component-methods */ /* eslint-disable react/sort-comp */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 16c474996..e1f0a3e41 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -30,9 +30,8 @@ import { StyleProp } from '../StyleProp'; import './CollectionNoteTakingView.scss'; import { CollectionNoteTakingViewColumn } from './CollectionNoteTakingViewColumn'; import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivider'; -import { CollectionSubView } from './CollectionSubView'; - -const _global = (window /* browser */ || global) /* node */ as any; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { Property } from 'csstype'; /** * CollectionNoteTakingView is a column-based view for displaying documents. In this view, the user can (1) @@ -52,9 +51,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { public DividerWidth = 16; @observable docsDraggedRowCol: number[] = []; @observable _scroll = 0; - @observable _refList: any[] = []; + @observable _refList: HTMLElement[] = []; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -78,7 +77,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { return colHeaderData ?? ([] as SchemaHeaderField[]); } @computed get headerMargin() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin); + return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) as number; } @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 5); @@ -216,7 +215,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // let's dive in and get the actual document we want to drag/move around focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); - const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); + const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find(node => node.id === doc[Id]); if (found) { const { top } = found.getBoundingClientRect(); const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); @@ -295,7 +294,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { addDocument={this._props.addDocument} moveDocument={this._props.moveDocument} removeDocument={this._props.removeDocument} - contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any} + contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as Property.PointerEvents} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} @@ -313,14 +312,14 @@ export class CollectionNoteTakingView extends CollectionSubView() { // how to get the width of a document. Currently returns the width of the column (minus margins) // if a note doc. Otherwise, returns the normal width (for graphs, images, etc...) - getDocWidth(d: Doc) { + getDocWidth = (d: Doc) => { const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as FieldType); const existingHeader = this.colHeaderData.find(sh => sh.heading === heading); const existingWidth = this.layoutDoc._notetaking_columns_autoSize ? 1 / (this.colHeaderData.length ?? 1) : existingHeader?.width ? existingHeader.width : 0; const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth; const width = d.layout_fitWidth ? maxWidth : NumCast(d._width); return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth); - } + }; // how to get the height of a document. Nothing special here. getDocHeight(d?: Doc) { @@ -364,7 +363,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { // onPointerMove is used to preview where a document will drop in a column once a drag is complete. @action onPointerMove = (force: boolean, ex: number, ey: number) => { - if (this.childDocList?.includes(DragManager.DocDragData?.draggedDocuments?.lastElement() as any) || force || SnappingManager.CanEmbed) { + const dragDoc = DragManager.DraggedDocs?.lastElement(); + if ((dragDoc && this.childDocList?.includes(dragDoc)) || force || SnappingManager.CanEmbed) { // get the current docs for the column based on the mouse's x coordinate const xCoord = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[0] - 2 * this.gridGap; const colDocs = this.getDocsFromXCoord(xCoord); @@ -500,7 +500,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { super.onExternalDrop( e, {}, - undoBatch( + undoable( action(docus => { this.onPointerMove(true, e.clientX, e.clientY); docus?.map((doc: Doc) => this.addDocument(doc)); @@ -513,7 +513,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { docs.splice(targInd, 0, newDoc); } this.removeDocDragHighlight(); - }) + }), + 'drop into note view' ) ); }; @@ -673,7 +674,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { return this.isContentActive() === false ? 'none' : undefined; } - observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight)))); + observer = new ResizeObserver(() => this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight)))); render() { TraceMobx(); diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 44ab1968d..8c6a6b551 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/control-has-associated-label */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -16,7 +15,7 @@ import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, undoable } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; -import { EditableView } from '../EditableView'; +import { EditableProps, EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionNoteTakingView.scss'; @@ -24,7 +23,7 @@ import './CollectionNoteTakingView.scss'; interface CSVFieldColumnProps { Document: Doc; TemplateDataDocument: Opt<Doc>; - backgroundColor?: (() => string) | undefined; + backgroundColor?: () => string | undefined; docList: Doc[]; heading: string; pivotField: string; @@ -35,15 +34,15 @@ interface CSVFieldColumnProps { yMargin: number; numGroupColumns: number; gridGap: number; - headings: () => object[]; + headings: () => [SchemaHeaderField, Doc[]][]; select: (ctrlPressed: boolean) => void; isContentActive: () => boolean | undefined; renderChildren: (docs: Doc[]) => JSX.Element[]; addDocument: (doc: Doc | Doc[]) => boolean; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; - refList: any[]; - editableViewProps: () => any; + refList: HTMLElement[]; + editableViewProps: () => EditableProps; resizeColumns: (headers: SchemaHeaderField[]) => boolean; maxColWidth: number; dividerWidth: number; @@ -103,7 +102,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV return true; }; - getValue = (value: string): any => { + getValue = (value: string) => { const parsed = parseInt(value); if (!isNaN(parsed)) return parsed; if (value.toLowerCase().indexOf('true') > -1) return true; @@ -272,7 +271,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV style={{ width: this.columnWidth, background: this._hover && SnappingManager.IsDragging ? '#b4b4b4' : 'inherit', - marginLeft: this._props.headings().findIndex((h: any) => h[0] === this._props.headingObject) === 0 ? NumCast(this._props.Document.xMargin) : 0, + marginLeft: this._props.headings().findIndex(h => h[0] === this._props.headingObject) === 0 ? NumCast(this._props.Document.xMargin) : 0, }}> <div className="collectionNoteTakingViewFieldColumn" key={this._heading} ref={this.createColumnDropRef}> {this.innards} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 5b3f625db..eea128803 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,10 +1,8 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, IReactionDisposer, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, FieldResult } from '../../../fields/Doc'; import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, StrCast, toList } from '../../../fields/Types'; import { emptyFunction } from '../../../Utils'; @@ -15,15 +13,15 @@ import { OpenWhere } from '../nodes/OpenWhere'; import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { DocumentView } from '../nodes/DocumentView'; @observer export class CollectionPileView extends CollectionSubView() { - _originalChrome: any = ''; + _originalChrome: FieldResult = ''; _disposers: { [name: string]: IReactionDisposer } = {}; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index b03f0cffa..08f3f3d65 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -1,8 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/alt-text */ /* eslint-disable no-use-before-define */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; @@ -34,7 +31,7 @@ import { LabelBox } from '../nodes/LabelBox'; import { OpenWhere } from '../nodes/OpenWhere'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; export type CollectionStackedTimelineProps = { Play: () => void; @@ -72,7 +69,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack ); this.SelectingRegions.clear(); } - constructor(props: any) { + constructor(props: SubCollectionViewProps & CollectionStackedTimelineProps) { super(props); makeObservable(this); } @@ -182,7 +179,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack }); anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this._props.startTag])); - anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null); + anchorEnd = (anchor: Doc, val?: number) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null); // converts screen pixel offset to time // prettier-ignore @@ -192,13 +189,13 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack @computed get rangeClick() { // prettier-ignore return ScriptField.MakeFunction('stackedTimeline.clickAnchor(this, clientX)', - { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: this as any } + { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: 'string' /* should be CollectionStackedTimeline */ } )!; } @computed get rangePlay() { // prettier-ignore return ScriptField.MakeFunction('stackedTimeline.playOnClick(this, clientX)', - { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: this as any })!; + { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: 'string' /* should be CollectionStackedTimeline */})!; } rangeClickScript = () => this.rangeClick; rangePlayScript = () => this.rangePlay; @@ -426,7 +423,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack const anchor = docAnchor ?? Docs.Create.LabelDocument({ - title: ComputedField.MakeFunction(`this["${endTag}"] ? "#" + formatToTime(this["${startTag}"]) + "-" + formatToTime(this["${endTag}"]) : "#" + formatToTime(this["${startTag}"])`) as any, + title: ComputedField.MakeFunction(`this["${endTag}"] ? "#" + formatToTime(this["${startTag}"]) + "-" + formatToTime(this["${endTag}"]) : "#" + formatToTime(this["${startTag}"])`) as unknown as string, // title can take a function or a string _label_minFontSize: 12, _label_maxFontSize: 24, _dragOnlyWithinContainer: true, @@ -777,8 +774,8 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch @action onAnchorDown = (e: React.PointerEvent, anchor: Doc, left: boolean): void => { const newTime = (timeDownEv: PointerEvent) => { - const rect = (timeDownEv.target as any).getBoundingClientRect(); - return this._props.toTimeline(timeDownEv.clientX - rect.x, rect.width); + const rect = (timeDownEv.target as HTMLElement).getBoundingClientRect?.(); + return !rect ? 0 : this._props.toTimeline(timeDownEv.clientX - rect.x, rect.width); }; const changeAnchor = (time: number | undefined) => { const timelineOnly = Cast(anchor[this._props.startTag], 'number', null) !== undefined; @@ -892,7 +889,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch } } // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function formatToTime(time: number): any { +ScriptingGlobals.add(function formatToTime(time: number): string { return formatTime(time); }); // eslint-disable-next-line prefer-arrow-callback diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 56d2a6c9c..03ade6579 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,6 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -// eslint-disable-next-line import/no-extraneous-dependencies import * as CSS from 'csstype'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -34,9 +33,7 @@ import { StyleProp } from '../StyleProp'; import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; import './CollectionStackingView.scss'; import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn'; -import { CollectionSubView } from './CollectionSubView'; - -const _global = (window /* browser */ || global) /* node */ as any; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; export type collectionStackingViewProps = { sortFunc?: (a: Doc, b: Doc) => number; @@ -57,8 +54,9 @@ 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: any[] = []; + @observable _refList: HTMLElement[] = []; // map of node headers to their heights. Used in Masonry @observable _heightMap = new Map<string, number>(); // Assuming that this is the current css cursor style @@ -85,7 +83,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection } // how much margin we give the header @computed get headerMargin() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin); + return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) as number; } @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth())); @@ -118,7 +116,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection return this._props.PanelWidth() - this.gridGap; } - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); if (this.colHeaderData === undefined) { @@ -260,7 +258,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); - const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); + const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find(node => node.id === doc[Id]); if (found) { const { top } = found.getBoundingClientRect(); const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); @@ -344,7 +342,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection LayoutTemplateString={this._props.childLayoutString} NativeWidth={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox NativeHeight={this._props.childIgnoreNativeSize ? returnZero : this._props.childLayoutFitWidth?.(doc) || (this.childFitWidth(doc) && !Doc.NativeHeight(doc)) ? height : undefined} - dontCenter={this._props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as any)} + dontCenter={this._props.childIgnoreNativeSize ? 'xy' : (StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy')} dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this._props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to. rootSelected={this.rootSelected} showTitle={this._props.childlayout_showTitle} @@ -363,7 +361,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection addDocument={this._props.addDocument} moveDocument={this._props.moveDocument} removeDocument={this._props.removeDocument} - contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any} + contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as CSS.Property.PointerEvents | undefined} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} @@ -623,7 +621,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection if (!e.isPropagationStopped()) { const cm = ContextMenu.Instance; const options = cm.findByDescription('Options...'); - const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; + const optionItems: ContextMenuProps[] = options?.subitems ?? []; optionItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => { this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill; }, icon: 'plus' }); // prettier-ignore optionItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => { this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight; }, icon: 'plus' }); // prettier-ignore optionItems.push({ description: 'Clear All', event: () => { this.dataDoc[this.fieldKey ?? 'data'] = new List([]); } , icon: 'times' }); // prettier-ignore @@ -688,10 +686,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection return this._props.isContentActive() === false ? 'none' : undefined; } - observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))); + observer = new ResizeObserver(() => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))); onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); - _oldWheel: any; render() { TraceMobx(); const editableViewProps = { @@ -722,8 +719,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection }} style={{ overflowY: this.isContentActive() ? 'auto' : 'hidden', - background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor), - pointerEvents: (this._props.pointerEvents?.() as any) ?? this.backgroundEvents, + background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string, + pointerEvents: this._props.pointerEvents?.() ?? this.backgroundEvents, }} onScroll={action(e => { this._scroll = e.currentTarget.scrollTop; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b7169ece0..5782d407e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -22,7 +22,7 @@ import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { SnappingManager } from '../../util/SnappingManager'; -import { UndoManager, undoBatch } from '../../util/UndoManager'; +import { UndoManager } from '../../util/UndoManager'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldViewProps } from '../nodes/FieldView'; import { DocumentView } from '../nodes/DocumentView'; @@ -227,7 +227,6 @@ export function CollectionSubView<X>() { } } - @undoBatch // eslint-disable-next-line @typescript-eslint/no-unused-vars protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {} @@ -294,7 +293,6 @@ export function CollectionSubView<X>() { return false; } - @undoBatch protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) { if (e.ctrlKey) { e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl @@ -386,7 +384,7 @@ export function CollectionSubView<X>() { addDocument(htmlDoc); if (srcWeb) { const iframe = DocumentView.Selected()[0].ContentDiv?.getElementsByTagName('iframe')?.[0]; - const focusNode = iframe?.contentDocument?.getSelection()?.focusNode as any; + const focusNode = iframe?.contentDocument?.getSelection()?.focusNode; if (focusNode) { const anchor = srcWeb?.ComponentView?.getAnchor?.(true); anchor && DocUtils.MakeLink(htmlDoc, anchor, {}); @@ -465,23 +463,6 @@ export function CollectionSubView<X>() { if (item.kind === 'file') { const file = item.getAsFile(); file?.type && files.push(file); - - file?.type === 'application/json' && - ClientUtils.readUploadedFileAsText(file).then(result => { - const json = JSON.parse(result as string); - addDocument( - Docs.Create.TreeDocument( - json['rectangular-puzzle'].crossword.clues[0].clue.map((c: any) => { - const label = Docs.Create.LabelDocument({ title: c['#text'], _width: 120, _height: 20 }); - const proto = Doc.GetProto(label); - proto._width = 120; - proto._height = 20; - return proto; - }), - { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _createDocOnCR: true } - ) - ); - }); } } this.slowLoadDocuments(files, options, generatedDocuments, text, completed, addDocument).then(batch.end); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 0369e4a2a..8a24db330 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -18,7 +16,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { FieldsDropdown } from '../FieldsDropdown'; import { PinDocView } from '../PinFuncs'; import { DocumentView } from '../nodes/DocumentView'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import './CollectionTimeView.scss'; import { ViewDefBounds, computePivotLayout, computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @@ -32,7 +30,7 @@ export class CollectionTimeView extends CollectionSubView() { @observable _viewDefDivClick: Opt<ScriptField> = undefined; @observable _focusPivotField: Opt<string> = undefined; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -51,7 +49,7 @@ export class CollectionTimeView extends CollectionSubView() { getAnchor = (addAsAnnotation: boolean) => { const anchor = Docs.Create.ConfigDocument({ - title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, + title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as unknown as string, // title can take a functiono or a string annotationOn: this.Document, }); PinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.Document); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 285598600..ff316cfbd 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,8 +1,7 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import ResizeObserver from 'resize-observer-polyfill'; import { DivHeight, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../ClientUtils'; import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -19,7 +18,7 @@ import { dropActionType } from '../../util/DropActionTypes'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; @@ -27,13 +26,11 @@ import { DocumentView } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProp'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import './CollectionTreeView.scss'; import { TreeViewType } from './CollectionTreeViewType'; import { TreeView } from './TreeView'; -const _global = (window /* browser */ || global) /* node */ as any; - export type collectionTreeViewProps = { treeViewExpandedView?: 'fields' | 'layout' | 'links' | 'data'; treeViewOpen?: boolean; @@ -55,10 +52,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree private _titleRef?: HTMLDivElement | HTMLInputElement | null; private _disposers: { [name: string]: IReactionDisposer } = {}; private _isDisposing = false; // notes that instance is in process of being disposed - private refList: Set<any> = new Set(); // list of tree view items to monitor for height changes - private observer: any; // observer for monitoring tree view items. + private refList: Set<HTMLElement> = new Set(); // list of tree view items to monitor for height changes + private observer: ResizeObserver | undefined; // observer for monitoring tree view items. - constructor(props: any) { + constructor(props: SubCollectionViewProps & collectionTreeViewProps) { super(props); makeObservable(this); } @@ -113,14 +110,14 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree !this._props.dontRegisterView && this._props.setHeight?.(bodyHeight + titleHeight); } }; - unobserveHeight = (ref: any) => { + unobserveHeight = (ref: HTMLElement) => { this.refList.delete(ref); this.layoutDoc.layout_autoHeight && this.computeHeight(); }; - observeHeight = (ref: any) => { + observeHeight = (ref: HTMLElement) => { if (ref) { this.refList.add(ref); - this.observer = new _global.ResizeObserver(() => { + this.observer = new ResizeObserver(() => { if (this.layoutDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.IsDragging) { this.computeHeight(); } @@ -216,7 +213,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); if (!Doc.noviceMode) { const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); - const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; + const onClicks: ContextMenuProps[] = existingOnClick.subitems ?? []; onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' }); !existingOnClick && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } @@ -234,11 +231,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree maxHeight={72} height="auto" GetValue={() => StrCast(this.dataDoc.title)} - SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { + SetValue={undoable((value: string, shift: boolean, enter: boolean) => { if (enter && this.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; - })} + }, 'set doc title')} /> ); } @@ -285,7 +282,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); - const dragAction = StrCast(this.Document.childDragAction) as any as dropActionType; + const dragAction = StrCast(this.Document.childDragAction) as dropActionType; const treeAddDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this._props.moveDocument?.(d, target, addDoc) || false; if (this._renderCount < this.treeChildren.length) @@ -333,9 +330,11 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree return this.dataDoc === null ? null : ( <div className="collectionTreeView-titleBar" - ref={action((r: any) => { - (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale); - })} + ref={r => + runInAction(() => { + (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale); + }) + } key={this.Document[Id]} style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle} @@ -410,8 +409,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree @observable _headerHeight = 0; @computed get content() { - const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor); - const color = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.Color); + const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string; + const color = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.Color) as string; const pointerEvents = () => (this._props.isContentActive() === false ? 'none' : undefined); const titleBar = this._props.treeViewHideTitle || this.Document.treeView_HideTitle ? null : this.titleBar; return ( diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f50f7394b..ee5c4afc0 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -6,6 +6,7 @@ import { IReactionDisposer, ObservableSet, action, computed, makeObservable, obs import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; +import ResizeObserver from 'resize-observer-polyfill'; import { ClientUtils, DashColor, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; @@ -41,8 +42,6 @@ import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -const _global = (window /* browser */ || global) /* node */ as any; - interface TabMinimapViewProps { document: Doc; tabView: () => DocumentView | undefined; @@ -183,6 +182,7 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps interface TabDocViewProps { documentId: FieldId; keyValue?: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any glContainer: any; } @observer @@ -327,10 +327,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { get view() { return this._view; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any _lastTab: any; _lastView: DocumentView | undefined; @action + // eslint-disable-next-line @typescript-eslint/no-explicit-any init = (tab: any, doc: Opt<Doc>) => { if (tab.contentItem === tab.header.parent.getActiveContentItem()) this._activated = true; if (tab.DashDoc !== doc && doc && tab.contentItem?.config.type !== 'stack') { @@ -357,10 +359,11 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { titleEle.size = StrCast(doc.title).length + 3; titleEle.value = doc.title; titleEle.onkeydown = (e: KeyboardEvent) => e.stopPropagation(); - titleEle.onchange = (e: any) => { + titleEle.onchange = (e: InputEvent) => { undoable(() => { - titleEle.size = e.currentTarget.value.length + 3; - doc[DocData].title = e.currentTarget.value; + const target = e.currentTarget as unknown as { value: string }; + titleEle.size = target?.value.length + 3; + doc[DocData].title = target?.value ?? ''; }, 'edit tab title')(); }; @@ -449,8 +452,8 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { }; // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected - titleEle.onpointerdown = action((e: any) => { - if (e.target.className !== 'lm_iconWrap') { + titleEle.onpointerdown = action((e: PointerEvent) => { + if ((e.target as HTMLElement)?.className !== 'lm_iconWrap') { if (this.view) DocumentView.SelectView(this.view, false); else this._activated = true; if (Date.now() - titleEle.lastClick < 1000) titleEle.select(); @@ -482,7 +485,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { tab.closeElement .off('click') // unbind the current click handler .click(() => { - Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); + Object.values(tab._disposers).forEach(disposer => (disposer as () => void)()); DocumentView.DeselectAll(); UndoManager.RunInBatch(() => tab.contentItem.remove(), 'delete tab'); }); @@ -490,8 +493,8 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { }; componentDidMount() { - new _global.ResizeObserver( - action((entries: any) => { + new ResizeObserver( + action(entries => { // eslint-disable-next-line no-restricted-syntax for (const entry of entries) { this._panelWidth = entry.contentRect.width; @@ -524,6 +527,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { public static DontSelectOnActivate = 'dontSelectOnActivate'; @action.bound + // eslint-disable-next-line @typescript-eslint/no-explicit-any private onActiveContentItemChanged(contentItem: any) { if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) { this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab; @@ -650,13 +654,13 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { this._view && DocumentView.removeView(this._view); } this._lastTab = this.tab; - (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); + (this._mainCont as { InitTab?: (tab: object) => void }).InitTab = (tab: object) => this.init(tab, this._document); DocServer.GetRefField(this._props.documentId).then( action(doc => { doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document); }) ); - new _global.ResizeObserver(action(() => this._forceInvalidateScreenToLocal++)).observe(ref); + ref && new ResizeObserver(action(() => this._forceInvalidateScreenToLocal++)).observe(ref); } }}> {this.docView} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 161d93788..54053d038 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -1,10 +1,7 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IconButton, Size } from 'browndash-components'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; @@ -41,14 +38,15 @@ import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { TREE_BULLET_WIDTH } = require('../global/globalCssVariables.module.scss'); // prettier-ignore export interface TreeViewProps { treeView: CollectionTreeView; // eslint-disable-next-line no-use-before-define parentTreeView: TreeView | CollectionTreeView | undefined; - observeHeight: (ref: any) => void; - unobserveHeight: (ref: any) => void; + observeHeight: (ref: HTMLDivElement) => void; + unobserveHeight: (ref: HTMLDivElement) => void; prevSibling?: Doc; Document: Doc; dataDoc?: Doc; @@ -188,7 +186,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { moving: boolean = false; @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { if (this.Document !== target && addDoc !== returnFalse) { - const canAdd1 = (this._props.parentTreeView as any).dropping || !(ComputedField.WithoutComputed(() => FieldValue(this._props.parentTreeView?.Document.data)) instanceof ComputedField); + const canAdd1 = (this._props.parentTreeView as TreeView).dropping || !(ComputedField.WithoutComputed(() => FieldValue(this._props.parentTreeView?.Document.data)) instanceof ComputedField); // bcz: this should all be running in a Temp undo batch instead of hackily testing for returnFalse if (canAdd1 && this._props.removeDoc?.(doc) === true) { @@ -263,7 +261,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return runningChildren; }; - static GetRunningChildren = new Map<Doc, any>(); + static GetRunningChildren = new Map<Doc, () => FieldResult[]>(); static ToggleChildrenRun = new Map<Doc, () => void>(); constructor(props: TreeViewProps) { super(props); @@ -285,7 +283,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { TreeView.GetRunningChildren.set(this.Document, () => this.getRunningChildren(this.childDocs)); } - _treeEle: any; + _treeEle: HTMLDivElement | null = null; protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer?.(); ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), this.Document, this.preTreeDrop.bind(this))), this.Document); @@ -524,7 +522,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return toList(docs).reduce((flg, iDoc) => flg && innerAdd(iDoc), true as boolean); }; contentElement = TreeView.GetChildElements( - toList(contents as any), + contents instanceof Doc ? [contents] : DocListCast(contents), this.treeView, this, doc, @@ -572,9 +570,11 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { rows.push( <div style={{ display: 'flex', overflow: 'auto' }} key={key}> <span - ref={action((r: any) => { - if (r) leftOffset.width = r.getBoundingClientRect().width; - })} + ref={r => + runInAction(() => { + if (r) leftOffset.width = r.getBoundingClientRect().width; + }) + } style={{ fontWeight: 'bold' }}> {key + ':'} @@ -608,7 +608,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { return rows; } - _renderTimer: any; + _renderTimer: NodeJS.Timeout | undefined; @observable _renderCount = 1; @computed get renderContent() { TraceMobx(); @@ -754,7 +754,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { } get onCheckedClick() { - return this.Document.type === DocumentType.COL ? undefined : this._props.onCheckedClick?.() ?? ScriptCast(this.Document.onCheckedClick); + return this.Document.type === DocumentType.COL ? undefined : (this._props.onCheckedClick?.() ?? ScriptCast(this.Document.onCheckedClick)); } @action @@ -779,7 +779,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { TraceMobx(); const iconType = (this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':treeOpen' : !this.childDocs.length ? ':empty' : '')) as string) || 'question'; const color = SettingsManager.userColor; - const checked = this.onCheckedClick ? this.Document.treeView_Checked ?? 'unchecked' : undefined; + const checked = this.onCheckedClick ? (this.Document.treeView_Checked ?? 'unchecked') : undefined; return ( <div className={`bullet${this.treeView.outlineMode ? '-outline' : ''}`} @@ -789,7 +789,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { style={ this.treeView.outlineMode ? { - opacity: this.titleStyleProvider?.(this.Document, this.treeView._props, StyleProp.Opacity), + opacity: this.titleStyleProvider?.(this.Document, this.treeView._props, StyleProp.Opacity) as number, } : { pointerEvents: this._props.isContentActive() ? 'all' : undefined, @@ -829,7 +829,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { @action expandNextviewType = () => { if (this.treeViewOpen && !this.Document.isFolder && !this.treeView.outlineMode && !this.Document.treeView_ExpandedViewLock) { - const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length]; + const next = (modes: string[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length]; this.Document.treeView_ExpandedView = next(this.validExpandViewTypes); } this.treeViewOpen = true; @@ -897,13 +897,13 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { onChildDoubleClick = () => ScriptCast(this.treeView.Document.treeView_ChildDoubleClick, !this.treeView.outlineMode ? this._openScript?.() : null); refocus = () => this.treeView._props.focus(this.treeView.Document, {}); - ignoreEvent = (e: any) => { + ignoreEvent = (e: React.MouseEvent) => { if (this._props.isContentActive(true)) { e.stopPropagation(); e.preventDefault(); } }; - titleStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { + titleStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView const { treeView } = this; @@ -938,7 +938,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { } return treeView._props.styleProvider?.(doc, props, property); }; - embeddedStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => { + embeddedStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; @@ -990,28 +990,30 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { this._editTitle = e; })} GetValue={() => StrCast(this.Document.title)} - OnTab={undoBatch((shift?: boolean) => { + OnTab={undoable((shift?: boolean) => { if (!shift) this._props.indentDocument?.(true); else this._props.outdentDocument?.(true); - })} - OnEmpty={undoBatch(() => this.treeView.outlineMode && this._props.removeDoc?.(this.Document))} + }, 'create new tree Doc')} + OnEmpty={undoable(() => this.treeView.outlineMode && this._props.removeDoc?.(this.Document), 'remove tree doc')} OnFillDown={() => this.treeView.fileSysMode && this.makeFolder()} - SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => { + SetValue={undoable((value: string, shiftKey: boolean, enterKey: boolean) => { Doc.SetInPlace(this.Document, 'title', value, false); - this.treeView.outlineMode && enterKey && this.makeTextCollection(); - })} + return this.treeView.outlineMode && enterKey && this.makeTextCollection(); + }, 'set tree doc title')} /> ) : ( <DocumentView key="title" - ref={action((r: any) => { - this._docRef = r || undefined; - if (this._docRef && TreeView._editTitleOnLoad?.id === this.Document[Id] && TreeView._editTitleOnLoad.parent === this._props.parentTreeView) { - this._docRef.select(false); - this.setEditTitle(this._docRef); - TreeView._editTitleOnLoad = undefined; - } - })} + ref={r => + runInAction(() => { + this._docRef = r || undefined; + if (this._docRef && TreeView._editTitleOnLoad?.id === this.Document[Id] && TreeView._editTitleOnLoad.parent === this._props.parentTreeView) { + this._docRef.select(false); + this.setEditTitle(this._docRef); + TreeView._editTitleOnLoad = undefined; + } + }) + } Document={this.Document} fitWidth={returnTrue} scriptContext={this} @@ -1068,9 +1070,11 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { </div> <div className="treeView-rightButtons" - ref={action((r: any) => { - r && (this.headerEleWidth = r.getBoundingClientRect().width); - })}> + ref={r => + runInAction(() => { + r && (this.headerEleWidth = r.getBoundingClientRect().width); + }) + }> {this.titleButtons} </div> </> @@ -1090,7 +1094,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { this, e, () => { - (this._dref ?? this._docRef)?.startDragging(e.clientX, e.clientY, '' as any); + (this._dref ?? this._docRef)?.startDragging(e.clientX, e.clientY, undefined); return true; }, returnFalse, @@ -1272,8 +1276,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> { firstLevel: boolean, whenChildContentsActiveChanged: (isActive: boolean) => void, dontRegisterView: boolean | undefined, - observerHeight: (ref: any) => void, - unobserveHeight: (ref: any) => void, + observerHeight: (ref: HTMLElement) => void, + unobserveHeight: (ref: HTMLElement) => void, contextMenuItems: { script: ScriptField; filter: ScriptField; label: string; icon: string }[], // TODO: [AL] add these AddToMap?: (treeViewDoc: Doc, index: number[]) => void, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx index fc39cafaa..c17371151 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx @@ -12,7 +12,7 @@ import './CollectionFreeFormView.scss'; * returns a truthy value */ // eslint-disable-next-line no-use-before-define -export type infoArc = [() => any, (res?: any) => infoState]; +export type infoArc = [() => unknown, (res?: unknown) => infoState]; export const StateMessage = Symbol('StateMessage'); export const StateMessageGIF = Symbol('StateMessageGIF'); @@ -20,9 +20,9 @@ export const StateEntryFunc = Symbol('StateEntryFunc'); export class infoState { [StateMessage]: string = ''; [StateMessageGIF]?: string = ''; - [StateEntryFunc]?: () => any; + [StateEntryFunc]?: () => unknown; [key: string]: infoArc; - constructor(message: string, arcs: { [key: string]: infoArc }, messageGif?: string, entryFunc?: () => any) { + constructor(message: string, arcs: { [key: string]: infoArc }, messageGif?: string, entryFunc?: () => unknown) { this[StateMessage] = message; Object.assign(this, arcs); this[StateMessageGIF] = messageGif; @@ -44,7 +44,7 @@ export function InfoState( msg: string, // arcs: { [key: string]: infoArc }, gif?: string, - entryFunc?: () => any + entryFunc?: () => unknown ) { // eslint-disable-next-line new-cap return new infoState(msg, arcs, gif, entryFunc); @@ -52,7 +52,7 @@ export function InfoState( export interface CollectionFreeFormInfoStateProps { infoState: infoState; - next: (state: infoState) => any; + next: (state: infoState) => unknown; close: () => void; } @@ -61,7 +61,7 @@ export class CollectionFreeFormInfoState extends ObservableReactComponent<Collec _disposers: IReactionDisposer[] = []; @observable _expanded = false; - constructor(props: any) { + constructor(props: CollectionFreeFormInfoStateProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index e543b4008..bc9dd022c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -54,8 +54,8 @@ export class CollectionFreeFormPannableContents extends ObservableReactComponent <div className={'collectionfreeformview' + (this._props.viewDefDivClick ? '-viewDef' : '-none')} onScroll={e => { - const target = e.target as any; - if (getComputedStyle(target)?.overflow === 'visible') { + const { target } = e; + if (target instanceof Element && getComputedStyle(target)?.overflow === 'visible') { target.scrollTop = target.scrollLeft = 0; // if collection is visible, scrolling messes things up since there are no scroll bars } }} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 39c3da7a5..c4cf8dee7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; +import { Property } from 'csstype'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; @@ -8,7 +9,6 @@ import * as React from 'react'; import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc'; -import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView'; import { DocData, Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField'; @@ -31,13 +31,13 @@ import { CompileScript } from '../../../util/Scripting'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { freeformScrollMode, SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; import { InkingStroke } from '../../InkingStroke'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { ActiveFillColor, DocumentView } from '../../nodes/DocumentView'; +import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FocusViewOptions } from '../../nodes/FocusViewOptions'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -121,7 +121,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _marqueeViewRef = React.createRef<MarqueeView>(); @observable _brushedView: { width: number; height: number; panX: number; panY: number } | undefined = undefined; // highlighted region of freeform canvas used by presentations to indicate a region @observable GroupChildDrag: boolean = false; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. - @observable _childPointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; + @observable _childPointerEvents: Property.PointerEvents | undefined = undefined; @observable _lightboxDoc: Opt<Doc> = undefined; @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); @observable _keyframeEditing = false; @@ -441,8 +441,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return true; } - @undoBatch - internalAnchorAnnoDrop(e: Event, de: DragManager.DropEvent, annoDragData: DragManager.AnchorAnnoDragData) { + internalAnchorAnnoDrop = undoable((e: Event, de: DragManager.DropEvent, annoDragData: DragManager.AnchorAnnoDragData) => { const dropCreator = annoDragData.dropDocCreator; const [xp, yp] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y); annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => { @@ -455,10 +454,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return dropDoc || this.Document; }; return true; - } + }, 'anchor drop'); - @undoBatch - internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) { + internalLinkDrop = undoable((e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) => { if (this.DocumentView?.() && linkDragData.linkDragView.containerViewPath?.().includes(this.DocumentView())) { const [x, y] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y); // do nothing if link is dropped into any freeform view parent of dragged document @@ -474,9 +472,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return added; } return false; - } + }, 'link drop'); - onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + onInternalDrop = (e: Event, de: DragManager.DropEvent): boolean => { if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de, de.complete.annoDragData); if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData); if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData); @@ -522,8 +520,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } }; - @undoBatch - onGesture = (e: Event, ge: GestureUtils.GestureEvent) => { + onGesture = undoable((e: Event, ge: GestureUtils.GestureEvent) => { switch (ge.gesture) { case Gestures.Text: if (ge.text) { @@ -566,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection e.stopPropagation(); } } - }; + }, 'gesture'); @action onEraserUp = (): void => { this._deleteList.lastElement()?._props.removeDocument?.(this._deleteList.map(ink => ink.Document)); @@ -1484,8 +1481,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const childData = entry.pair.data; return ( <CollectionFreeFormDocumentView - // eslint-disable-next-line react/jsx-props-no-spreading - {...OmitKeys(entry, ['replica', 'pair']).omit} + // eslint-disable-next-line react/jsx-props-no-spreading, @typescript-eslint/no-explicit-any + {...(OmitKeys(entry, ['replica', 'pair']).omit as any)} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} reactParent={this} @@ -1771,7 +1768,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._disposers.pointerevents = reaction( () => this.childPointerEvents, pointerevents => { - this._childPointerEvents = pointerevents as 'none' | 'all' | 'visiblePainted' | undefined; + this._childPointerEvents = pointerevents as Property.PointerEvents | undefined; }, { fireImmediately: true } ); @@ -1849,8 +1846,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._showEraserCircle = true; }; - @undoBatch - promoteCollection = () => { + promoteCollection = undoable(() => { const childDocs = this.childDocs.slice(); childDocs.forEach(docIn => { const doc = docIn; @@ -1859,10 +1855,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection doc.y = scr?.[1]; }); this._props.addDocTab(childDocs, OpenWhere.inParentFromScreen); - }; + }, 'promote collection'); - @undoBatch - layoutDocsInGrid = () => { + layoutDocsInGrid = undoable(() => { const docs = this.childLayoutPairs.map(pair => pair.layout); const width = Math.max(...docs.map(doc => NumCast(doc._width))) + 20; const height = Math.max(...docs.map(doc => NumCast(doc._height))) + 20; @@ -1872,40 +1867,37 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); - }; + }, 'layout docs in grid'); - @undoBatch - toggleNativeDimensions = () => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); + toggleNativeDimensions = undoable(() => Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight), 'toggle native dimensions'); /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS /// the view is a group, in which case this does nothing (since Groups calculate their own scale and center) /// - @undoBatch - resetView = () => { + resetView = undoable(() => { this.layoutDoc[this.panXFieldKey] = NumCast(this.dataDoc[this.panXFieldKey + '_reset']); this.layoutDoc[this.panYFieldKey] = NumCast(this.dataDoc[this.panYFieldKey + '_reset']); this.layoutDoc[this.scaleFieldKey] = NumCast(this.dataDoc[this.scaleFieldKey + '_reset'], 1); - }; + }, 'reset view'); /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS /// the view is a group, in which case this does nothing (since Groups calculate their own scale and center) /// - @undoBatch - toggleResetView = () => { + toggleResetView = undoable(() => { this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey]; if (this.dataDoc[this.autoResetFieldKey]) { this.dataDoc[this.panXFieldKey + '_reset'] = this.layoutDoc[this.panXFieldKey]; this.dataDoc[this.panYFieldKey + '_reset'] = this.layoutDoc[this.panYFieldKey]; this.dataDoc[this.scaleFieldKey + '_reset'] = this.layoutDoc[this.scaleFieldKey]; } - }; + }, 'toggle reset view'); onContextMenu = () => { if (this._props.isAnnotationOverlay || !ContextMenu.Instance) return; const appearance = ContextMenu.Instance.findByDescription('Appearance...'); - const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : []; + const appearanceItems = appearance?.subitems ?? []; !this.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' }); !this.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' }); if (this._props.setContentViewBox === emptyFunction) { @@ -1932,7 +1924,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); const options = ContextMenu.Instance.findByDescription('Options...'); - const optionItems = options && 'subitems' in options ? options.subitems : []; + const optionItems = options?.subitems ?? []; !this._props.isAnnotationOverlay && !Doc.noviceMode && optionItems.push({ @@ -1956,12 +1948,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } !options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); const mores = ContextMenu.Instance.findByDescription('More...'); - const moreItems = mores && 'subitems' in mores ? mores.subitems : []; + const moreItems = mores?.subitems ?? []; !mores && ContextMenu.Instance.addItem({ description: 'More...', subitems: moreItems, icon: 'eye' }); }; - @undoBatch - transcribeStrokes = () => { + transcribeStrokes = undoable(() => { if (this.Document.isGroup && this.Document.transcription) { const text = StrCast(this.Document.transcription); const lines = text.split('\n'); @@ -1969,7 +1960,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height })); } - }; + }, 'transcribe strokes'); @action dragEnding = () => { diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index eac0dc0e1..3af8464c2 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -1,8 +1,7 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Toggle, ToggleType, Type } from 'browndash-components'; +import { Property } from 'csstype'; import { IReactionDisposer, action, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -22,8 +21,7 @@ import { UndoStack } from '../../UndoStack'; import { DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { DocumentView } from '../../nodes/DocumentView'; import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup'; -import { CollectionSubView } from '../CollectionSubView'; -import './CollectionLinearView.scss'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; /** * CollectionLinearView is the class for rendering the horizontal collection @@ -39,7 +37,7 @@ export class CollectionLinearView extends CollectionSubView() { private _widthDisposer?: IReactionDisposer; private _selectedDisposer?: IReactionDisposer; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -239,7 +237,7 @@ export class CollectionLinearView extends CollectionSubView() { className="collectionLinearView-content" style={{ height: this.dimension(), - flexDirection: flexDir as any, + flexDirection: flexDir as Property.FlexDirection, gap: flexGap, }}> {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} |
