aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
diff options
context:
space:
mode:
authorsrichman333 <sarah_n_richman@brown.edu>2024-03-10 14:00:51 -0400
committersrichman333 <sarah_n_richman@brown.edu>2024-03-10 14:00:51 -0400
commit68d017fdfb3b2592a61718de8edbdde09335cb55 (patch)
tree0bdb49127d9cf278fbb219de4216d10a1f8b1434 /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
parent8fc97eb6e093d4217f28919bf836425b75fdfea3 (diff)
parentcf91f5d4db5ba822b30d06cae9934bc979aff829 (diff)
Merge branch 'master' into dataviz-ai-sarah
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx48
1 files changed, 29 insertions, 19 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 877569ab3..9500b918a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
@@ -30,7 +30,7 @@ import { SelectionManager } from '../../../util/SelectionManager';
import { freeformScrollMode } from '../../../util/SettingsManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
-import { undoBatch, UndoManager } from '../../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager';
import { Timeline } from '../../animationtimeline/Timeline';
import { ContextMenu } from '../../ContextMenu';
import { GestureOverlay } from '../../GestureOverlay';
@@ -840,10 +840,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (excludeT < startSegmentT || excludeT > docCurveTVal) {
const localStartTVal = startSegmentT - Math.floor(i / 4);
t !== (localStartTVal < 0 ? 0 : localStartTVal) && segment.push(inkSegment.split(localStartTVal < 0 ? 0 : localStartTVal, t));
- segment.length && segments.push(segment);
+ if (segment.length && (Math.abs(segment[0].points[0].x - segment[0].points.lastElement().x) > 0.5 || Math.abs(segment[0].points[0].y - segment[0].points.lastElement().y) > 0.5)) segments.push(segment);
}
// start a new segment from the intersection t value
- segment = tVals.length - 1 === index ? [inkSegment.split(t).right] : [];
+ if (tVals.length - 1 === index) {
+ const split = inkSegment.split(t).right;
+ if (split && (Math.abs(split.points[0].x - split.points.lastElement().x) > 0.5 || Math.abs(split.points[0].y - split.points.lastElement().y) > 0.5)) segment = [split];
+ else segment = [];
+ } else segment = [];
startSegmentT = docCurveTVal;
});
} else {
@@ -1142,23 +1146,29 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
isContentActive = () => this._props.isContentActive();
- @undoBatch
+ /**
+ * Create a new text note of the same style as the one being typed into.
+ * If the text doc is be part of a larger templated doc, the new Doc will be a copy of the templated Doc
+ *
+ * @param fieldProps render props for the text doc being typed into
+ * @param below whether to place the new text Doc below or to the right of the one being typed into.
+ * @returns whether the new text doc was created and added successfully
+ */
+ createTextDocCopy = undoable((fieldProps: FieldViewProps, below: boolean) => {
+ const textDoc = DocCast(fieldProps.Document.rootDocument, fieldProps.Document);
+ const newDoc = Doc.MakeCopy(textDoc, true);
+ newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
+ newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10);
+ newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0);
+ FormattedTextBox.SetSelectOnLoad(newDoc);
+ FormattedTextBox.DontSelectInitialText = true;
+ return this.addDocument?.(newDoc);
+ }, 'copied text note');
+
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
e.stopPropagation?.();
- const below = !e.altKey && e.key !== 'Tab';
- const layout_fieldKey = StrCast(fieldProps.fieldKey);
- const newDoc = Doc.MakeCopy(fieldProps.Document, true);
- const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
- newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10;
- else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10;
- if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
- newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
- }
- newDoc[DocData].text = undefined;
- FormattedTextBox.SetSelectOnLoad(newDoc);
- return this.addDocument?.(newDoc);
+ return this.createTextDocCopy(fieldProps, !e.altKey && e.key !== 'Tab');
}
};
@computed get childPointerEvents() {
@@ -1647,7 +1657,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!this._props.isAnnotationOverlay &&
!Doc.noviceMode &&
optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
- this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
+ this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null).backgroundColor = StrCast(this.layoutDoc.backgroundColor)), icon: 'palette' });
this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
if (!Doc.noviceMode) {
optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });