|
@@ -432,6 +432,7 @@ import { getShortcutFromShortcutName } from "../actions/shortcuts";
|
|
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|
import { getVisibleSceneBounds } from "../element/bounds";
|
|
import { getVisibleSceneBounds } from "../element/bounds";
|
|
import { isMaybeMermaidDefinition } from "../mermaid";
|
|
import { isMaybeMermaidDefinition } from "../mermaid";
|
|
|
|
+import NewElementCanvas from "./canvases/NewElementCanvas";
|
|
import { mutateElbowArrow } from "../element/routing";
|
|
import { mutateElbowArrow } from "../element/routing";
|
|
import {
|
|
import {
|
|
FlowChartCreator,
|
|
FlowChartCreator,
|
|
@@ -1472,25 +1473,21 @@ class App extends React.Component<AppProps, AppState> {
|
|
scrollY: this.state.scrollY,
|
|
scrollY: this.state.scrollY,
|
|
height: this.state.height,
|
|
height: this.state.height,
|
|
width: this.state.width,
|
|
width: this.state.width,
|
|
- editingElement: this.state.editingElement,
|
|
|
|
|
|
+ editingTextElement: this.state.editingTextElement,
|
|
|
|
+ newElementId: this.state.newElement?.id,
|
|
pendingImageElementId: this.state.pendingImageElementId,
|
|
pendingImageElementId: this.state.pendingImageElementId,
|
|
});
|
|
});
|
|
|
|
|
|
const allElementsMap = this.scene.getNonDeletedElementsMap();
|
|
const allElementsMap = this.scene.getNonDeletedElementsMap();
|
|
|
|
|
|
const shouldBlockPointerEvents =
|
|
const shouldBlockPointerEvents =
|
|
- !(
|
|
|
|
- this.state.editingElement && isLinearElement(this.state.editingElement)
|
|
|
|
- ) &&
|
|
|
|
- (this.state.selectionElement ||
|
|
|
|
- this.state.newElement ||
|
|
|
|
- this.state.selectedElementsAreBeingDragged ||
|
|
|
|
- this.state.resizingElement ||
|
|
|
|
- (this.state.activeTool.type === "laser" &&
|
|
|
|
- // technically we can just test on this once we make it more safe
|
|
|
|
- this.state.cursorButton === "down") ||
|
|
|
|
- (this.state.editingElement &&
|
|
|
|
- !isTextElement(this.state.editingElement)));
|
|
|
|
|
|
+ this.state.selectionElement ||
|
|
|
|
+ this.state.newElement ||
|
|
|
|
+ this.state.selectedElementsAreBeingDragged ||
|
|
|
|
+ this.state.resizingElement ||
|
|
|
|
+ (this.state.activeTool.type === "laser" &&
|
|
|
|
+ // technically we can just test on this once we make it more safe
|
|
|
|
+ this.state.cursorButton === "down");
|
|
|
|
|
|
const firstSelectedElement = selectedElements[0];
|
|
const firstSelectedElement = selectedElements[0];
|
|
|
|
|
|
@@ -1697,6 +1694,27 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.flowChartCreator.pendingNodes,
|
|
this.flowChartCreator.pendingNodes,
|
|
}}
|
|
}}
|
|
/>
|
|
/>
|
|
|
|
+ {this.state.newElement && (
|
|
|
|
+ <NewElementCanvas
|
|
|
|
+ appState={this.state}
|
|
|
|
+ scale={window.devicePixelRatio}
|
|
|
|
+ rc={this.rc}
|
|
|
|
+ elementsMap={elementsMap}
|
|
|
|
+ allElementsMap={allElementsMap}
|
|
|
|
+ renderConfig={{
|
|
|
|
+ imageCache: this.imageCache,
|
|
|
|
+ isExporting: false,
|
|
|
|
+ renderGrid: false,
|
|
|
|
+ canvasBackgroundColor:
|
|
|
|
+ this.state.viewBackgroundColor,
|
|
|
|
+ embedsValidationStatus:
|
|
|
|
+ this.embedsValidationStatus,
|
|
|
|
+ elementsPendingErasure:
|
|
|
|
+ this.elementsPendingErasure,
|
|
|
|
+ pendingFlowchartNodes: null,
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ )}
|
|
<InteractiveCanvas
|
|
<InteractiveCanvas
|
|
containerRef={this.excalidrawContainerRef}
|
|
containerRef={this.excalidrawContainerRef}
|
|
canvas={this.interactiveCanvas}
|
|
canvas={this.interactiveCanvas}
|
|
@@ -2073,7 +2091,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
let didUpdate = false;
|
|
let didUpdate = false;
|
|
|
|
|
|
- let editingElement: AppState["editingElement"] | null = null;
|
|
|
|
|
|
+ let editingTextElement: AppState["editingTextElement"] | null = null;
|
|
if (actionResult.elements) {
|
|
if (actionResult.elements) {
|
|
this.scene.replaceAllElements(actionResult.elements);
|
|
this.scene.replaceAllElements(actionResult.elements);
|
|
didUpdate = true;
|
|
didUpdate = true;
|
|
@@ -2086,7 +2104,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.addNewImagesToImageCache();
|
|
this.addNewImagesToImageCache();
|
|
}
|
|
}
|
|
|
|
|
|
- if (actionResult.appState || editingElement || this.state.contextMenu) {
|
|
|
|
|
|
+ if (actionResult.appState || editingTextElement || this.state.contextMenu) {
|
|
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
|
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
|
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
|
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
|
const theme =
|
|
const theme =
|
|
@@ -2102,23 +2120,24 @@ class App extends React.Component<AppProps, AppState> {
|
|
zenModeEnabled = this.props.zenModeEnabled;
|
|
zenModeEnabled = this.props.zenModeEnabled;
|
|
}
|
|
}
|
|
|
|
|
|
- editingElement = actionResult.appState?.editingElement || null;
|
|
|
|
|
|
+ editingTextElement = actionResult.appState?.editingTextElement || null;
|
|
|
|
|
|
- // make sure editingElement points to latest element reference
|
|
|
|
- if (actionResult.elements && editingElement) {
|
|
|
|
|
|
+ // make sure editingTextElement points to latest element reference
|
|
|
|
+ if (actionResult.elements && editingTextElement) {
|
|
actionResult.elements.forEach((element) => {
|
|
actionResult.elements.forEach((element) => {
|
|
if (
|
|
if (
|
|
- editingElement?.id === element.id &&
|
|
|
|
- editingElement !== element &&
|
|
|
|
- isNonDeletedElement(element)
|
|
|
|
|
|
+ editingTextElement?.id === element.id &&
|
|
|
|
+ editingTextElement !== element &&
|
|
|
|
+ isNonDeletedElement(element) &&
|
|
|
|
+ isTextElement(element)
|
|
) {
|
|
) {
|
|
- editingElement = element;
|
|
|
|
|
|
+ editingTextElement = element;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- if (editingElement?.isDeleted) {
|
|
|
|
- editingElement = null;
|
|
|
|
|
|
+ if (editingTextElement?.isDeleted) {
|
|
|
|
+ editingTextElement = null;
|
|
}
|
|
}
|
|
|
|
|
|
this.setState((state) => {
|
|
this.setState((state) => {
|
|
@@ -2130,7 +2149,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
// or programmatically from the host, so it will need to be
|
|
// or programmatically from the host, so it will need to be
|
|
// rewritten later
|
|
// rewritten later
|
|
contextMenu: null,
|
|
contextMenu: null,
|
|
- editingElement,
|
|
|
|
|
|
+ editingTextElement,
|
|
viewModeEnabled,
|
|
viewModeEnabled,
|
|
zenModeEnabled,
|
|
zenModeEnabled,
|
|
theme,
|
|
theme,
|
|
@@ -2709,9 +2728,9 @@ class App extends React.Component<AppProps, AppState> {
|
|
}
|
|
}
|
|
|
|
|
|
// failsafe in case the state is being updated in incorrect order resulting
|
|
// failsafe in case the state is being updated in incorrect order resulting
|
|
- // in the editingElement being now a deleted element
|
|
|
|
- if (this.state.editingElement?.isDeleted) {
|
|
|
|
- this.setState({ editingElement: null });
|
|
|
|
|
|
+ // in the editingTextElement being now a deleted element
|
|
|
|
+ if (this.state.editingTextElement?.isDeleted) {
|
|
|
|
+ this.setState({ editingTextElement: null });
|
|
}
|
|
}
|
|
|
|
|
|
if (
|
|
if (
|
|
@@ -2767,7 +2786,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
}
|
|
}
|
|
const scrolledOutside =
|
|
const scrolledOutside =
|
|
// hide when editing text
|
|
// hide when editing text
|
|
- isTextElement(this.state.editingElement)
|
|
|
|
|
|
+ this.state.editingTextElement
|
|
? false
|
|
? false
|
|
: !atLeastOneVisibleElement && elementsMap.size > 0;
|
|
: !atLeastOneVisibleElement && elementsMap.size > 0;
|
|
if (this.state.scrolledOutside !== scrolledOutside) {
|
|
if (this.state.scrolledOutside !== scrolledOutside) {
|
|
@@ -4636,7 +4655,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
this.setState({
|
|
this.setState({
|
|
newElement: null,
|
|
newElement: null,
|
|
- editingElement: null,
|
|
|
|
|
|
+ editingTextElement: null,
|
|
});
|
|
});
|
|
if (this.state.activeTool.locked) {
|
|
if (this.state.activeTool.locked) {
|
|
setCursorForShape(this.interactiveCanvas, this.state);
|
|
setCursorForShape(this.interactiveCanvas, this.state);
|
|
@@ -5010,7 +5029,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
}),
|
|
}),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
- this.setState({ editingElement: element });
|
|
|
|
|
|
+ this.setState({ editingTextElement: element });
|
|
|
|
|
|
if (!existingTextElement) {
|
|
if (!existingTextElement) {
|
|
if (container && shouldBindToContainer) {
|
|
if (container && shouldBindToContainer) {
|
|
@@ -5467,9 +5486,13 @@ class App extends React.Component<AppProps, AppState> {
|
|
lastPoint[1],
|
|
lastPoint[1],
|
|
) >= LINE_CONFIRM_THRESHOLD
|
|
) >= LINE_CONFIRM_THRESHOLD
|
|
) {
|
|
) {
|
|
- mutateElement(multiElement, {
|
|
|
|
- points: [...points, [scenePointerX - rx, scenePointerY - ry]],
|
|
|
|
- });
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ multiElement,
|
|
|
|
+ {
|
|
|
|
+ points: [...points, [scenePointerX - rx, scenePointerY - ry]],
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
} else {
|
|
} else {
|
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
// in this branch, we're inside the commit zone, and no uncommitted
|
|
// in this branch, we're inside the commit zone, and no uncommitted
|
|
@@ -5486,9 +5509,13 @@ class App extends React.Component<AppProps, AppState> {
|
|
) < LINE_CONFIRM_THRESHOLD
|
|
) < LINE_CONFIRM_THRESHOLD
|
|
) {
|
|
) {
|
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
- mutateElement(multiElement, {
|
|
|
|
- points: points.slice(0, -1),
|
|
|
|
- });
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ multiElement,
|
|
|
|
+ {
|
|
|
|
+ points: points.slice(0, -1),
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
} else {
|
|
} else {
|
|
const [gridX, gridY] = getGridPoint(
|
|
const [gridX, gridY] = getGridPoint(
|
|
scenePointerX,
|
|
scenePointerX,
|
|
@@ -5534,20 +5561,30 @@ class App extends React.Component<AppProps, AppState> {
|
|
undefined,
|
|
undefined,
|
|
{
|
|
{
|
|
isDragging: true,
|
|
isDragging: true,
|
|
|
|
+ informMutation: false,
|
|
},
|
|
},
|
|
);
|
|
);
|
|
} else {
|
|
} else {
|
|
// update last uncommitted point
|
|
// update last uncommitted point
|
|
- mutateElement(multiElement, {
|
|
|
|
- points: [
|
|
|
|
- ...points.slice(0, -1),
|
|
|
|
- [
|
|
|
|
- lastCommittedX + dxFromLastCommitted,
|
|
|
|
- lastCommittedY + dyFromLastCommitted,
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ multiElement,
|
|
|
|
+ {
|
|
|
|
+ points: [
|
|
|
|
+ ...points.slice(0, -1),
|
|
|
|
+ [
|
|
|
|
+ lastCommittedX + dxFromLastCommitted,
|
|
|
|
+ lastCommittedY + dyFromLastCommitted,
|
|
|
|
+ ],
|
|
],
|
|
],
|
|
- ],
|
|
|
|
- });
|
|
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // in this path, we're mutating multiElement to reflect
|
|
|
|
+ // how it will be after adding pointer position as the next point
|
|
|
|
+ // trigger update here so that new element canvas renders again to reflect this
|
|
|
|
+ this.triggerRender(false);
|
|
}
|
|
}
|
|
|
|
|
|
return;
|
|
return;
|
|
@@ -5950,7 +5987,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
: {}),
|
|
: {}),
|
|
appState: {
|
|
appState: {
|
|
newElement: null,
|
|
newElement: null,
|
|
- editingElement: null,
|
|
|
|
|
|
+ editingTextElement: null,
|
|
startBoundElement: null,
|
|
startBoundElement: null,
|
|
suggestedBindings: [],
|
|
suggestedBindings: [],
|
|
selectedElementIds: makeNextSelectedElementIds(
|
|
selectedElementIds: makeNextSelectedElementIds(
|
|
@@ -6133,7 +6170,6 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
this.setState({
|
|
this.setState({
|
|
newElement: pendingImageElement as ExcalidrawNonSelectionElement,
|
|
newElement: pendingImageElement as ExcalidrawNonSelectionElement,
|
|
- editingElement: pendingImageElement,
|
|
|
|
pendingImageElementId: null,
|
|
pendingImageElementId: null,
|
|
multiElement: null,
|
|
multiElement: null,
|
|
});
|
|
});
|
|
@@ -6339,7 +6375,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
isHandToolActive(this.state) ||
|
|
isHandToolActive(this.state) ||
|
|
this.state.viewModeEnabled)
|
|
this.state.viewModeEnabled)
|
|
) ||
|
|
) ||
|
|
- isTextElement(this.state.editingElement)
|
|
|
|
|
|
+ this.state.editingTextElement
|
|
) {
|
|
) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
@@ -6883,7 +6919,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
// if we're currently still editing text, clicking outside
|
|
// if we're currently still editing text, clicking outside
|
|
// should only finalize it, not create another (irrespective
|
|
// should only finalize it, not create another (irrespective
|
|
// of state.activeTool.locked)
|
|
// of state.activeTool.locked)
|
|
- if (isTextElement(this.state.editingElement)) {
|
|
|
|
|
|
+ if (this.state.editingTextElement) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
let sceneX = pointerDownState.origin.x;
|
|
let sceneX = pointerDownState.origin.x;
|
|
@@ -6934,6 +6970,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
y: gridY,
|
|
y: gridY,
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ const simulatePressure = event.pressure === 0.5;
|
|
|
|
+
|
|
const element = newFreeDrawElement({
|
|
const element = newFreeDrawElement({
|
|
type: elementType,
|
|
type: elementType,
|
|
x: gridX,
|
|
x: gridX,
|
|
@@ -6946,11 +6984,15 @@ class App extends React.Component<AppProps, AppState> {
|
|
roughness: this.state.currentItemRoughness,
|
|
roughness: this.state.currentItemRoughness,
|
|
opacity: this.state.currentItemOpacity,
|
|
opacity: this.state.currentItemOpacity,
|
|
roundness: null,
|
|
roundness: null,
|
|
- simulatePressure: event.pressure === 0.5,
|
|
|
|
|
|
+ simulatePressure,
|
|
locked: false,
|
|
locked: false,
|
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
|
|
+ points: [[0, 0]],
|
|
|
|
+ pressures: simulatePressure ? [] : [event.pressure],
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ this.scene.insertElement(element);
|
|
|
|
+
|
|
this.setState((prevState) => {
|
|
this.setState((prevState) => {
|
|
const nextSelectedElementIds = {
|
|
const nextSelectedElementIds = {
|
|
...prevState.selectedElementIds,
|
|
...prevState.selectedElementIds,
|
|
@@ -6964,21 +7006,12 @@ class App extends React.Component<AppProps, AppState> {
|
|
};
|
|
};
|
|
});
|
|
});
|
|
|
|
|
|
- const pressures = element.simulatePressure
|
|
|
|
- ? element.pressures
|
|
|
|
- : [...element.pressures, event.pressure];
|
|
|
|
-
|
|
|
|
- mutateElement(element, {
|
|
|
|
- points: [[0, 0]],
|
|
|
|
- pressures,
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
const boundElement = getHoveredElementForBinding(
|
|
const boundElement = getHoveredElementForBinding(
|
|
pointerDownState.origin,
|
|
pointerDownState.origin,
|
|
this.scene.getNonDeletedElements(),
|
|
this.scene.getNonDeletedElements(),
|
|
this.scene.getNonDeletedElementsMap(),
|
|
this.scene.getNonDeletedElementsMap(),
|
|
);
|
|
);
|
|
- this.scene.insertElement(element);
|
|
|
|
|
|
+
|
|
this.setState({
|
|
this.setState({
|
|
newElement: element,
|
|
newElement: element,
|
|
startBoundElement: boundElement,
|
|
startBoundElement: boundElement,
|
|
@@ -7279,7 +7312,6 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.scene.insertElement(element);
|
|
this.scene.insertElement(element);
|
|
this.setState({
|
|
this.setState({
|
|
newElement: element,
|
|
newElement: element,
|
|
- editingElement: element,
|
|
|
|
startBoundElement: boundElement,
|
|
startBoundElement: boundElement,
|
|
suggestedBindings: [],
|
|
suggestedBindings: [],
|
|
});
|
|
});
|
|
@@ -7671,11 +7703,11 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
// prevent dragging even if we're no longer holding cmd/ctrl otherwise
|
|
// prevent dragging even if we're no longer holding cmd/ctrl otherwise
|
|
// it would have weird results (stuff jumping all over the screen)
|
|
// it would have weird results (stuff jumping all over the screen)
|
|
- // Checking for editingElement to avoid jump while editing on mobile #6503
|
|
|
|
|
|
+ // Checking for editingTextElement to avoid jump while editing on mobile #6503
|
|
if (
|
|
if (
|
|
selectedElements.length > 0 &&
|
|
selectedElements.length > 0 &&
|
|
!pointerDownState.withCmdOrCtrl &&
|
|
!pointerDownState.withCmdOrCtrl &&
|
|
- !this.state.editingElement &&
|
|
|
|
|
|
+ !this.state.editingTextElement &&
|
|
this.state.activeEmbeddable?.state !== "active"
|
|
this.state.activeEmbeddable?.state !== "active"
|
|
) {
|
|
) {
|
|
const dragOffset = {
|
|
const dragOffset = {
|
|
@@ -7870,9 +7902,17 @@ class App extends React.Component<AppProps, AppState> {
|
|
? newElement.pressures
|
|
? newElement.pressures
|
|
: [...newElement.pressures, event.pressure];
|
|
: [...newElement.pressures, event.pressure];
|
|
|
|
|
|
- mutateElement(newElement, {
|
|
|
|
- points: [...points, [dx, dy]],
|
|
|
|
- pressures,
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ newElement,
|
|
|
|
+ {
|
|
|
|
+ points: [...points, [dx, dy]],
|
|
|
|
+ pressures,
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ this.setState({
|
|
|
|
+ newElement,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
} else if (isLinearElement(newElement)) {
|
|
} else if (isLinearElement(newElement)) {
|
|
@@ -7891,9 +7931,13 @@ class App extends React.Component<AppProps, AppState> {
|
|
}
|
|
}
|
|
|
|
|
|
if (points.length === 1) {
|
|
if (points.length === 1) {
|
|
- mutateElement(newElement, {
|
|
|
|
- points: [...points, [dx, dy]],
|
|
|
|
- });
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ newElement,
|
|
|
|
+ {
|
|
|
|
+ points: [...points, [dx, dy]],
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
} else if (points.length > 1 && isElbowArrow(newElement)) {
|
|
} else if (points.length > 1 && isElbowArrow(newElement)) {
|
|
mutateElbowArrow(
|
|
mutateElbowArrow(
|
|
newElement,
|
|
newElement,
|
|
@@ -7903,14 +7947,23 @@ class App extends React.Component<AppProps, AppState> {
|
|
undefined,
|
|
undefined,
|
|
{
|
|
{
|
|
isDragging: true,
|
|
isDragging: true,
|
|
|
|
+ informMutation: false,
|
|
},
|
|
},
|
|
);
|
|
);
|
|
} else if (points.length === 2) {
|
|
} else if (points.length === 2) {
|
|
- mutateElement(newElement, {
|
|
|
|
- points: [...points.slice(0, -1), [dx, dy]],
|
|
|
|
- });
|
|
|
|
|
|
+ mutateElement(
|
|
|
|
+ newElement,
|
|
|
|
+ {
|
|
|
|
+ points: [...points.slice(0, -1), [dx, dy]],
|
|
|
|
+ },
|
|
|
|
+ false,
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.setState({
|
|
|
|
+ newElement,
|
|
|
|
+ });
|
|
|
|
+
|
|
if (isBindingElement(newElement, false)) {
|
|
if (isBindingElement(newElement, false)) {
|
|
// When creating a linear element by dragging
|
|
// When creating a linear element by dragging
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
@@ -7922,7 +7975,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
} else {
|
|
} else {
|
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
|
- this.maybeDragNewGenericElement(pointerDownState, event);
|
|
|
|
|
|
+ this.maybeDragNewGenericElement(pointerDownState, event, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -8080,12 +8133,6 @@ class App extends React.Component<AppProps, AppState> {
|
|
frameToHighlight: null,
|
|
frameToHighlight: null,
|
|
elementsToHighlight: null,
|
|
elementsToHighlight: null,
|
|
cursorButton: "up",
|
|
cursorButton: "up",
|
|
- // text elements are reset on finalize, and resetting on pointerup
|
|
|
|
- // may cause issues with double taps
|
|
|
|
- editingElement:
|
|
|
|
- multiElement || isTextElement(this.state.editingElement)
|
|
|
|
- ? this.state.editingElement
|
|
|
|
- : null,
|
|
|
|
snapLines: updateStable(prevState.snapLines, []),
|
|
snapLines: updateStable(prevState.snapLines, []),
|
|
originSnapOffset: null,
|
|
originSnapOffset: null,
|
|
}));
|
|
}));
|
|
@@ -8270,7 +8317,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
});
|
|
});
|
|
this.setState({
|
|
this.setState({
|
|
multiElement: newElement,
|
|
multiElement: newElement,
|
|
- editingElement: this.state.newElement,
|
|
|
|
|
|
+ newElement,
|
|
});
|
|
});
|
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
if (
|
|
if (
|
|
@@ -8307,6 +8354,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
newElement: null,
|
|
newElement: null,
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
|
|
+ // so that the scene gets rendered again to display the newly drawn linear as well
|
|
|
|
+ this.scene.triggerUpdate();
|
|
}
|
|
}
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -8371,6 +8420,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
if (newElement) {
|
|
if (newElement) {
|
|
mutateElement(newElement, getNormalizedDimensions(newElement));
|
|
mutateElement(newElement, getNormalizedDimensions(newElement));
|
|
|
|
+ // the above does not guarantee the scene to be rendered again, hence the trigger below
|
|
|
|
+ this.scene.triggerUpdate();
|
|
}
|
|
}
|
|
|
|
|
|
if (pointerDownState.drag.hasOccurred) {
|
|
if (pointerDownState.drag.hasOccurred) {
|
|
@@ -9179,7 +9230,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.setState(
|
|
this.setState(
|
|
{
|
|
{
|
|
pendingImageElementId: null,
|
|
pendingImageElementId: null,
|
|
- editingElement: null,
|
|
|
|
|
|
+ newElement: null,
|
|
activeTool: updateActiveTool(this.state, { type: "selection" }),
|
|
activeTool: updateActiveTool(this.state, { type: "selection" }),
|
|
},
|
|
},
|
|
() => {
|
|
() => {
|
|
@@ -9675,23 +9726,25 @@ class App extends React.Component<AppProps, AppState> {
|
|
private maybeDragNewGenericElement = (
|
|
private maybeDragNewGenericElement = (
|
|
pointerDownState: PointerDownState,
|
|
pointerDownState: PointerDownState,
|
|
event: MouseEvent | KeyboardEvent,
|
|
event: MouseEvent | KeyboardEvent,
|
|
|
|
+ informMutation = true,
|
|
): void => {
|
|
): void => {
|
|
const selectionElement = this.state.selectionElement;
|
|
const selectionElement = this.state.selectionElement;
|
|
const pointerCoords = pointerDownState.lastCoords;
|
|
const pointerCoords = pointerDownState.lastCoords;
|
|
if (selectionElement && this.state.activeTool.type !== "eraser") {
|
|
if (selectionElement && this.state.activeTool.type !== "eraser") {
|
|
- dragNewElement(
|
|
|
|
- selectionElement,
|
|
|
|
- this.state.activeTool.type,
|
|
|
|
- pointerDownState.origin.x,
|
|
|
|
- pointerDownState.origin.y,
|
|
|
|
- pointerCoords.x,
|
|
|
|
- pointerCoords.y,
|
|
|
|
- distance(pointerDownState.origin.x, pointerCoords.x),
|
|
|
|
- distance(pointerDownState.origin.y, pointerCoords.y),
|
|
|
|
- shouldMaintainAspectRatio(event),
|
|
|
|
- shouldResizeFromCenter(event),
|
|
|
|
- this.state.zoom.value,
|
|
|
|
- );
|
|
|
|
|
|
+ dragNewElement({
|
|
|
|
+ newElement: selectionElement,
|
|
|
|
+ elementType: this.state.activeTool.type,
|
|
|
|
+ originX: pointerDownState.origin.x,
|
|
|
|
+ originY: pointerDownState.origin.y,
|
|
|
|
+ x: pointerCoords.x,
|
|
|
|
+ y: pointerCoords.y,
|
|
|
|
+ width: distance(pointerDownState.origin.x, pointerCoords.x),
|
|
|
|
+ height: distance(pointerDownState.origin.y, pointerCoords.y),
|
|
|
|
+ shouldMaintainAspectRatio: shouldMaintainAspectRatio(event),
|
|
|
|
+ shouldResizeFromCenter: shouldResizeFromCenter(event),
|
|
|
|
+ zoom: this.state.zoom.value,
|
|
|
|
+ informMutation,
|
|
|
|
+ });
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -9740,23 +9793,28 @@ class App extends React.Component<AppProps, AppState> {
|
|
snapLines,
|
|
snapLines,
|
|
});
|
|
});
|
|
|
|
|
|
- dragNewElement(
|
|
|
|
|
|
+ dragNewElement({
|
|
newElement,
|
|
newElement,
|
|
- this.state.activeTool.type,
|
|
|
|
- pointerDownState.originInGrid.x,
|
|
|
|
- pointerDownState.originInGrid.y,
|
|
|
|
- gridX,
|
|
|
|
- gridY,
|
|
|
|
- distance(pointerDownState.originInGrid.x, gridX),
|
|
|
|
- distance(pointerDownState.originInGrid.y, gridY),
|
|
|
|
- isImageElement(newElement)
|
|
|
|
|
|
+ elementType: this.state.activeTool.type,
|
|
|
|
+ originX: pointerDownState.originInGrid.x,
|
|
|
|
+ originY: pointerDownState.originInGrid.y,
|
|
|
|
+ x: gridX,
|
|
|
|
+ y: gridY,
|
|
|
|
+ width: distance(pointerDownState.originInGrid.x, gridX),
|
|
|
|
+ height: distance(pointerDownState.originInGrid.y, gridY),
|
|
|
|
+ shouldMaintainAspectRatio: isImageElement(newElement)
|
|
? !shouldMaintainAspectRatio(event)
|
|
? !shouldMaintainAspectRatio(event)
|
|
: shouldMaintainAspectRatio(event),
|
|
: shouldMaintainAspectRatio(event),
|
|
- shouldResizeFromCenter(event),
|
|
|
|
- this.state.zoom.value,
|
|
|
|
- aspectRatio,
|
|
|
|
- this.state.originSnapOffset,
|
|
|
|
- );
|
|
|
|
|
|
+ shouldResizeFromCenter: shouldResizeFromCenter(event),
|
|
|
|
+ zoom: this.state.zoom.value,
|
|
|
|
+ widthAspectRatio: aspectRatio,
|
|
|
|
+ originOffset: this.state.originSnapOffset,
|
|
|
|
+ informMutation,
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ this.setState({
|
|
|
|
+ newElement,
|
|
|
|
+ });
|
|
|
|
|
|
// highlight elements that are to be added to frames on frames creation
|
|
// highlight elements that are to be added to frames on frames creation
|
|
if (
|
|
if (
|