feat: Arrow binding is a preference (#10839)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -438,6 +438,8 @@ export class Scene {
|
||||
options: {
|
||||
informMutation: boolean;
|
||||
isDragging: boolean;
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
} = {
|
||||
informMutation: true,
|
||||
isDragging: false,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
KEYS,
|
||||
arrayToMap,
|
||||
getFeatureFlag,
|
||||
invariant,
|
||||
@@ -137,12 +136,6 @@ export const maxBindingDistance_simple = (zoom?: AppState["zoom"]): number => {
|
||||
);
|
||||
};
|
||||
|
||||
export const shouldEnableBindingForPointerEvent = (
|
||||
event: React.PointerEvent<HTMLElement>,
|
||||
) => {
|
||||
return !event[KEYS.CTRL_OR_CMD];
|
||||
};
|
||||
|
||||
export const isBindingEnabled = (appState: {
|
||||
isBindingEnabled: AppState["isBindingEnabled"];
|
||||
}): boolean => {
|
||||
@@ -177,8 +170,20 @@ export const bindOrUnbindBindingElement = (
|
||||
},
|
||||
);
|
||||
|
||||
bindOrUnbindBindingElementEdge(arrow, start, "start", scene);
|
||||
bindOrUnbindBindingElementEdge(arrow, end, "end", scene);
|
||||
bindOrUnbindBindingElementEdge(
|
||||
arrow,
|
||||
start,
|
||||
"start",
|
||||
scene,
|
||||
appState.isBindingEnabled,
|
||||
);
|
||||
bindOrUnbindBindingElementEdge(
|
||||
arrow,
|
||||
end,
|
||||
"end",
|
||||
scene,
|
||||
appState.isBindingEnabled,
|
||||
);
|
||||
if (start.focusPoint || end.focusPoint) {
|
||||
// If the strategy dictates a focus point override, then
|
||||
// update the arrow points to point to the focus point.
|
||||
@@ -221,12 +226,21 @@ const bindOrUnbindBindingElementEdge = (
|
||||
{ mode, element, focusPoint }: BindingStrategy,
|
||||
startOrEnd: "start" | "end",
|
||||
scene: Scene,
|
||||
shouldSnapToOutline = true,
|
||||
): void => {
|
||||
if (mode === null) {
|
||||
// null means break the binding
|
||||
unbindBindingElement(arrow, startOrEnd, scene);
|
||||
} else if (mode !== undefined) {
|
||||
bindBindingElement(arrow, element, mode, startOrEnd, scene, focusPoint);
|
||||
bindBindingElement(
|
||||
arrow,
|
||||
element,
|
||||
mode,
|
||||
startOrEnd,
|
||||
scene,
|
||||
focusPoint,
|
||||
shouldSnapToOutline,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -798,6 +812,7 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
||||
startDragged ? "start" : "end",
|
||||
elementsMap,
|
||||
appState.zoom,
|
||||
appState.isMidpointSnappingEnabled,
|
||||
) || globalPoint,
|
||||
}
|
||||
: { mode: null };
|
||||
@@ -842,6 +857,7 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
||||
startDragged ? "end" : "start",
|
||||
elementsMap,
|
||||
appState.zoom,
|
||||
appState.isMidpointSnappingEnabled,
|
||||
) || otherEndpoint,
|
||||
}
|
||||
: { mode: undefined }
|
||||
@@ -1005,6 +1021,7 @@ export const bindBindingElement = (
|
||||
startOrEnd: "start" | "end",
|
||||
scene: Scene,
|
||||
focusPoint?: GlobalPoint,
|
||||
shouldSnapToOutline = true,
|
||||
): void => {
|
||||
const elementsMap = scene.getNonDeletedElementsMap();
|
||||
|
||||
@@ -1019,6 +1036,7 @@ export const bindBindingElement = (
|
||||
hoveredElement,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
shouldSnapToOutline,
|
||||
),
|
||||
};
|
||||
} else {
|
||||
@@ -1352,6 +1370,7 @@ export const bindPointToSnapToElementOutline = (
|
||||
startOrEnd: "start" | "end",
|
||||
elementsMap: ElementsMap,
|
||||
customIntersector?: LineSegment<GlobalPoint>,
|
||||
isMidpointSnappingEnabled = true,
|
||||
): GlobalPoint => {
|
||||
const elbowed = isElbowArrow(arrowElement);
|
||||
const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
@@ -1391,13 +1410,9 @@ export const bindPointToSnapToElementOutline = (
|
||||
const isHorizontal = headingIsHorizontal(
|
||||
headingForPointFromElement(bindableElement, aabb, point),
|
||||
);
|
||||
const snapPoint = snapToMid(
|
||||
bindableElement,
|
||||
elementsMap,
|
||||
edgePoint,
|
||||
0.05,
|
||||
arrowElement,
|
||||
);
|
||||
const snapPoint = isMidpointSnappingEnabled
|
||||
? snapToMid(bindableElement, elementsMap, edgePoint, 0.05, arrowElement)
|
||||
: undefined;
|
||||
const resolved = snapPoint || point;
|
||||
const otherPoint = pointFrom<GlobalPoint>(
|
||||
isHorizontal ? bindableCenter[0] : resolved[0],
|
||||
@@ -1892,6 +1907,8 @@ export const calculateFixedPointForElbowArrowBinding = (
|
||||
hoveredElement: ExcalidrawBindableElement,
|
||||
startOrEnd: "start" | "end",
|
||||
elementsMap: ElementsMap,
|
||||
shouldSnapToOutline = true,
|
||||
isMidpointSnappingEnabled = true,
|
||||
): { fixedPoint: FixedPoint } => {
|
||||
const bounds = [
|
||||
hoveredElement.x,
|
||||
@@ -1899,12 +1916,20 @@ export const calculateFixedPointForElbowArrowBinding = (
|
||||
hoveredElement.x + hoveredElement.width,
|
||||
hoveredElement.y + hoveredElement.height,
|
||||
] as Bounds;
|
||||
const snappedPoint = bindPointToSnapToElementOutline(
|
||||
linearElement,
|
||||
hoveredElement,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
);
|
||||
const snappedPoint = shouldSnapToOutline
|
||||
? bindPointToSnapToElementOutline(
|
||||
linearElement,
|
||||
hoveredElement,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
undefined,
|
||||
isMidpointSnappingEnabled,
|
||||
)
|
||||
: LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
linearElement,
|
||||
startOrEnd === "start" ? 0 : -1,
|
||||
elementsMap,
|
||||
);
|
||||
const globalMidPoint = pointFrom(
|
||||
bounds[0] + (bounds[2] - bounds[0]) / 2,
|
||||
bounds[1] + (bounds[3] - bounds[1]) / 2,
|
||||
|
||||
@@ -915,6 +915,8 @@ export const updateElbowArrowPoints = (
|
||||
},
|
||||
options?: {
|
||||
isDragging?: boolean;
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
},
|
||||
): ElementUpdate<ExcalidrawElbowArrowElement> => {
|
||||
if (arrow.points.length < 2) {
|
||||
@@ -1202,6 +1204,8 @@ const getElbowArrowData = (
|
||||
options?: {
|
||||
isDragging?: boolean;
|
||||
zoom?: AppState["zoom"];
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
},
|
||||
) => {
|
||||
const origStartGlobalPoint: GlobalPoint = pointTranslate<
|
||||
@@ -1215,7 +1219,7 @@ const getElbowArrowData = (
|
||||
|
||||
let hoveredStartElement = null;
|
||||
let hoveredEndElement = null;
|
||||
if (options?.isDragging) {
|
||||
if (options?.isDragging && options?.isBindingEnabled !== false) {
|
||||
const elements = Array.from(elementsMap.values());
|
||||
hoveredStartElement =
|
||||
getHoveredElement(
|
||||
@@ -1255,6 +1259,8 @@ const getElbowArrowData = (
|
||||
hoveredStartElement,
|
||||
elementsMap,
|
||||
options?.isDragging,
|
||||
options?.isBindingEnabled,
|
||||
options?.isMidpointSnappingEnabled,
|
||||
);
|
||||
const endGlobalPoint = getGlobalPoint(
|
||||
{
|
||||
@@ -1270,6 +1276,8 @@ const getElbowArrowData = (
|
||||
hoveredEndElement,
|
||||
elementsMap,
|
||||
options?.isDragging,
|
||||
options?.isBindingEnabled,
|
||||
options?.isMidpointSnappingEnabled,
|
||||
);
|
||||
const startHeading = getBindPointHeading(
|
||||
startGlobalPoint,
|
||||
@@ -2213,14 +2221,18 @@ const getGlobalPoint = (
|
||||
element?: ExcalidrawBindableElement | null,
|
||||
elementsMap?: ElementsMap,
|
||||
isDragging?: boolean,
|
||||
isBindingEnabled = true,
|
||||
isMidpointSnappingEnabled = true,
|
||||
): GlobalPoint => {
|
||||
if (isDragging) {
|
||||
if (element && elementsMap) {
|
||||
if (isBindingEnabled && element && elementsMap) {
|
||||
return bindPointToSnapToElementOutline(
|
||||
arrow,
|
||||
element,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
undefined,
|
||||
isMidpointSnappingEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -359,11 +359,20 @@ export class LinearElementEditor {
|
||||
linearElementEditor,
|
||||
);
|
||||
|
||||
LinearElementEditor.movePoints(element, app.scene, positions, {
|
||||
startBinding: updates?.startBinding,
|
||||
endBinding: updates?.endBinding,
|
||||
moveMidPointsWithElement: updates?.moveMidPointsWithElement,
|
||||
});
|
||||
LinearElementEditor.movePoints(
|
||||
element,
|
||||
app.scene,
|
||||
positions,
|
||||
{
|
||||
startBinding: updates?.startBinding,
|
||||
endBinding: updates?.endBinding,
|
||||
moveMidPointsWithElement: updates?.moveMidPointsWithElement,
|
||||
},
|
||||
{
|
||||
isBindingEnabled: app.state.isBindingEnabled,
|
||||
isMidpointSnappingEnabled: app.state.isMidpointSnappingEnabled,
|
||||
},
|
||||
);
|
||||
// Set the suggested binding from the updates if available
|
||||
if (isBindingElement(element, false)) {
|
||||
if (isBindingEnabled(app.state)) {
|
||||
@@ -418,6 +427,7 @@ export class LinearElementEditor {
|
||||
"start",
|
||||
elementsMap,
|
||||
app.state.zoom,
|
||||
app.state.isMidpointSnappingEnabled,
|
||||
)
|
||||
: linearElementEditor.initialState.altFocusPoint,
|
||||
},
|
||||
@@ -538,11 +548,20 @@ export class LinearElementEditor {
|
||||
linearElementEditor,
|
||||
);
|
||||
|
||||
LinearElementEditor.movePoints(element, app.scene, positions, {
|
||||
startBinding: updates?.startBinding,
|
||||
endBinding: updates?.endBinding,
|
||||
moveMidPointsWithElement: updates?.moveMidPointsWithElement,
|
||||
});
|
||||
LinearElementEditor.movePoints(
|
||||
element,
|
||||
app.scene,
|
||||
positions,
|
||||
{
|
||||
startBinding: updates?.startBinding,
|
||||
endBinding: updates?.endBinding,
|
||||
moveMidPointsWithElement: updates?.moveMidPointsWithElement,
|
||||
},
|
||||
{
|
||||
isBindingEnabled: app.state.isBindingEnabled,
|
||||
isMidpointSnappingEnabled: app.state.isMidpointSnappingEnabled,
|
||||
},
|
||||
);
|
||||
|
||||
// Set the suggested binding from the updates if available
|
||||
if (isBindingElement(element, false)) {
|
||||
@@ -636,6 +655,7 @@ export class LinearElementEditor {
|
||||
"start",
|
||||
elementsMap,
|
||||
app.state.zoom,
|
||||
app.state.isMidpointSnappingEnabled,
|
||||
)
|
||||
: linearElementEditor.initialState.altFocusPoint,
|
||||
},
|
||||
@@ -1524,6 +1544,10 @@ export class LinearElementEditor {
|
||||
endBinding?: FixedPointBinding | null;
|
||||
moveMidPointsWithElement?: boolean | null;
|
||||
},
|
||||
options?: {
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
},
|
||||
) {
|
||||
const { points } = element;
|
||||
|
||||
@@ -1592,6 +1616,8 @@ export class LinearElementEditor {
|
||||
otherUpdates,
|
||||
{
|
||||
isDragging: Array.from(pointUpdates.values()).some((t) => t.isDragging),
|
||||
isBindingEnabled: options?.isBindingEnabled,
|
||||
isMidpointSnappingEnabled: options?.isMidpointSnappingEnabled,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1706,6 +1732,8 @@ export class LinearElementEditor {
|
||||
isDragging?: boolean;
|
||||
zoom?: AppState["zoom"];
|
||||
sceneElementsMap?: NonDeletedSceneElementsMap;
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
},
|
||||
) {
|
||||
if (isElbowArrow(element)) {
|
||||
@@ -1726,6 +1754,8 @@ export class LinearElementEditor {
|
||||
scene.mutateElement(element, updates, {
|
||||
informMutation: true,
|
||||
isDragging: options?.isDragging ?? false,
|
||||
isBindingEnabled: options?.isBindingEnabled,
|
||||
isMidpointSnappingEnabled: options?.isMidpointSnappingEnabled,
|
||||
});
|
||||
} else {
|
||||
// TODO do we need to get precise coords here just to calc centers?
|
||||
@@ -2145,14 +2175,16 @@ const pointDraggingUpdates = (
|
||||
suggestedBinding: suggestedBindingElement
|
||||
? {
|
||||
element: suggestedBindingElement,
|
||||
midPoint: snapToMid(
|
||||
suggestedBindingElement,
|
||||
elementsMap,
|
||||
pointFrom<GlobalPoint>(
|
||||
scenePointerX - linearElementEditor.pointerOffset.x,
|
||||
scenePointerY - linearElementEditor.pointerOffset.y,
|
||||
),
|
||||
),
|
||||
midPoint: app.state.isMidpointSnappingEnabled
|
||||
? snapToMid(
|
||||
suggestedBindingElement,
|
||||
elementsMap,
|
||||
pointFrom<GlobalPoint>(
|
||||
scenePointerX - linearElementEditor.pointerOffset.x,
|
||||
scenePointerY - linearElementEditor.pointerOffset.y,
|
||||
),
|
||||
)
|
||||
: undefined,
|
||||
}
|
||||
: null,
|
||||
},
|
||||
|
||||
@@ -40,6 +40,8 @@ export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
|
||||
updates: ElementUpdate<TElement>,
|
||||
options?: {
|
||||
isDragging?: boolean;
|
||||
isBindingEnabled?: boolean;
|
||||
isMidpointSnappingEnabled?: boolean;
|
||||
},
|
||||
) => {
|
||||
let didChange = false;
|
||||
|
||||
@@ -659,20 +659,23 @@ export const projectFixedPointOntoDiagonal = (
|
||||
startOrEnd: "start" | "end",
|
||||
elementsMap: ElementsMap,
|
||||
zoom: AppState["zoom"],
|
||||
isMidpointSnappingEnabled: boolean = true,
|
||||
): GlobalPoint | null => {
|
||||
invariant(arrow.points.length >= 2, "Arrow must have at least two points");
|
||||
if (arrow.width < 3 && arrow.height < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sideMidPoint = getSnapOutlineMidPoint(
|
||||
point,
|
||||
element,
|
||||
elementsMap,
|
||||
zoom,
|
||||
);
|
||||
if (sideMidPoint) {
|
||||
return sideMidPoint;
|
||||
if (isMidpointSnappingEnabled) {
|
||||
const sideMidPoint = getSnapOutlineMidPoint(
|
||||
point,
|
||||
element,
|
||||
elementsMap,
|
||||
zoom,
|
||||
);
|
||||
if (sideMidPoint) {
|
||||
return sideMidPoint;
|
||||
}
|
||||
}
|
||||
|
||||
// Do the projection onto the diagonals (or center lines
|
||||
|
||||
@@ -1830,6 +1830,7 @@ export const actionChangeArrowType = register<keyof typeof ARROW_TYPE>({
|
||||
startElement,
|
||||
"start",
|
||||
elementsMap,
|
||||
appState.isBindingEnabled,
|
||||
),
|
||||
}
|
||||
: null;
|
||||
@@ -1843,6 +1844,7 @@ export const actionChangeArrowType = register<keyof typeof ARROW_TYPE>({
|
||||
endElement,
|
||||
"end",
|
||||
elementsMap,
|
||||
appState.isBindingEnabled,
|
||||
),
|
||||
}
|
||||
: null;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||
|
||||
import { register } from "./register";
|
||||
|
||||
export const actionToggleArrowBinding = register({
|
||||
name: "arrowBinding",
|
||||
label: "labels.arrowBinding",
|
||||
viewMode: false,
|
||||
trackEvent: {
|
||||
category: "canvas",
|
||||
predicate: (appState) => appState.bindingPreference === "disabled",
|
||||
},
|
||||
perform(elements, appState) {
|
||||
const newPreference =
|
||||
appState.bindingPreference === "enabled" ? "disabled" : "enabled";
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
bindingPreference: newPreference,
|
||||
isBindingEnabled: newPreference === "enabled",
|
||||
},
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
};
|
||||
},
|
||||
checked: (appState) => appState.bindingPreference === "enabled",
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { CaptureUpdateAction } from "@excalidraw/element";
|
||||
|
||||
import { register } from "./register";
|
||||
|
||||
export const actionToggleMidpointSnapping = register({
|
||||
name: "midpointSnapping",
|
||||
label: "labels.midpointSnapping",
|
||||
viewMode: false,
|
||||
trackEvent: {
|
||||
category: "canvas",
|
||||
predicate: (appState) => !appState.isMidpointSnappingEnabled,
|
||||
},
|
||||
perform(elements, appState) {
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
isMidpointSnappingEnabled: !this.checked!(appState),
|
||||
},
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
};
|
||||
},
|
||||
checked: (appState) => appState.isMidpointSnappingEnabled,
|
||||
});
|
||||
@@ -79,6 +79,8 @@ export {
|
||||
export { actionToggleGridMode } from "./actionToggleGridMode";
|
||||
export { actionToggleZenMode } from "./actionToggleZenMode";
|
||||
export { actionToggleObjectsSnapMode } from "./actionToggleObjectsSnapMode";
|
||||
export { actionToggleArrowBinding } from "./actionToggleArrowBinding";
|
||||
export { actionToggleMidpointSnapping } from "./actionToggleMidpointSnapping";
|
||||
|
||||
export { actionToggleStats } from "./actionToggleStats";
|
||||
export { actionUnbindText, actionBindText } from "./actionBoundText";
|
||||
|
||||
@@ -59,6 +59,8 @@ export type ActionName =
|
||||
| "gridMode"
|
||||
| "zenMode"
|
||||
| "objectsSnapMode"
|
||||
| "arrowBinding"
|
||||
| "midpointSnapping"
|
||||
| "stats"
|
||||
| "changeStrokeColor"
|
||||
| "changeBackgroundColor"
|
||||
|
||||
@@ -70,6 +70,8 @@ export const getDefaultAppState = (): Omit<
|
||||
gridStep: DEFAULT_GRID_STEP,
|
||||
gridModeEnabled: false,
|
||||
isBindingEnabled: true,
|
||||
bindingPreference: "enabled",
|
||||
isMidpointSnappingEnabled: true,
|
||||
defaultSidebarDockedPreference: false,
|
||||
isLoading: false,
|
||||
isResizing: false,
|
||||
@@ -190,7 +192,9 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
gridStep: { browser: true, export: true, server: true },
|
||||
gridModeEnabled: { browser: true, export: true, server: true },
|
||||
height: { browser: false, export: false, server: false },
|
||||
isBindingEnabled: { browser: false, export: false, server: false },
|
||||
isBindingEnabled: { browser: true, export: false, server: false },
|
||||
bindingPreference: { browser: true, export: false, server: false },
|
||||
isMidpointSnappingEnabled: { browser: true, export: false, server: false },
|
||||
defaultSidebarDockedPreference: {
|
||||
browser: true,
|
||||
export: false,
|
||||
|
||||
@@ -119,7 +119,6 @@ import {
|
||||
fixBindingsAfterDeletion,
|
||||
getHoveredElementForBinding,
|
||||
isBindingEnabled,
|
||||
shouldEnableBindingForPointerEvent,
|
||||
updateBoundElements,
|
||||
LinearElementEditor,
|
||||
newElementWith,
|
||||
@@ -319,6 +318,8 @@ import {
|
||||
actionToggleElementLock,
|
||||
actionToggleLinearEditor,
|
||||
actionToggleObjectsSnapMode,
|
||||
actionToggleArrowBinding,
|
||||
actionToggleMidpointSnapping,
|
||||
actionToggleCropEditor,
|
||||
} from "../actions";
|
||||
import { actionWrapTextInContainer } from "../actions/actionBoundText";
|
||||
@@ -2734,7 +2735,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
private onBlur = withBatchedUpdates(() => {
|
||||
isHoldingSpace = false;
|
||||
this.setState({ isBindingEnabled: true });
|
||||
this.setState({
|
||||
isBindingEnabled: this.state.bindingPreference === "enabled",
|
||||
});
|
||||
});
|
||||
|
||||
private onUnload = () => {
|
||||
@@ -4937,13 +4940,15 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event[KEYS.CTRL_OR_CMD] && this.state.isBindingEnabled) {
|
||||
if (event[KEYS.CTRL_OR_CMD] && !event.repeat) {
|
||||
if (getFeatureFlag("COMPLEX_BINDINGS")) {
|
||||
this.resetDelayedBindMode();
|
||||
}
|
||||
|
||||
flushSync(() => {
|
||||
this.setState({ isBindingEnabled: false });
|
||||
this.setState({
|
||||
isBindingEnabled: this.state.bindingPreference !== "enabled",
|
||||
});
|
||||
});
|
||||
|
||||
maybeHandleArrowPointlikeDrag({ app: this, event });
|
||||
@@ -5217,10 +5222,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!event[KEYS.CTRL_OR_CMD] && !this.state.isBindingEnabled) {
|
||||
flushSync(() => {
|
||||
this.setState({ isBindingEnabled: true });
|
||||
});
|
||||
if (!event[KEYS.CTRL_OR_CMD]) {
|
||||
const preferenceEnabled = this.state.bindingPreference === "enabled";
|
||||
if (this.state.isBindingEnabled !== preferenceEnabled) {
|
||||
flushSync(() => {
|
||||
this.setState({ isBindingEnabled: preferenceEnabled });
|
||||
});
|
||||
}
|
||||
|
||||
maybeHandleArrowPointlikeDrag({ app: this, event });
|
||||
}
|
||||
@@ -7138,6 +7146,14 @@ class App extends React.Component<AppProps, AppState> {
|
||||
private handleCanvasPointerDown = (
|
||||
event: React.PointerEvent<HTMLElement>,
|
||||
) => {
|
||||
// If Ctrl is not held, ensure isBindingEnabled reflects the user preference.
|
||||
if (!event.ctrlKey) {
|
||||
const preferenceEnabled = this.state.bindingPreference === "enabled";
|
||||
if (this.state.isBindingEnabled !== preferenceEnabled) {
|
||||
this.setState({ isBindingEnabled: preferenceEnabled });
|
||||
}
|
||||
}
|
||||
|
||||
const scenePointer = viewportCoordsToSceneCoords(event, this.state);
|
||||
const { x: scenePointerX, y: scenePointerY } = scenePointer;
|
||||
this.lastPointerMoveCoords = {
|
||||
@@ -7358,7 +7374,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
|
||||
this.clearSelectionIfNotUsingSelection();
|
||||
this.updateBindingEnabledOnPointerMove(event);
|
||||
|
||||
if (this.handleSelectionOnPointerDown(event, pointerDownState)) {
|
||||
return;
|
||||
@@ -7581,6 +7596,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.removePointer(event);
|
||||
this.lastPointerUpEvent = event;
|
||||
|
||||
if (!event.ctrlKey) {
|
||||
const preferenceEnabled = this.state.bindingPreference === "enabled";
|
||||
if (this.state.isBindingEnabled !== preferenceEnabled) {
|
||||
this.setState({ isBindingEnabled: preferenceEnabled });
|
||||
}
|
||||
}
|
||||
|
||||
const scenePointer = viewportCoordsToSceneCoords(
|
||||
{ clientX: event.clientX, clientY: event.clientY },
|
||||
this.state,
|
||||
@@ -8636,7 +8658,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
): void => {
|
||||
if (event.ctrlKey) {
|
||||
flushSync(() => {
|
||||
this.setState({ isBindingEnabled: false });
|
||||
this.setState({
|
||||
isBindingEnabled: this.state.bindingPreference !== "enabled",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11330,15 +11354,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.addNewImagesToImageCache();
|
||||
}, IMAGE_RENDER_TIMEOUT);
|
||||
|
||||
private updateBindingEnabledOnPointerMove = (
|
||||
event: React.PointerEvent<HTMLElement>,
|
||||
) => {
|
||||
const shouldEnableBinding = shouldEnableBindingForPointerEvent(event);
|
||||
if (this.state.isBindingEnabled !== shouldEnableBinding) {
|
||||
this.setState({ isBindingEnabled: shouldEnableBinding });
|
||||
}
|
||||
};
|
||||
|
||||
private clearSelection(hitElement: ExcalidrawElement | null): void {
|
||||
this.setState((prevState) => ({
|
||||
selectedElementIds: makeNextSelectedElementIds({}, prevState),
|
||||
@@ -12100,6 +12115,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
CONTEXT_MENU_SEPARATOR,
|
||||
actionToggleGridMode,
|
||||
actionToggleObjectsSnapMode,
|
||||
actionToggleArrowBinding,
|
||||
actionToggleMidpointSnapping,
|
||||
actionToggleZenMode,
|
||||
actionToggleViewMode,
|
||||
actionToggleStats,
|
||||
|
||||
@@ -249,6 +249,7 @@ const getRelevantAppStateProps = (
|
||||
multiElement: appState.multiElement,
|
||||
newElement: appState.newElement,
|
||||
isBindingEnabled: appState.isBindingEnabled,
|
||||
isMidpointSnappingEnabled: appState.isMidpointSnappingEnabled,
|
||||
suggestedBinding: appState.suggestedBinding,
|
||||
isRotating: appState.isRotating,
|
||||
elementsToHighlight: appState.elementsToHighlight,
|
||||
|
||||
@@ -9,7 +9,9 @@ import {
|
||||
actionLoadScene,
|
||||
actionSaveToActiveFile,
|
||||
actionShortcuts,
|
||||
actionToggleArrowBinding,
|
||||
actionToggleGridMode,
|
||||
actionToggleMidpointSnapping,
|
||||
actionToggleObjectsSnapMode,
|
||||
actionToggleSearchMenu,
|
||||
actionToggleStats,
|
||||
@@ -443,6 +445,40 @@ const PreferencesToggleSnapModeItem = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const PreferencesToggleArrowBindingItem = () => {
|
||||
const { t } = useI18n();
|
||||
const actionManager = useExcalidrawActionManager();
|
||||
const appState = useUIAppState();
|
||||
return (
|
||||
<DropdownMenuItemCheckbox
|
||||
checked={appState.bindingPreference === "enabled"}
|
||||
onSelect={(event) => {
|
||||
actionManager.executeAction(actionToggleArrowBinding);
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
{t("labels.arrowBinding")}
|
||||
</DropdownMenuItemCheckbox>
|
||||
);
|
||||
};
|
||||
|
||||
const PreferencesToggleMidpointSnappingItem = () => {
|
||||
const { t } = useI18n();
|
||||
const actionManager = useExcalidrawActionManager();
|
||||
const appState = useUIAppState();
|
||||
return (
|
||||
<DropdownMenuItemCheckbox
|
||||
checked={appState.isMidpointSnappingEnabled}
|
||||
onSelect={(event) => {
|
||||
actionManager.executeAction(actionToggleMidpointSnapping);
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
{t("labels.midpointSnapping")}
|
||||
</DropdownMenuItemCheckbox>
|
||||
);
|
||||
};
|
||||
|
||||
export const PreferencesToggleGridModeItem = () => {
|
||||
const { t } = useI18n();
|
||||
const actionManager = useExcalidrawActionManager();
|
||||
@@ -538,6 +574,8 @@ export const Preferences = ({
|
||||
<PreferencesToggleZenModeItem />
|
||||
<PreferencesToggleViewModeItem />
|
||||
<PreferencesToggleElementPropertiesItem />
|
||||
<PreferencesToggleArrowBindingItem />
|
||||
<PreferencesToggleMidpointSnappingItem />
|
||||
</>
|
||||
)}
|
||||
{additionalItems}
|
||||
@@ -548,6 +586,8 @@ export const Preferences = ({
|
||||
|
||||
Preferences.ToggleToolLock = PreferencesToggleToolLockItem;
|
||||
Preferences.ToggleSnapMode = PreferencesToggleSnapModeItem;
|
||||
Preferences.ToggleArrowBinding = PreferencesToggleArrowBindingItem;
|
||||
Preferences.ToggleMidpointSnapping = PreferencesToggleMidpointSnappingItem;
|
||||
Preferences.ToggleGridMode = PreferencesToggleGridModeItem;
|
||||
Preferences.ToggleZenMode = PreferencesToggleZenModeItem;
|
||||
Preferences.ToggleViewMode = PreferencesToggleViewModeItem;
|
||||
|
||||
@@ -177,7 +177,9 @@
|
||||
"tab": "Tab",
|
||||
"shapeSwitch": "Switch shape",
|
||||
"preferences": "Preferences",
|
||||
"preferences_toolLock": "Tool lock"
|
||||
"preferences_toolLock": "Tool lock",
|
||||
"arrowBinding": "Arrow binding",
|
||||
"midpointSnapping": "Snap to midpoints"
|
||||
},
|
||||
"elementLink": {
|
||||
"title": "Link to object",
|
||||
|
||||
@@ -407,8 +407,9 @@ const renderBindingHighlightForBindableElement_simple = (
|
||||
}
|
||||
|
||||
if (
|
||||
isFrameLikeElement(suggestedBinding.element) ||
|
||||
isBindableElement(suggestedBinding.element)
|
||||
appState.isMidpointSnappingEnabled &&
|
||||
(isFrameLikeElement(suggestedBinding.element) ||
|
||||
isBindableElement(suggestedBinding.element))
|
||||
) {
|
||||
// Draw midpoint indicators
|
||||
const linearElement = appState.selectedLinearElement;
|
||||
@@ -799,77 +800,79 @@ const renderBindingHighlightForBindableElement_complex = (
|
||||
|
||||
context.restore();
|
||||
|
||||
// Draw midpoint indicators
|
||||
context.save();
|
||||
context.translate(
|
||||
element.x + appState.scrollX,
|
||||
element.y + appState.scrollY,
|
||||
);
|
||||
|
||||
const midpointRadius = 5 / appState.zoom.value;
|
||||
const cutoutPadding = 5 / appState.zoom.value;
|
||||
const cutoutRadius = midpointRadius + cutoutPadding;
|
||||
|
||||
let midpoints;
|
||||
if (element.type === "diamond") {
|
||||
const [, curves] = deconstructDiamondElement(element);
|
||||
const center = elementCenterPoint(element, allElementsMap);
|
||||
|
||||
midpoints = curves.map((curve) => {
|
||||
const point = bezierEquation(curve, 0.5);
|
||||
const rotatedPoint = pointRotateRads(point, center, element.angle);
|
||||
return {
|
||||
x: rotatedPoint[0] - element.x,
|
||||
y: rotatedPoint[1] - element.y,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
const center = elementCenterPoint(element, allElementsMap);
|
||||
const basePoints = [
|
||||
{ x: element.width / 2, y: 0 }, // TOP
|
||||
{ x: element.width, y: element.height / 2 }, // RIGHT
|
||||
{ x: element.width / 2, y: element.height }, // BOTTOM
|
||||
{ x: 0, y: element.height / 2 }, // LEFT
|
||||
];
|
||||
midpoints = basePoints.map((point) => {
|
||||
const globalPoint = pointFrom<GlobalPoint>(
|
||||
point.x + element.x,
|
||||
point.y + element.y,
|
||||
);
|
||||
const rotatedPoint = pointRotateRads(
|
||||
globalPoint,
|
||||
center,
|
||||
element.angle,
|
||||
);
|
||||
return {
|
||||
x: rotatedPoint[0] - element.x,
|
||||
y: rotatedPoint[1] - element.y,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Clear cutouts around midpoints
|
||||
midpoints.forEach((midpoint) => {
|
||||
context.clearRect(
|
||||
midpoint.x - cutoutRadius,
|
||||
midpoint.y - cutoutRadius,
|
||||
cutoutRadius * 2,
|
||||
cutoutRadius * 2,
|
||||
if (appState.isMidpointSnappingEnabled) {
|
||||
// Draw midpoint indicators
|
||||
context.save();
|
||||
context.translate(
|
||||
element.x + appState.scrollX,
|
||||
element.y + appState.scrollY,
|
||||
);
|
||||
});
|
||||
|
||||
context.fillStyle =
|
||||
appState.theme === THEME.DARK
|
||||
? `rgba(3, 93, 161, ${opacity})`
|
||||
: `rgba(106, 189, 252, ${opacity})`;
|
||||
const midpointRadius = 5 / appState.zoom.value;
|
||||
const cutoutPadding = 5 / appState.zoom.value;
|
||||
const cutoutRadius = midpointRadius + cutoutPadding;
|
||||
|
||||
midpoints.forEach((midpoint) => {
|
||||
context.beginPath();
|
||||
context.arc(midpoint.x, midpoint.y, midpointRadius, 0, 2 * Math.PI);
|
||||
context.fill();
|
||||
});
|
||||
let midpoints;
|
||||
if (element.type === "diamond") {
|
||||
const [, curves] = deconstructDiamondElement(element);
|
||||
const center = elementCenterPoint(element, allElementsMap);
|
||||
|
||||
context.restore();
|
||||
midpoints = curves.map((curve) => {
|
||||
const point = bezierEquation(curve, 0.5);
|
||||
const rotatedPoint = pointRotateRads(point, center, element.angle);
|
||||
return {
|
||||
x: rotatedPoint[0] - element.x,
|
||||
y: rotatedPoint[1] - element.y,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
const center = elementCenterPoint(element, allElementsMap);
|
||||
const basePoints = [
|
||||
{ x: element.width / 2, y: 0 }, // TOP
|
||||
{ x: element.width, y: element.height / 2 }, // RIGHT
|
||||
{ x: element.width / 2, y: element.height }, // BOTTOM
|
||||
{ x: 0, y: element.height / 2 }, // LEFT
|
||||
];
|
||||
midpoints = basePoints.map((point) => {
|
||||
const globalPoint = pointFrom<GlobalPoint>(
|
||||
point.x + element.x,
|
||||
point.y + element.y,
|
||||
);
|
||||
const rotatedPoint = pointRotateRads(
|
||||
globalPoint,
|
||||
center,
|
||||
element.angle,
|
||||
);
|
||||
return {
|
||||
x: rotatedPoint[0] - element.x,
|
||||
y: rotatedPoint[1] - element.y,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Clear cutouts around midpoints
|
||||
midpoints.forEach((midpoint) => {
|
||||
context.clearRect(
|
||||
midpoint.x - cutoutRadius,
|
||||
midpoint.y - cutoutRadius,
|
||||
cutoutRadius * 2,
|
||||
cutoutRadius * 2,
|
||||
);
|
||||
});
|
||||
|
||||
context.fillStyle =
|
||||
appState.theme === THEME.DARK
|
||||
? `rgba(3, 93, 161, ${opacity})`
|
||||
: `rgba(106, 189, 252, ${opacity})`;
|
||||
|
||||
midpoints.forEach((midpoint) => {
|
||||
context.beginPath();
|
||||
context.arc(midpoint.x, midpoint.y, midpointRadius, 0, 2 * Math.PI);
|
||||
context.fill();
|
||||
});
|
||||
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -12,6 +12,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -932,6 +933,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1083,6 +1085,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1129,6 +1132,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1295,6 +1299,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1341,6 +1346,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1624,6 +1630,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1670,6 +1677,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1953,6 +1961,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1999,6 +2008,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2165,6 +2175,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2211,6 +2222,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2404,6 +2416,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2450,6 +2463,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2700,6 +2714,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2746,6 +2761,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3070,6 +3086,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3116,6 +3133,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3561,6 +3579,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3607,6 +3626,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3882,6 +3902,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3928,6 +3949,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4203,6 +4225,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4249,6 +4272,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4612,6 +4636,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -5532,6 +5557,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5827,6 +5853,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -6747,6 +6774,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7093,6 +7121,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -7468,6 +7497,28 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
||||
},
|
||||
"viewMode": false,
|
||||
},
|
||||
{
|
||||
"checked": [Function],
|
||||
"label": "labels.arrowBinding",
|
||||
"name": "arrowBinding",
|
||||
"perform": [Function],
|
||||
"trackEvent": {
|
||||
"category": "canvas",
|
||||
"predicate": [Function],
|
||||
},
|
||||
"viewMode": false,
|
||||
},
|
||||
{
|
||||
"checked": [Function],
|
||||
"label": "labels.midpointSnapping",
|
||||
"name": "midpointSnapping",
|
||||
"perform": [Function],
|
||||
"trackEvent": {
|
||||
"category": "canvas",
|
||||
"predicate": [Function],
|
||||
},
|
||||
"viewMode": false,
|
||||
},
|
||||
{
|
||||
"checked": [Function],
|
||||
"icon": <svg
|
||||
@@ -7680,6 +7731,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7758,6 +7810,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -8678,6 +8731,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8747,6 +8801,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": {
|
||||
"items": [
|
||||
@@ -9667,6 +9722,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
|
||||
@@ -12,6 +12,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -58,6 +59,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -641,6 +643,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -687,6 +690,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1200,6 +1204,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1246,6 +1251,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1558,6 +1564,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1604,6 +1611,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1918,6 +1926,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1964,6 +1973,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2179,6 +2189,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2225,6 +2236,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2630,6 +2642,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2676,6 +2689,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2931,6 +2945,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2977,6 +2992,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3248,6 +3264,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3294,6 +3311,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3540,6 +3558,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3586,6 +3605,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3824,6 +3844,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3870,6 +3891,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4057,6 +4079,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4103,6 +4126,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4312,6 +4336,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4358,6 +4383,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4581,6 +4607,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4627,6 +4654,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4808,6 +4836,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4854,6 +4883,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5035,6 +5065,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5081,6 +5112,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5280,6 +5312,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5326,6 +5359,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5534,6 +5568,7 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5580,6 +5615,7 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5790,6 +5826,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5836,6 +5873,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6117,6 +6155,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -6163,6 +6202,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6542,6 +6582,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -6588,6 +6629,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6914,6 +6956,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -6960,6 +7003,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7224,6 +7268,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7270,6 +7315,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7514,6 +7560,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7560,6 +7607,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7742,6 +7790,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7788,6 +7837,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8092,6 +8142,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8138,6 +8189,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8442,6 +8494,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8488,6 +8541,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8846,6 +8900,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"type": "freedraw",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8892,6 +8947,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9123,6 +9179,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9169,6 +9226,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9385,6 +9443,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9431,6 +9490,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9648,6 +9708,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9694,6 +9755,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9878,6 +9940,7 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9924,6 +9987,7 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10173,6 +10237,7 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10219,6 +10284,7 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10488,6 +10554,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10534,6 +10601,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10722,6 +10790,7 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10768,6 +10837,7 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11162,6 +11232,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11208,6 +11279,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11420,6 +11492,7 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11466,6 +11539,7 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11653,6 +11727,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11699,6 +11774,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11888,6 +11964,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
||||
"type": "freedraw",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11934,6 +12011,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12277,6 +12355,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -12323,6 +12402,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12485,6 +12565,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -12531,6 +12612,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12690,6 +12772,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -12736,6 +12819,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12989,6 +13073,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13035,6 +13120,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13285,6 +13371,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13331,6 +13418,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13528,6 +13616,7 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13574,6 +13663,7 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13763,6 +13853,7 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13809,6 +13900,7 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13998,6 +14090,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14044,6 +14137,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14243,6 +14337,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14289,6 +14384,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14572,6 +14668,7 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14618,6 +14715,7 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14740,6 +14838,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14786,6 +14885,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15022,6 +15122,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -15068,6 +15169,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15283,6 +15385,7 @@ exports[`history > singleplayer undo/redo > should not modify anything on unrela
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -15329,6 +15432,7 @@ exports[`history > singleplayer undo/redo > should not modify anything on unrela
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15434,6 +15538,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -15480,6 +15585,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15714,6 +15820,7 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -15760,6 +15867,7 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15874,6 +15982,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -15920,6 +16029,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -16620,6 +16730,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -16666,6 +16777,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17264,6 +17376,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -17310,6 +17423,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17908,6 +18022,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -17954,6 +18069,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -18655,6 +18771,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -18701,6 +18818,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -19421,6 +19539,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -19467,6 +19586,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -19899,6 +20019,7 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -19945,6 +20066,7 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -20408,6 +20530,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -20454,6 +20577,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -20865,6 +20989,7 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -20911,6 +21036,7 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
|
||||
@@ -12,6 +12,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -58,6 +59,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -436,6 +438,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -482,6 +485,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -850,6 +854,7 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -893,9 +898,10 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||
"gridStep": 5,
|
||||
"height": 768,
|
||||
"hoveredElementIds": {},
|
||||
"isBindingEnabled": false,
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1414,6 +1420,7 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1460,6 +1467,7 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1619,6 +1627,7 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -1665,6 +1674,7 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2001,6 +2011,7 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2047,6 +2058,7 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2244,6 +2256,7 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2290,6 +2303,7 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2422,6 +2436,7 @@ exports[`regression tests > can drag element that covers another element, while
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2468,6 +2483,7 @@ exports[`regression tests > can drag element that covers another element, while
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2745,6 +2761,7 @@ exports[`regression tests > change the properties of a shape > [end of test] app
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -2791,6 +2808,7 @@ exports[`regression tests > change the properties of a shape > [end of test] app
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2998,6 +3016,7 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3044,6 +3063,7 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3237,6 +3257,7 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3283,6 +3304,7 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3471,6 +3493,7 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3517,6 +3540,7 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3727,6 +3751,7 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -3773,6 +3798,7 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4039,6 +4065,7 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4085,6 +4112,7 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4473,6 +4501,7 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4519,6 +4548,7 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4754,6 +4784,7 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -4800,6 +4831,7 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5028,6 +5060,7 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5074,6 +5107,7 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5234,6 +5268,7 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5280,6 +5315,7 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5432,6 +5468,7 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5478,6 +5515,7 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5823,6 +5861,7 @@ exports[`regression tests > drags selected elements from point inside common bou
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -5869,6 +5908,7 @@ exports[`regression tests > drags selected elements from point inside common bou
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6118,6 +6158,7 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
||||
"type": "freedraw",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -6164,6 +6205,7 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6904,6 +6946,7 @@ exports[`regression tests > given a group of selected elements with an element t
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -6950,6 +6993,7 @@ exports[`regression tests > given a group of selected elements with an element t
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7236,6 +7280,7 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7282,6 +7327,7 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7513,6 +7559,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7559,6 +7606,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7746,6 +7794,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -7792,6 +7841,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -7984,6 +8034,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8030,6 +8081,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8162,6 +8214,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8208,6 +8261,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8340,6 +8394,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8386,6 +8441,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8518,6 +8574,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8564,6 +8621,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8748,6 +8806,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -8794,6 +8853,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8976,6 +9036,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
|
||||
"type": "freedraw",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9022,6 +9083,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9166,6 +9228,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9212,6 +9275,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9396,6 +9460,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9442,6 +9507,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9574,6 +9640,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9620,6 +9687,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9802,6 +9870,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -9848,6 +9917,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9980,6 +10050,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
|
||||
"type": "freedraw",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10026,6 +10097,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10170,6 +10242,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10216,6 +10289,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10348,6 +10422,7 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10394,6 +10469,7 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10877,6 +10953,7 @@ exports[`regression tests > noop interaction after undo shouldn't create history
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -10923,6 +11000,7 @@ exports[`regression tests > noop interaction after undo shouldn't create history
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11155,6 +11233,7 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11201,6 +11280,7 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "touch",
|
||||
@@ -11276,6 +11356,7 @@ exports[`regression tests > shift click on selected element should deselect it o
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11322,6 +11403,7 @@ exports[`regression tests > shift click on selected element should deselect it o
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11474,6 +11556,7 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11520,6 +11603,7 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11791,6 +11875,7 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -11837,6 +11922,7 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12218,6 +12304,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -12264,6 +12351,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12856,6 +12944,7 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -12902,6 +12991,7 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12980,6 +13070,7 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13026,6 +13117,7 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13609,6 +13701,7 @@ exports[`regression tests > switches from group of selected elements to another
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13655,6 +13748,7 @@ exports[`regression tests > switches from group of selected elements to another
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13946,6 +14040,7 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -13992,6 +14087,7 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14208,6 +14304,7 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14254,6 +14351,7 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "touch",
|
||||
@@ -14329,6 +14427,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14375,6 +14474,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14691,6 +14791,7 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
|
||||
"type": "text",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14737,6 +14838,7 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14812,6 +14914,7 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -14858,6 +14961,7 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
|
||||
@@ -0,0 +1,526 @@
|
||||
import { reseed } from "@excalidraw/common";
|
||||
import {
|
||||
isElbowArrow,
|
||||
projectFixedPointOntoDiagonal,
|
||||
} from "@excalidraw/element";
|
||||
|
||||
import { pointFrom } from "@excalidraw/math";
|
||||
|
||||
import type { GlobalPoint, LocalPoint } from "@excalidraw/math";
|
||||
|
||||
import type {
|
||||
ExcalidrawArrowElement,
|
||||
ExcalidrawBindableElement,
|
||||
ExcalidrawElement,
|
||||
} from "@excalidraw/element/types";
|
||||
|
||||
import { actionToggleArrowBinding } from "../actions/actionToggleArrowBinding";
|
||||
import { Excalidraw, sceneCoordsToViewportCoords } from "../index";
|
||||
|
||||
import { API } from "./helpers/api";
|
||||
import { Pointer, UI } from "./helpers/ui";
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
mockBoundingClientRect,
|
||||
restoreOriginalGetBoundingClientRect,
|
||||
waitFor,
|
||||
unmountComponent,
|
||||
} from "./test-utils";
|
||||
|
||||
unmountComponent();
|
||||
|
||||
const { h } = window;
|
||||
const mouse = new Pointer("mouse");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Fire Ctrl (or Meta on Mac) keydown on document. */
|
||||
const ctrlKeyDown = (extra: Partial<KeyboardEventInit> = {}) =>
|
||||
fireEvent.keyDown(document, {
|
||||
key: "Control",
|
||||
code: "ControlLeft",
|
||||
ctrlKey: true,
|
||||
repeat: false,
|
||||
...extra,
|
||||
});
|
||||
|
||||
/** Fire Ctrl (or Meta on Mac) keyup on document (ctrlKey is false on keyup). */
|
||||
const ctrlKeyUp = () =>
|
||||
fireEvent.keyUp(document, {
|
||||
key: "Control",
|
||||
code: "ControlLeft",
|
||||
ctrlKey: false,
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("Arrow binding – non-default case (bindingPreference: disabled)", () => {
|
||||
beforeAll(() => {
|
||||
mockBoundingClientRect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
restoreOriginalGetBoundingClientRect();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
reseed(7);
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
h.state.width = 1920;
|
||||
h.state.height = 1080;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mouse.reset();
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// actionToggleArrowBinding
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("actionToggleArrowBinding", () => {
|
||||
it("isBindingEnabled defaults to true", () => {
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("checked() reflects the current bindingPreference value", () => {
|
||||
expect(actionToggleArrowBinding.checked!(h.state)).toBe(true);
|
||||
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
expect(actionToggleArrowBinding.checked!(h.state)).toBe(false);
|
||||
});
|
||||
|
||||
it("executing the action toggles binding from enabled → disabled", () => {
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
API.executeAction(actionToggleArrowBinding);
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
expect(h.state.bindingPreference).toBe("disabled");
|
||||
});
|
||||
|
||||
it("executing the action toggles binding from disabled → enabled", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
API.executeAction(actionToggleArrowBinding);
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
expect(h.state.bindingPreference).toBe("enabled");
|
||||
});
|
||||
|
||||
it("checked() returns false after action disables binding", () => {
|
||||
API.executeAction(actionToggleArrowBinding); // true → false
|
||||
expect(actionToggleArrowBinding.checked!(h.state)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Arrow does not bind when isBindingEnabled is false
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("Arrow drawing with binding disabled", () => {
|
||||
/**
|
||||
* Baseline: verify binding IS created with binding enabled so we know the
|
||||
* spatial setup is correct.
|
||||
*/
|
||||
it("arrow startBinding is set when binding is enabled", async () => {
|
||||
API.setElements([
|
||||
API.createElement({
|
||||
type: "rectangle",
|
||||
id: "baselineRect",
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 400,
|
||||
height: 200,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
UI.clickTool("arrow");
|
||||
// Start inside the rectangle so startBinding can be created
|
||||
mouse.down(200, 200);
|
||||
mouse.up(700, 200);
|
||||
|
||||
await waitFor(() => {
|
||||
const arrow = h.elements.find(
|
||||
(el): el is ExcalidrawArrowElement => el.type === "arrow",
|
||||
);
|
||||
expect(arrow).toBeDefined();
|
||||
expect(arrow!.startBinding).not.toBeNull();
|
||||
expect(arrow!.startBinding!.elementId).toBe("baselineRect");
|
||||
});
|
||||
});
|
||||
|
||||
it("arrow has no startBinding when binding is disabled", async () => {
|
||||
API.setElements([
|
||||
API.createElement({
|
||||
type: "rectangle",
|
||||
id: "rect1",
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 400,
|
||||
height: 200,
|
||||
}),
|
||||
]);
|
||||
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
UI.clickTool("arrow");
|
||||
// Start inside the rectangle – binding is off, so no startBinding
|
||||
mouse.down(200, 200);
|
||||
mouse.up(700, 200);
|
||||
|
||||
await waitFor(() => {
|
||||
const arrow = h.elements.find(
|
||||
(el): el is ExcalidrawArrowElement => el.type === "arrow",
|
||||
);
|
||||
expect(arrow).toBeDefined();
|
||||
expect(arrow!.startBinding).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("arrow has no endBinding when binding is disabled", async () => {
|
||||
API.setElements([
|
||||
API.createElement({
|
||||
type: "rectangle",
|
||||
id: "rect2",
|
||||
x: 500,
|
||||
y: 100,
|
||||
width: 300,
|
||||
height: 200,
|
||||
}),
|
||||
]);
|
||||
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
UI.clickTool("arrow");
|
||||
// End inside the target rectangle – binding off -> no endBinding
|
||||
mouse.down(100, 200);
|
||||
mouse.up(600, 200);
|
||||
|
||||
await waitFor(() => {
|
||||
const arrow = h.elements.find(
|
||||
(el): el is ExcalidrawArrowElement => el.type === "arrow",
|
||||
);
|
||||
expect(arrow).toBeDefined();
|
||||
expect(arrow!.endBinding).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("re-enabling binding via action causes new arrows to bind again", async () => {
|
||||
API.setElements([
|
||||
API.createElement({
|
||||
type: "rectangle",
|
||||
id: "rect3",
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 400,
|
||||
height: 200,
|
||||
}),
|
||||
]);
|
||||
|
||||
// Disable then re-enable binding
|
||||
API.executeAction(actionToggleArrowBinding); // true -> false
|
||||
API.executeAction(actionToggleArrowBinding); // false -> true
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
UI.clickTool("arrow");
|
||||
mouse.down(200, 200);
|
||||
mouse.up(700, 200);
|
||||
|
||||
await waitFor(() => {
|
||||
const arrow = h.elements.find(
|
||||
(el): el is ExcalidrawArrowElement => el.type === "arrow",
|
||||
);
|
||||
expect(arrow).toBeDefined();
|
||||
expect(arrow!.startBinding).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("elbow arrow does not snap to rectangle when binding is disabled", async () => {
|
||||
const rect = API.createElement({
|
||||
type: "rectangle",
|
||||
id: "rect-elbow-no-snap",
|
||||
x: 900,
|
||||
y: 500,
|
||||
width: 200,
|
||||
height: 120,
|
||||
}) as ExcalidrawBindableElement;
|
||||
API.setElements([rect]);
|
||||
|
||||
// Turn off arrow binding
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
isMidpointSnappingEnabled: false,
|
||||
});
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
|
||||
// Create the elbow arrow
|
||||
UI.clickTool("arrow");
|
||||
API.setAppState({ currentItemArrowType: "elbow" });
|
||||
mouse.downAt(700, 400);
|
||||
mouse.upAt(760, 460);
|
||||
|
||||
let arrow: ExcalidrawArrowElement;
|
||||
await waitFor(() => {
|
||||
const maybeArrow = h.elements.find(isElbowArrow);
|
||||
expect(maybeArrow).toBeDefined();
|
||||
arrow = maybeArrow!;
|
||||
});
|
||||
|
||||
// Move the elbow arrow
|
||||
UI.clickTool("selection");
|
||||
|
||||
const insideRectanglePoint = pointFrom<GlobalPoint>(1010, 570);
|
||||
const originalArrowEndGlobal = pointFrom<GlobalPoint>(
|
||||
arrow!.x + arrow!.points[arrow!.points.length - 1][0],
|
||||
arrow!.y + arrow!.points[arrow!.points.length - 1][1],
|
||||
);
|
||||
const originalArrowEndViewport = sceneCoordsToViewportCoords(
|
||||
{
|
||||
sceneX: originalArrowEndGlobal[0],
|
||||
sceneY: originalArrowEndGlobal[1],
|
||||
},
|
||||
h.state,
|
||||
);
|
||||
const insideRectangleViewport = sceneCoordsToViewportCoords(
|
||||
{
|
||||
sceneX: insideRectanglePoint[0],
|
||||
sceneY: insideRectanglePoint[1],
|
||||
},
|
||||
h.state,
|
||||
);
|
||||
|
||||
// End point dragged inside the rectangle; with snapping enabled this
|
||||
// would snap to the rectangle outline.
|
||||
mouse.moveTo(originalArrowEndViewport.x, originalArrowEndViewport.y);
|
||||
mouse.down();
|
||||
mouse.moveTo(insideRectangleViewport.x, insideRectangleViewport.y);
|
||||
mouse.up();
|
||||
|
||||
const updatedEnd = arrow!.points[arrow!.points.length - 1];
|
||||
const updatedEndGlobal = pointFrom<GlobalPoint>(
|
||||
arrow!.x + updatedEnd[0],
|
||||
arrow!.y + updatedEnd[1],
|
||||
);
|
||||
|
||||
expect(arrow!.startBinding).toBeNull();
|
||||
expect(arrow!.endBinding).toBeNull();
|
||||
expect(updatedEndGlobal).not.toEqual(originalArrowEndGlobal);
|
||||
expect(updatedEndGlobal).toEqual(insideRectanglePoint);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Arrow does snap to midpoint when isMidpointSnappingEnabled is true
|
||||
// -------------------------------------------------------------------------
|
||||
describe("Arrow doesn't snap to midpoint when midpoint snapping is disabled", () => {
|
||||
it("does not snap to midpoint when midpoint snapping is turned off", () => {
|
||||
const rect = API.createElement({
|
||||
type: "rectangle",
|
||||
id: "rectNoMidSnap",
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 400,
|
||||
height: 200,
|
||||
}) as ExcalidrawBindableElement;
|
||||
const arrow = API.createElement({
|
||||
type: "arrow",
|
||||
x: 0,
|
||||
y: 250,
|
||||
width: 502,
|
||||
height: -48,
|
||||
points: [pointFrom<LocalPoint>(0, 0), pointFrom<LocalPoint>(502, -48)],
|
||||
}) as ExcalidrawArrowElement;
|
||||
const elementsMap = new Map<string, ExcalidrawElement>([
|
||||
[rect.id, rect],
|
||||
[arrow.id, arrow],
|
||||
]);
|
||||
const point = pointFrom<GlobalPoint>(502, 202);
|
||||
|
||||
const snappedWithMidpoint = projectFixedPointOntoDiagonal(
|
||||
arrow,
|
||||
point,
|
||||
rect,
|
||||
"end",
|
||||
elementsMap,
|
||||
h.state.zoom,
|
||||
true,
|
||||
);
|
||||
const snappedWithoutMidpoint = projectFixedPointOntoDiagonal(
|
||||
arrow,
|
||||
point,
|
||||
rect,
|
||||
"end",
|
||||
elementsMap,
|
||||
h.state.zoom,
|
||||
false,
|
||||
);
|
||||
|
||||
expect(snappedWithMidpoint).toEqual([500, 200]);
|
||||
expect(snappedWithoutMidpoint).not.toEqual([500, 200]);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Ctrl / Cmd key toggle
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("Ctrl key toggle when binding preference is disabled", () => {
|
||||
it("Ctrl keydown temporarily enables binding when preference is disabled", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
ctrlKeyDown();
|
||||
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("Ctrl keyup restores isBindingEnabled to false after the temporary toggle", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("full round-trip: off → Ctrl down → on → Ctrl up → off", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("full round-trip can be repeated after Ctrl release resets state", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
// First cycle
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
|
||||
// Second cycle
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Ctrl key toggle when binding starts ON", () => {
|
||||
it("Ctrl keydown temporarily disables binding when it was on", () => {
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("Ctrl keyup restores isBindingEnabled to true after the temporary toggle", () => {
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// event.repeat guard
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("event.repeat guard", () => {
|
||||
it("Ctrl keydown with repeat=true does not toggle binding (preference: disabled)", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
});
|
||||
|
||||
ctrlKeyDown({ repeat: true });
|
||||
|
||||
// Must remain off – repeat events are ignored
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("Ctrl keydown with repeat=true does not toggle binding (default: on)", () => {
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyDown({ repeat: true });
|
||||
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("pressing another key while Ctrl held does not change binding state", () => {
|
||||
// Start ON, first Ctrl keydown flips to false
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
|
||||
ctrlKeyDown();
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
|
||||
// A second keydown with Ctrl (e.g. pressing another key while Ctrl held)
|
||||
// should leave state unchanged
|
||||
fireEvent.keyDown(document, {
|
||||
key: "z",
|
||||
ctrlKey: true,
|
||||
repeat: false,
|
||||
});
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
|
||||
// Ctrl keyup restores to preference value
|
||||
ctrlKeyUp();
|
||||
expect(h.state.isBindingEnabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// View-mode guard
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe("View-mode guard", () => {
|
||||
it("Ctrl keydown in viewMode does not toggle isBindingEnabled", () => {
|
||||
API.setAppState({
|
||||
bindingPreference: "disabled",
|
||||
isBindingEnabled: false,
|
||||
viewModeEnabled: true,
|
||||
});
|
||||
|
||||
ctrlKeyDown();
|
||||
|
||||
// Handler returns early in viewMode — state must stay false
|
||||
expect(h.state.isBindingEnabled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -87,20 +87,17 @@ describe("contextMenu element", () => {
|
||||
clientY: 1,
|
||||
});
|
||||
const contextMenu = UI.queryContextMenu();
|
||||
const contextMenuOptions =
|
||||
contextMenu?.querySelectorAll(".context-menu li");
|
||||
const expectedShortcutNames: ShortcutName[] = [
|
||||
"paste",
|
||||
"selectAll",
|
||||
"gridMode",
|
||||
"objectsSnapMode",
|
||||
"zenMode",
|
||||
"viewMode",
|
||||
"objectsSnapMode",
|
||||
"stats",
|
||||
];
|
||||
|
||||
expect(contextMenu).not.toBeNull();
|
||||
expect(contextMenuOptions?.length).toBe(expectedShortcutNames.length);
|
||||
expectedShortcutNames.forEach((shortcutName) => {
|
||||
expect(
|
||||
contextMenu?.querySelector(`li[data-testid="${shortcutName}"]`),
|
||||
|
||||
@@ -223,6 +223,7 @@ export type InteractiveCanvasAppState = Readonly<
|
||||
multiElement: AppState["multiElement"];
|
||||
newElement: AppState["newElement"];
|
||||
isBindingEnabled: AppState["isBindingEnabled"];
|
||||
isMidpointSnappingEnabled: AppState["isMidpointSnappingEnabled"];
|
||||
suggestedBinding: AppState["suggestedBinding"];
|
||||
isRotating: AppState["isRotating"];
|
||||
elementsToHighlight: AppState["elementsToHighlight"];
|
||||
@@ -301,7 +302,15 @@ export interface AppState {
|
||||
* - set on pointer down, updated during pointer move
|
||||
*/
|
||||
selectionElement: NonDeletedExcalidrawElement | null;
|
||||
/**
|
||||
* tracking current arrow binding editor state (takes into account
|
||||
* `bindingPreference` and keyboard modifiers (ctrl/alt)
|
||||
*/
|
||||
isBindingEnabled: boolean;
|
||||
/** user arrow binding preference */
|
||||
bindingPreference: "enabled" | "disabled";
|
||||
/** user preference whether arrow snap to midpoints while binding */
|
||||
isMidpointSnappingEnabled: boolean;
|
||||
startBoundElement: NonDeleted<ExcalidrawBindableElement> | null;
|
||||
suggestedBinding: {
|
||||
element: NonDeleted<ExcalidrawBindableElement>;
|
||||
|
||||
@@ -12,6 +12,7 @@ exports[`exportToSvg > with default arguments 1`] = `
|
||||
"type": "selection",
|
||||
},
|
||||
"bindMode": "orbit",
|
||||
"bindingPreference": "enabled",
|
||||
"collaborators": Map {},
|
||||
"contextMenu": null,
|
||||
"croppingElementId": null,
|
||||
@@ -58,6 +59,7 @@ exports[`exportToSvg > with default arguments 1`] = `
|
||||
"isBindingEnabled": true,
|
||||
"isCropping": false,
|
||||
"isLoading": false,
|
||||
"isMidpointSnappingEnabled": true,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
|
||||
Reference in New Issue
Block a user