aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-10-01 03:58:47 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-10-01 03:58:47 -0400
commit6d35629dd8f997208130981aac1daf36bc83b134 (patch)
tree7b7e3baac15e5f7b4fcb48d90372c48d4552ae4c /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
parentcf45abf8ada938caddb226c825166d4acdee3086 (diff)
parentba01c7376ed4a2b817a26a430faf4041524aef35 (diff)
Merge branch 'master' of https://github.com/brown-dash/Dash-Web into nathan-starter
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx144
1 files changed, 66 insertions, 78 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5b7f09be3..f106eba26 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,16 +1,13 @@
-/* eslint-disable react/jsx-props-no-spreading */
-/* eslint-disable jsx-a11y/click-events-have-key-events */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
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';
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 } from '../../../../fields/Doc';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView';
+import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
import { DocData, Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField';
@@ -33,20 +30,20 @@ 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';
import { OpenWhere, OpenWhereMod } from '../../nodes/OpenWhere';
import { PinDocView, PinProps } from '../../PinFuncs';
import { StyleProp } from '../../StyleProp';
-import { CollectionSubView } from '../CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import { TreeViewType } from '../CollectionTreeViewType';
import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid';
import { CollectionFreeFormClusters } from './CollectionFreeFormClusters';
@@ -71,7 +68,7 @@ export interface collectionFreeformViewProps {
childPointerEvents?: () => string | undefined;
viewField?: string;
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
- engineProps?: any;
+ engineProps?: unknown;
getScrollHeight?: () => number | undefined;
}
@@ -83,7 +80,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
public unprocessedDocs: Doc[] = [];
public static collectionsWithUnprocessedInk = new Set<CollectionFreeFormView>();
public static from(dv?: DocumentView): CollectionFreeFormView | undefined {
- const parent = CollectionFreeFormDocumentView.from(dv)?._props.parent;
+ const parent = CollectionFreeFormDocumentView.from(dv)?._props.reactParent;
return parent instanceof CollectionFreeFormView ? parent : undefined;
}
@@ -123,14 +120,14 @@ 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;
@observable _eraserX: number = 0;
@observable _eraserY: number = 0;
@observable _showEraserCircle: boolean = false; // to determine whether the radius eraser should show
- constructor(props: collectionFreeformViewProps) {
+ constructor(props: SubCollectionViewProps) {
super(props);
makeObservable(this);
}
@@ -140,12 +137,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@computed get childPointerEvents() {
return SnappingManager.IsResizing
? 'none'
- : this._props.childPointerEvents?.() ??
+ : (this._props.childPointerEvents?.() ??
(this._props.viewDefDivClick || //
(this.layoutEngine === computePassLayout.name && !this._props.isSelected()) ||
this.isContentActive() === false
? 'none'
- : this._props.pointerEvents?.());
+ : this._props.pointerEvents?.()));
}
@computed get contentViews() {
const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask !== -1 && ele.inkMask !== undefined).map(ele => ele.ele);
@@ -185,7 +182,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
.transform(this.panZoomXf);
}
@computed get backgroundColor() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor);
+ return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
}
@computed get fitWidth() {
return this._props.fitWidth?.(this.Document) ?? this.layoutDoc.layout_fitWidth;
@@ -357,7 +354,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
* @param options
* @returns
*/
- focus = (anchor: Doc, options: FocusViewOptions): any => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
if (anchor.isGroup && !options.docTransform && options.contextPath?.length) {
// don't focus on group if there's a context path because we're about to focus on a group item
// which will override any group focus. (If we allowed the group to focus, it would mark didMove even if there were no net movement)
@@ -374,14 +371,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const xfToCollection = options?.docTransform ?? Transform.Identity();
const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
const cantTransform = this.fitContentsToBox || ((this.Document.isGroup || this.layoutDoc._lockedTransform) && !DocumentView.LightboxDoc());
- const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale ?? 0.75 : undefined);
+ const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? (options?.zoomScale ?? 0.75) : undefined);
// focus on the document in the collection
const didMove = !cantTransform && !anchor.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale);
if (didMove) options.didMove = true;
// glr: freeform transform speed can be set by adjusting presentation_transition field - needs a way of knowing when presentation is not active...
if (didMove) {
- const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
+ const focusTime = options?.instant ? 0 : (options.zoomTime ?? 500);
(options.zoomScale ?? options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
this.setPan(panX, panY, focusTime); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
return focusTime;
@@ -443,8 +440,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) => {
@@ -457,10 +453,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
@@ -476,9 +471,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);
@@ -524,8 +519,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) {
@@ -568,7 +562,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));
@@ -1178,6 +1172,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// for some reason bezier.js doesn't handle the case of intersecting a linear curve, so we wrap the intersection
// call in a test for linearity
bintersects = (curve: Bezier, otherCurve: Bezier) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((curve as any)._linear) {
// bezier.js doesn't intersect properly if the curve is actually a line -- so get intersect other curve against this line, then figure out the t coordinates of the intersection on this line
const intersections = otherCurve.lineIntersects({ p1: curve.points[0], p2: curve.points[3] });
@@ -1187,6 +1182,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return intT ? [intT] : [];
}
}
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((otherCurve as any)._linear) {
return curve.lineIntersects({ p1: otherCurve.points[0], p2: otherCurve.points[3] });
}
@@ -1214,7 +1210,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
for (let j = 0; j < otherCtrlPts.length - 3; j += 4) {
const neighboringSegment = i === j || i === j - 4 || i === j + 4;
// Ensuring that the curve intersected by the eraser is not checked for further ink intersections.
- // eslint-disable-next-line no-continue
if (ink?.Document === otherInk.Document && neighboringSegment) continue;
const otherCurve = new Bezier(otherCtrlPts.slice(j, j + 4).map(p => ({ x: p.X, y: p.Y })));
@@ -1478,17 +1473,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return ret;
};
childPointerEventsFunc = () => this._childPointerEvents;
- childContentsActive = () => (this._props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)();
+ childContentsActive = () => ((this._props.childContentsActive ?? this.isContentActive() === false) ? returnFalse : emptyFunction)();
getChildDocView(entry: PoolData) {
const childLayout = entry.pair.layout;
const childData = entry.pair.data;
return (
<CollectionFreeFormDocumentView
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...OmitKeys(entry, ['replica', 'pair']).omit}
+ {...(OmitKeys(entry, ['replica', 'pair']).omit as { x: number; y: number; z: number; width: number; height: number })}
key={childLayout[Id] + (entry.replica || '')}
Document={childLayout}
- parent={this}
+ reactParent={this}
containerViewPath={this.DocumentView?.().docViewPath}
styleProvider={this._clusters.styleProvider}
TemplateDataDocument={childData}
@@ -1603,7 +1597,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
}
- onViewDefDivClick = (e: React.MouseEvent, payload: any) => {
+ onViewDefDivClick = (e: React.MouseEvent, payload: unknown) => {
(this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload });
e.stopPropagation();
};
@@ -1637,7 +1631,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
ele: (
<div
className="collectionFreeform-customDiv"
- title={viewDef.payload?.join(' ')}
+ title={StrListCast(viewDef.payload as string).join(' ')}
key={'div' + x + y + z + viewDef.payload}
onClick={e => this.onViewDefDivClick(e, viewDef)}
style={{ width, height, backgroundColor: color, transform }}
@@ -1658,7 +1652,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
doEngineLayout(
poolData: Map<string, PoolData>,
- engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[]
+ engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: unknown) => ViewDefResult[]
) {
return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps);
}
@@ -1688,7 +1682,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
.forEach(entry =>
elements.push({
ele: this.getChildDocView(entry[1]),
- bounds: (entry[1].opacity === 0 ? { payload:undefined, type:"", ...entry[1], width: 0, height: 0 } : { payload:undefined, type:"",...entry[1] }),
+ bounds: entry[1].opacity === 0 ? { payload: undefined, type: '', ...entry[1], width: 0, height: 0 } : { payload: undefined, type: '', ...entry[1] },
inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
})
);
@@ -1771,7 +1765,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this._disposers.pointerevents = reaction(
() => this.childPointerEvents,
pointerevents => {
- this._childPointerEvents = pointerevents as any;
+ this._childPointerEvents = pointerevents as Property.PointerEvents | undefined;
},
{ fireImmediately: true }
);
@@ -1789,7 +1783,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!code.includes('dashDiv')) {
const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true });
if (script.compiled) script.run({ this: this.DocumentView?.() });
- // eslint-disable-next-line no-eval
} else code && !first && eval?.(code);
},
{ fireImmediately: true }
@@ -1812,24 +1805,25 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
updateIcon = () => {
const contentDiv = this.DocumentView?.().ContentDiv;
- contentDiv && UpdateIcon(
- this.layoutDoc[Id] + '-icon' + new Date().getTime(),
- contentDiv,
- NumCast(this.layoutDoc._width),
- NumCast(this.layoutDoc._height),
- this._props.PanelWidth(),
- this._props.PanelHeight(),
- 0,
- 1,
- false,
- '',
- (iconFile, nativeWidth, nativeHeight) => {
- this.dataDoc.icon = new ImageField(iconFile);
- this.dataDoc.icon_nativeWidth = nativeWidth;
- this.dataDoc.icon_nativeHeight = nativeHeight;
- }
- );
- }
+ contentDiv &&
+ UpdateIcon(
+ this.layoutDoc[Id] + '_icon_' + new Date().getTime(),
+ contentDiv,
+ NumCast(this.layoutDoc._width),
+ NumCast(this.layoutDoc._height),
+ this._props.PanelWidth(),
+ this._props.PanelHeight(),
+ 0,
+ 1,
+ false,
+ '',
+ (iconFile, nativeWidth, nativeHeight) => {
+ this.dataDoc.icon = new ImageField(iconFile);
+ this.dataDoc.icon_nativeWidth = nativeWidth;
+ this.dataDoc.icon_nativeHeight = nativeHeight;
+ }
+ );
+ };
@action
onCursorMove = (e: React.PointerEvent) => {
@@ -1848,8 +1842,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;
@@ -1858,10 +1851,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;
@@ -1871,40 +1863,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) {
@@ -1931,7 +1920,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({
@@ -1955,12 +1944,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');
@@ -1968,7 +1956,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 = () => {
@@ -2134,7 +2122,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onDragOver={e => e.preventDefault()}
onContextMenu={this.onContextMenu}
style={{
- pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : (this._props.pointerEvents?.() as any),
+ pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : this._props.pointerEvents?.(),
textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
transform: `scale(${this.nativeDimScaling})`,
width: `${100 / this.nativeDimScaling}%`,