Compare commits

..

8 Commits

Author SHA1 Message Date
zsviczian
85ebc4e2f1 lint 2024-05-23 18:07:25 +00:00
zsviczian
c79bb5ed6a changed logic to match regression tests 2024-05-23 18:02:05 +00:00
zsviczian
6ef88eb851 double tap eraser 2024-05-23 17:37:08 +00:00
David Luzar
a71bb63d1f fix: fix twitter og image (#8050) 2024-05-23 11:52:37 +02:00
Marcel Mraz
661d6a4a75 fix: flaky snapshot tests with floating point precision issues (#8049) 2024-05-23 11:51:01 +02:00
David Luzar
defd34923a docs: fix updateScene storeAction default tsdoc & document types (#8048) 2024-05-22 13:40:23 +02:00
Ryan Di
c540bd68aa feat: wrap long text when pasting (#8026)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-05-21 16:56:09 +02:00
Marcel Mraz
eddbe55f50 fix: always re-generate index of defined moved elements (#8040) 2024-05-20 23:23:42 +02:00
17 changed files with 453 additions and 335 deletions

View File

@@ -20,7 +20,7 @@
name="description"
content="Excalidraw is a virtual collaborative whiteboard tool that lets you easily sketch diagrams that have a hand-drawn feel to them."
/>
<meta name="image" content="https://excalidraw.com/og-image-2.png" />
<meta name="image" content="https://excalidraw.com/og-image-3.png" />
<!-- Open Graph / Facebook -->
<meta property="og:site_name" content="Excalidraw" />
@@ -35,7 +35,7 @@
property="og:description"
content="Excalidraw is a virtual collaborative whiteboard tool that lets you easily sketch diagrams that have a hand-drawn feel to them."
/>
<meta property="og:image" content="https://excalidraw.com/og-image-2.png" />
<meta property="og:image" content="https://excalidraw.com/og-image-3.png" />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
@@ -51,7 +51,7 @@
/>
<meta
property="twitter:image"
content="https://excalidraw.com/og-twitter-v2.png"
content="https://excalidraw.com/og-image-3.png"
/>
<!-- General tags -->

View File

@@ -1477,19 +1477,28 @@ export class ElementsChange implements Change<SceneElementsMap> {
return elements;
}
const previous = Array.from(elements.values());
const reordered = orderByFractionalIndex([...previous]);
const unordered = Array.from(elements.values());
const ordered = orderByFractionalIndex([...unordered]);
const moved = Delta.getRightDifferences(unordered, ordered, true).reduce(
(acc, arrayIndex) => {
const candidate = unordered[Number(arrayIndex)];
if (candidate && changed.has(candidate.id)) {
acc.set(candidate.id, candidate);
}
if (
!flags.containsVisibleDifference &&
Delta.isRightDifferent(previous, reordered, true)
) {
return acc;
},
new Map(),
);
if (!flags.containsVisibleDifference && moved.size) {
// we found a difference in order!
flags.containsVisibleDifference = true;
}
// let's synchronize all invalid indices of moved elements
return arrayToMap(syncMovedIndices(reordered, changed)) as typeof elements;
// synchronize all elements that were actually moved
// could fallback to synchronizing all invalid indices
return arrayToMap(syncMovedIndices(ordered, moved)) as typeof elements;
}
/**

View File

@@ -88,6 +88,7 @@ import {
isIOS,
supportsResizeObserver,
DEFAULT_COLLISION_THRESHOLD,
DEFAULT_TEXT_ALIGN,
} from "../constants";
import type { ExportedElements } from "../data";
import { exportCanvas, loadFromBlob } from "../data";
@@ -331,6 +332,8 @@ import {
getLineHeightInPx,
isMeasureTextSupported,
isValidTextContainer,
measureText,
wrapText,
} from "../element/textElement";
import {
showHyperlinkTooltip,
@@ -367,7 +370,11 @@ import {
actionRemoveAllElementsFromFrame,
actionSelectAllElementsInFrame,
} from "../actions/actionFrame";
import { actionToggleHandTool, zoomToFit } from "../actions/actionCanvas";
import {
actionToggleEraserTool,
actionToggleHandTool,
zoomToFit,
} from "../actions/actionCanvas";
import { jotaiStore } from "../jotai";
import { activeConfirmDialogAtom } from "./ActiveConfirmDialog";
import { ImageSceneDataError } from "../errors";
@@ -430,6 +437,7 @@ import {
} from "./hyperlink/helpers";
import { getShortcutFromShortcutName } from "../actions/shortcuts";
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
import { getVisibleSceneBounds } from "../element/bounds";
const AppContext = React.createContext<AppClassProperties>(null!);
const AppPropsContext = React.createContext<AppProps>(null!);
@@ -2565,7 +2573,7 @@ class App extends React.Component<AppProps, AppState> {
addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }),
addEventListener(
document,
EVENT.MOUSE_MOVE,
EVENT.POINTER_MOVE,
this.updateCurrentCursorPosition,
),
// rerender text elements on font load to fix #637 && #1553
@@ -3341,32 +3349,53 @@ class App extends React.Component<AppProps, AppState> {
text,
fontSize: this.state.currentItemFontSize,
fontFamily: this.state.currentItemFontFamily,
textAlign: this.state.currentItemTextAlign,
textAlign: DEFAULT_TEXT_ALIGN,
verticalAlign: DEFAULT_VERTICAL_ALIGN,
locked: false,
};
const fontString = getFontString({
fontSize: textElementProps.fontSize,
fontFamily: textElementProps.fontFamily,
});
const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
const [x1, , x2] = getVisibleSceneBounds(this.state);
// long texts should not go beyond 800 pixels in width nor should it go below 200 px
const maxTextWidth = Math.max(Math.min((x2 - x1) * 0.5, 800), 200);
const LINE_GAP = 10;
let currentY = y;
const lines = isPlainPaste ? [text] : text.split("\n");
const textElements = lines.reduce(
(acc: ExcalidrawTextElement[], line, idx) => {
const text = line.trim();
const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
if (text.length) {
const originalText = line.trim();
if (originalText.length) {
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
x,
y: currentY,
});
let metrics = measureText(originalText, fontString, lineHeight);
const isTextWrapped = metrics.width > maxTextWidth;
const text = isTextWrapped
? wrapText(originalText, fontString, maxTextWidth)
: originalText;
metrics = isTextWrapped
? measureText(text, fontString, lineHeight)
: metrics;
const startX = x - metrics.width / 2;
const startY = currentY - metrics.height / 2;
const element = newTextElement({
...textElementProps,
x,
y: currentY,
x: startX,
y: startY,
text,
originalText,
lineHeight,
autoResize: !isTextWrapped,
frameId: topLayerFrame ? topLayerFrame.id : null,
});
acc.push(element);
@@ -3683,7 +3712,7 @@ class App extends React.Component<AppProps, AppState> {
elements?: SceneData["elements"];
appState?: Pick<AppState, K> | null;
collaborators?: SceneData["collaborators"];
/** @default StoreAction.CAPTURE */
/** @default StoreAction.NONE */
storeAction?: SceneData["storeAction"];
}) => {
const nextElements = syncInvalidIndices(sceneData.elements ?? []);
@@ -4842,6 +4871,7 @@ class App extends React.Component<AppProps, AppState> {
});
};
private debounceDoubleClickTimestamp: number = 0;
private handleCanvasDoubleClick = (
event: React.MouseEvent<HTMLCanvasElement>,
) => {
@@ -4850,6 +4880,23 @@ class App extends React.Component<AppProps, AppState> {
if (this.state.multiElement) {
return;
}
if (
this.state.penMode &&
this.lastPointerDownEvent?.pointerType === "touch" &&
this.state.activeTool.type !== "selection"
) {
const now = Date.now();
if (now - this.debounceDoubleClickTimestamp < 200) {
//handleCanvasDoubleClick click fires twice in case of touch.
//Once from the onTouchStart event handler, once from the double click event handler
return;
}
this.debounceDoubleClickTimestamp = now;
this.updateScene(actionToggleEraserTool.perform([] as any, this.state));
return;
}
// we should only be able to double click when mode is selection
if (this.state.activeTool.type !== "selection") {
return;

View File

@@ -140,7 +140,7 @@ const restoreElementWithProperties = <
seed: element.seed ?? 1,
groupIds: element.groupIds ?? [],
frameId: element.frameId ?? null,
roundness: typeof element.roundness !== "undefined"
roundness: element.roundness
? element.roundness
: element.strokeSharpness === "round"
? {

View File

@@ -215,6 +215,7 @@ const getTextElementPositionOffsets = (
export const newTextElement = (
opts: {
text: string;
originalText?: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
@@ -222,6 +223,7 @@ export const newTextElement = (
containerId?: ExcalidrawTextContainer["id"] | null;
lineHeight?: ExcalidrawTextElement["lineHeight"];
strokeWidth?: ExcalidrawTextElement["strokeWidth"];
autoResize?: ExcalidrawTextElement["autoResize"];
} & ElementConstructorOpts,
): NonDeleted<ExcalidrawTextElement> => {
const fontFamily = opts.fontFamily || DEFAULT_FONT_FAMILY;
@@ -252,8 +254,8 @@ export const newTextElement = (
width: metrics.width,
height: metrics.height,
containerId: opts.containerId || null,
originalText: text,
autoResize: true,
originalText: opts.originalText ?? text,
autoResize: opts.autoResize ?? true,
lineHeight,
};

View File

@@ -1064,7 +1064,7 @@ describe("textWysiwyg", () => {
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
[
85,
4.999999999999986,
"5.00000",
]
`);
@@ -1109,8 +1109,8 @@ describe("textWysiwyg", () => {
UI.resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 100]);
expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
[
374.99999999999994,
-535.0000000000001,
"375.00000",
"-535.00000",
]
`);
});

View File

@@ -133,27 +133,11 @@ const getMovedIndicesGroups = (
let i = 0;
while (i < elements.length) {
if (
movedElements.has(elements[i].id) &&
!isValidFractionalIndex(
elements[i]?.index,
elements[i - 1]?.index,
elements[i + 1]?.index,
)
) {
if (movedElements.has(elements[i].id)) {
const indicesGroup = [i - 1, i]; // push the lower bound index as the first item
while (++i < elements.length) {
if (
!(
movedElements.has(elements[i].id) &&
!isValidFractionalIndex(
elements[i]?.index,
elements[i - 1]?.index,
elements[i + 1]?.index,
)
)
) {
if (!movedElements.has(elements[i].id)) {
break;
}

View File

@@ -6,6 +6,7 @@ import { deepCopyElement } from "./element/newElement";
import type { OrderedExcalidrawElement } from "./element/types";
import { Emitter } from "./emitter";
import type { AppState, ObservedAppState } from "./types";
import type { ValueOf } from "./utility-types";
import { isShallowEqual } from "./utils";
// hidden non-enumerable property for runtime checks
@@ -35,16 +36,41 @@ const isObservedAppState = (
): appState is ObservedAppState =>
!!Reflect.get(appState, hiddenObservedAppStateProp);
export type StoreActionType = "capture" | "update" | "none";
export const StoreAction: {
[K in Uppercase<StoreActionType>]: StoreActionType;
} = {
export const StoreAction = {
/**
* Immediately undoable.
*
* Use for updates which should be captured.
* Should be used for most of the local updates.
*
* These updates will _immediately_ make it to the local undo / redo stacks.
*/
CAPTURE: "capture",
/**
* Never undoable.
*
* Use for updates which should never be recorded, such as remote updates
* or scene initialization.
*
* These updates will _never_ make it to the local undo / redo stacks.
*/
UPDATE: "update",
/**
* Eventually undoable.
*
* Use for updates which should not be captured immediately - likely
* exceptions which are part of some async multi-step process. Otherwise, all
* such updates would end up being captured with the next
* `StoreAction.CAPTURE` - triggered either by the next `updateScene`
* or internally by the editor.
*
* These updates will _eventually_ make it to the local undo / redo stacks.
*/
NONE: "none",
} as const;
export type StoreActionType = ValueOf<typeof StoreAction>;
/**
* Represent an increment to the Store.
*/

View File

@@ -27,7 +27,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -130,7 +130,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -182,7 +182,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -248,7 +248,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -288,7 +288,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -406,7 +406,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -453,7 +453,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -505,7 +505,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -554,7 +554,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -603,7 +603,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -643,7 +643,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4448,7 +4448,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4551,7 +4551,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4603,7 +4603,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4669,7 +4669,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4709,7 +4709,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -4827,7 +4827,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -4874,7 +4874,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -4926,7 +4926,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -4975,7 +4975,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -5024,7 +5024,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5064,7 +5064,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5567,7 +5567,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5670,7 +5670,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5722,7 +5722,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5788,7 +5788,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5828,7 +5828,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -5946,7 +5946,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -5993,7 +5993,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -6045,7 +6045,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -6094,7 +6094,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -6143,7 +6143,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -6183,7 +6183,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -6741,7 +6741,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -6793,7 +6793,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7005,7 +7005,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7061,7 +7061,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7105,7 +7105,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7158,7 +7158,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
<g
fill="none"
stroke="currentColor"
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7200,7 +7200,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7393,7 +7393,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7496,7 +7496,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7548,7 +7548,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7614,7 +7614,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7654,7 +7654,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -7772,7 +7772,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7819,7 +7819,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7871,7 +7871,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7920,7 +7920,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -7969,7 +7969,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8009,7 +8009,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8279,7 +8279,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8382,7 +8382,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8434,7 +8434,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8500,7 +8500,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8540,7 +8540,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8658,7 +8658,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -8705,7 +8705,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -8757,7 +8757,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -8806,7 +8806,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.5}
strokeWidth={"1.50000"}
>
<path
d="M0 0h24v24H0z"
@@ -8855,7 +8855,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"
@@ -8895,7 +8895,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
viewBox="0 0 24 24"
>
<g
strokeWidth={1.25}
strokeWidth={"1.25000"}
>
<path
d="M0 0h24v24H0z"

View File

@@ -181,7 +181,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 99.19725525211979,
"height": "99.19726",
"id": "id163",
"index": "a2",
"isDeleted": false,
@@ -195,8 +195,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
0,
],
[
98.40367721010284,
99.19725525211979,
"98.40368",
"99.19726",
],
],
"roughness": 1,
@@ -211,7 +211,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"type": "arrow",
"updated": 1,
"version": 54,
"width": 98.40367721010284,
"width": "98.40368",
"x": 1,
"y": 0,
}
@@ -278,10 +278,10 @@ History {
"deleted": {
"endBinding": {
"elementId": "id162",
"focus": 0.009900990099009901,
"focus": "0.00990",
"gap": 1,
},
"height": 0.9800031696987099,
"height": "0.98000",
"points": [
[
0,
@@ -289,22 +289,22 @@ History {
],
[
98,
-0.9800031696987099,
"-0.98000",
],
],
"startBinding": {
"elementId": "id161",
"focus": 0.0297029702970297,
"focus": "0.02970",
"gap": 1,
},
},
"inserted": {
"endBinding": {
"elementId": "id162",
"focus": -0.02,
"focus": "-0.02000",
"gap": 1,
},
"height": 0.0002487679019458344,
"height": "0.00025",
"points": [
[
0,
@@ -312,12 +312,12 @@ History {
],
[
98,
0.0002487679019458344,
"0.00025",
],
],
"startBinding": {
"elementId": "id161",
"focus": 0.02,
"focus": "0.02000",
"gap": 1,
},
},
@@ -369,15 +369,15 @@ History {
"focus": 0,
"gap": 1,
},
"height": 99.19725525211979,
"height": "99.19726",
"points": [
[
0,
0,
],
[
98.40367721010284,
99.19725525211979,
"98.40368",
"99.19726",
],
],
"startBinding": null,
@@ -386,10 +386,10 @@ History {
"inserted": {
"endBinding": {
"elementId": "id162",
"focus": 0.009900990099009901,
"focus": "0.00990",
"gap": 1,
},
"height": 0.9802432787444684,
"height": "0.98024",
"points": [
[
0,
@@ -397,15 +397,15 @@ History {
],
[
98,
-0.9802432787444684,
"-0.98024",
],
],
"startBinding": {
"elementId": "id161",
"focus": 0.0297029702970297,
"focus": "0.02970",
"gap": 1,
},
"y": 0.9903686540602428,
"y": "0.99037",
},
},
"id166" => Delta {
@@ -1188,7 +1188,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0.03596020595764898,
"height": "0.03596",
"id": "id169",
"index": "Zz",
"isDeleted": false,
@@ -1203,7 +1203,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
[
98,
-0.03596020595764898,
"-0.03596",
],
],
"roughness": 1,
@@ -1224,7 +1224,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"version": 15,
"width": 98,
"x": 1,
"y": 0.05467419069071122,
"y": "0.05467",
}
`;
@@ -1531,7 +1531,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0.03596020595764898,
"height": "0.03596",
"id": "id172",
"index": "a0",
"isDeleted": false,
@@ -1546,7 +1546,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
[
98,
-0.03596020595764898,
"-0.03596",
],
],
"roughness": 1,
@@ -1567,7 +1567,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"version": 15,
"width": 98,
"x": 1,
"y": 0.05467419069071122,
"y": "0.05467",
}
`;
@@ -1680,7 +1680,7 @@ History {
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 2.6199110083015196,
"height": "2.61991",
"index": "a0",
"isDeleted": false,
"lastCommittedPoint": null,
@@ -1694,7 +1694,7 @@ History {
],
[
98,
-2.6199110083015196,
"-2.61991",
],
],
"roughness": 1,
@@ -1713,7 +1713,7 @@ History {
"type": "arrow",
"width": 98,
"x": 1,
"y": 3.98333408405027,
"y": "3.98333",
},
"inserted": {
"isDeleted": true,
@@ -2206,7 +2206,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 373.7994222717614,
"height": "373.79942",
"id": "id177",
"index": "a2",
"isDeleted": false,
@@ -2221,7 +2221,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
],
[
498,
-373.7994222717614,
"-373.79942",
],
],
"roughness": 1,
@@ -2242,7 +2242,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"version": 12,
"width": 498,
"x": 1,
"y": -37.91991400161248,
"y": "-37.91991",
}
`;
@@ -2598,7 +2598,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id143",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -2639,7 +2639,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id144",
"index": "a2",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -2889,7 +2889,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id146",
"index": "a0",
"isDeleted": true,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -2930,7 +2930,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id147",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -3165,7 +3165,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id134",
"index": "a0V",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -3206,7 +3206,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id133",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -3483,7 +3483,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id136",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -3724,7 +3724,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id131",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -3956,7 +3956,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id139",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -4207,7 +4207,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id141",
"index": "a0",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -4267,7 +4267,7 @@ History {
"height": 25,
"index": "a0",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -4472,7 +4472,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id155",
"index": "a0",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -4695,7 +4695,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id153",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -4913,7 +4913,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id149",
"index": "a1",
"isDeleted": true,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -5139,7 +5139,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"id": "id151",
"index": "a0",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -13995,7 +13995,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id": "id51",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -14015,7 +14015,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
}
`;
@@ -14254,7 +14254,7 @@ History {
"height": 100,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -14389,7 +14389,7 @@ History {
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
},
"inserted": {
"containerId": null,
@@ -14677,7 +14677,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id": "id45",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -14697,7 +14697,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
}
`;
@@ -14860,7 +14860,7 @@ History {
"height": 100,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -14995,7 +14995,7 @@ History {
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
},
"inserted": {
"containerId": null,
@@ -15283,7 +15283,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id": "id57",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -15303,7 +15303,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
}
`;
@@ -15466,7 +15466,7 @@ History {
"height": 100,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -15601,7 +15601,7 @@ History {
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
},
"inserted": {
"containerId": null,
@@ -15887,7 +15887,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id": "id63",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -15907,7 +15907,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
}
`;
@@ -16140,7 +16140,7 @@ History {
"height": 100,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -16275,7 +16275,7 @@ History {
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
},
"inserted": {
"containerId": null,
@@ -16587,7 +16587,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id": "id70",
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -16607,7 +16607,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
}
`;
@@ -16855,7 +16855,7 @@ History {
"height": 100,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -16990,7 +16990,7 @@ History {
"verticalAlign": "middle",
"width": 30,
"x": -65,
"y": -12.5,
"y": "-12.50000",
},
"inserted": {
"containerId": null,
@@ -17320,7 +17320,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 6,
"version": 7,
"width": 10,
"x": 10,
"y": 0,
@@ -17352,7 +17352,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 9,
"version": 10,
"width": 10,
"x": 40,
"y": 40,
@@ -17604,7 +17604,7 @@ History {
"index": "a2",
},
"inserted": {
"index": "a0",
"index": "Zz",
},
},
"id41" => Delta {
@@ -17612,7 +17612,7 @@ History {
"index": "a3",
},
"inserted": {
"index": "a0V",
"index": "a0",
},
},
},

View File

@@ -189,13 +189,13 @@ exports[`move element > rectangles with binding arrow 7`] = `
"endArrowhead": "arrow",
"endBinding": {
"elementId": "id1",
"focus": -0.46666666666666673,
"focus": "-0.46667",
"gap": 10,
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 81.48231043525051,
"height": "81.48231",
"id": "id2",
"index": "a2",
"isDeleted": false,
@@ -210,7 +210,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
],
[
81,
81.48231043525051,
"81.48231",
],
],
"roughness": 1,
@@ -221,7 +221,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
"startArrowhead": null,
"startBinding": {
"elementId": "id0",
"focus": -0.6000000000000001,
"focus": "-0.60000",
"gap": 10,
},
"strokeColor": "#1e1e1e",
@@ -233,6 +233,6 @@ exports[`move element > rectangles with binding arrow 7`] = `
"versionNonce": 2066753033,
"width": 81,
"x": 110,
"y": 49.981789081137734,
"y": "49.98179",
}
`;

View File

@@ -336,7 +336,7 @@ History {
"groupIds": [
"id5",
],
"index": "a1V",
"index": "a2",
},
"inserted": {
"groupIds": [],
@@ -348,9 +348,11 @@ History {
"groupIds": [
"id5",
],
"index": "a3",
},
"inserted": {
"groupIds": [],
"index": "a2",
},
},
},
@@ -719,7 +721,7 @@ History {
"groupIds": [
"id4",
],
"index": "a1V",
"index": "a2",
},
"inserted": {
"groupIds": [],
@@ -731,9 +733,11 @@ History {
"groupIds": [
"id4",
],
"index": "a3",
},
"inserted": {
"groupIds": [],
"index": "a2",
},
},
},
@@ -1856,7 +1860,7 @@ History {
"groupIds": [
"id5",
],
"index": "a1V",
"index": "a2",
},
"inserted": {
"groupIds": [],
@@ -1868,9 +1872,11 @@ History {
"groupIds": [
"id5",
],
"index": "a3",
},
"inserted": {
"groupIds": [],
"index": "a2",
},
},
},
@@ -10752,7 +10758,7 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
"pendingImageElementId": null,
"previousSelectedElementIds": {},
"resizingElement": null,
"scrollX": -6.2500000000000036,
"scrollX": "-6.25000",
"scrollY": 0,
"scrolledOutside": false,
"selectedElementIds": {},
@@ -12810,7 +12816,7 @@ History {
"id5",
"id3",
],
"index": "a1V",
"index": "a2",
},
"inserted": {
"groupIds": [
@@ -12825,11 +12831,13 @@ History {
"id5",
"id3",
],
"index": "a3",
},
"inserted": {
"groupIds": [
"id3",
],
"index": "a2",
},
},
},
@@ -13689,7 +13697,7 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
"previousSelectedElementIds": {},
"resizingElement": null,
"scrollX": 20,
"scrollY": -18.535533905932738,
"scrollY": "-18.53553",
"scrolledOutside": false,
"selectedElementIds": {},
"selectedElementsAreBeingDragged": false,

View File

@@ -316,7 +316,7 @@ exports[`restoreElements > should restore text element correctly passing value f
"id": "id-text01",
"index": "a0",
"isDeleted": false,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,
@@ -338,7 +338,7 @@ exports[`restoreElements > should restore text element correctly passing value f
"verticalAlign": "middle",
"width": 100,
"x": -20,
"y": -8.75,
"y": "-8.75000",
}
`;
@@ -359,7 +359,7 @@ exports[`restoreElements > should restore text element correctly with unknown fo
"id": "id-text01",
"index": "a0",
"isDeleted": true,
"lineHeight": 1.25,
"lineHeight": "1.25000",
"link": null,
"locked": false,
"opacity": 100,

View File

@@ -77,97 +77,6 @@ describe("sync invalid indices with array order", () => {
});
});
describe("should NOT sync index when it is already valid", () => {
testMovedIndicesSync({
elements: [
{ id: "A", index: "a2" },
{ id: "B", index: "a4" },
],
movedElements: ["A"],
expect: {
validInput: true,
unchangedElements: ["A", "B"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A", index: "a2" },
{ id: "B", index: "a4" },
],
movedElements: ["B"],
expect: {
validInput: true,
unchangedElements: ["A", "B"],
},
});
});
describe("should NOT sync indices when they are already valid", () => {
{
testMovedIndicesSync({
elements: [
{ id: "A", index: "a1" },
{ id: "B", index: "a0" },
{ id: "C", index: "a2" },
],
movedElements: ["B", "C"],
expect: {
// this should not sync 'C'
unchangedElements: ["A", "C"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A", index: "a1" },
{ id: "B", index: "a0" },
{ id: "C", index: "a2" },
],
movedElements: ["A", "B"],
expect: {
// but this should sync 'A' as it's invalid!
unchangedElements: ["C"],
},
});
}
testMovedIndicesSync({
elements: [
{ id: "A", index: "a0" },
{ id: "B", index: "a2" },
{ id: "C", index: "a1" },
{ id: "D", index: "a1" },
{ id: "E", index: "a2" },
],
movedElements: ["B", "D", "E"],
expect: {
// should not sync 'E'
unchangedElements: ["A", "C", "E"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A" },
{ id: "B" },
{ id: "C", index: "a0" },
{ id: "D", index: "a2" },
{ id: "E" },
{ id: "F", index: "a3" },
{ id: "G" },
{ id: "H", index: "a1" },
{ id: "I", index: "a2" },
{ id: "J" },
],
movedElements: ["A", "B", "D", "E", "F", "G", "J"],
expect: {
// should not sync 'D' and 'F'
unchangedElements: ["C", "D", "F"],
},
});
});
describe("should sync when fractional index is not defined", () => {
testMovedIndicesSync({
elements: [{ id: "A" }],
@@ -384,6 +293,122 @@ describe("sync invalid indices with array order", () => {
});
});
describe("should sync all moved elements regardless of their validity", () => {
testMovedIndicesSync({
elements: [
{ id: "A", index: "a2" },
{ id: "B", index: "a4" },
],
movedElements: ["A"],
expect: {
validInput: true,
unchangedElements: ["B"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A", index: "a2" },
{ id: "B", index: "a4" },
],
movedElements: ["B"],
expect: {
validInput: true,
unchangedElements: ["A"],
},
});
testMovedIndicesSync({
elements: [
{ id: "C", index: "a2" },
{ id: "D", index: "a3" },
{ id: "A", index: "a0" },
{ id: "B", index: "a1" },
],
movedElements: ["C", "D"],
expect: {
unchangedElements: ["A", "B"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A", index: "a1" },
{ id: "B", index: "a2" },
{ id: "D", index: "a4" },
{ id: "C", index: "a3" },
{ id: "F", index: "a6" },
{ id: "E", index: "a5" },
{ id: "H", index: "a8" },
{ id: "G", index: "a7" },
{ id: "I", index: "a9" },
],
movedElements: ["D", "F", "H"],
expect: {
unchangedElements: ["A", "B", "C", "E", "G", "I"],
},
});
{
testMovedIndicesSync({
elements: [
{ id: "A", index: "a1" },
{ id: "B", index: "a0" },
{ id: "C", index: "a2" },
],
movedElements: ["B", "C"],
expect: {
unchangedElements: ["A"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A", index: "a1" },
{ id: "B", index: "a0" },
{ id: "C", index: "a2" },
],
movedElements: ["A", "B"],
expect: {
unchangedElements: ["C"],
},
});
}
testMovedIndicesSync({
elements: [
{ id: "A", index: "a0" },
{ id: "B", index: "a2" },
{ id: "C", index: "a1" },
{ id: "D", index: "a1" },
{ id: "E", index: "a2" },
],
movedElements: ["B", "D", "E"],
expect: {
unchangedElements: ["A", "C"],
},
});
testMovedIndicesSync({
elements: [
{ id: "A" },
{ id: "B" },
{ id: "C", index: "a0" },
{ id: "D", index: "a2" },
{ id: "E" },
{ id: "F", index: "a3" },
{ id: "G" },
{ id: "H", index: "a1" },
{ id: "I", index: "a2" },
{ id: "J" },
],
movedElements: ["A", "B", "D", "E", "F", "G", "J"],
expect: {
unchangedElements: ["C", "H", "I"],
},
});
});
describe("should generate fractions for explicitly moved elements", () => {
describe("should generate a fraction between 'A' and 'C'", () => {
testMovedIndicesSync({

View File

@@ -319,12 +319,12 @@ describe("Test Linear Elements", () => {
expect(midPointsWithRoundEdge).toMatchInlineSnapshot(`
[
[
55.9697848965255,
47.442326230998205,
"55.96978",
"47.44233",
],
[
76.08587175006699,
43.294165939653226,
"76.08587",
"43.29417",
],
]
`);
@@ -381,12 +381,12 @@ describe("Test Linear Elements", () => {
expect(newMidPoints).toMatchInlineSnapshot(`
[
[
105.96978489652551,
67.4423262309982,
"105.96978",
"67.44233",
],
[
126.08587175006699,
63.294165939653226,
"126.08587",
"63.29417",
],
]
`);
@@ -627,16 +627,16 @@ describe("Test Linear Elements", () => {
0,
],
[
85.96978489652551,
77.4423262309982,
"85.96978",
"77.44233",
],
[
70,
50,
],
[
106.08587175006699,
73.29416593965323,
"106.08587",
"73.29417",
],
[
40,
@@ -683,12 +683,12 @@ describe("Test Linear Elements", () => {
expect(newMidPoints).toMatchInlineSnapshot(`
[
[
31.884084517616053,
23.13275505472383,
"31.88408",
"23.13276",
],
[
77.74792546875662,
44.57840982272327,
"77.74793",
"44.57841",
],
]
`);
@@ -769,12 +769,12 @@ describe("Test Linear Elements", () => {
expect(newMidPoints).toMatchInlineSnapshot(`
[
[
55.9697848965255,
47.442326230998205,
"55.96978",
"47.44233",
],
[
76.08587175006699,
43.294165939653226,
"76.08587",
"43.29417",
],
]
`);
@@ -928,8 +928,8 @@ describe("Test Linear Elements", () => {
);
expect(position).toMatchInlineSnapshot(`
{
"x": 85.82201843191861,
"y": 75.63461309860818,
"x": "85.82202",
"y": "75.63461",
}
`);
});
@@ -1068,15 +1068,15 @@ describe("Test Linear Elements", () => {
true,
),
).toMatchInlineSnapshot(`
[
20,
20,
105,
80,
55.45893770831013,
45,
]
`);
[
20,
20,
105,
80,
"55.45894",
45,
]
`);
UI.resize(container, "ne", [300, 200]);
@@ -1084,7 +1084,7 @@ describe("Test Linear Elements", () => {
.toMatchInlineSnapshot(`
{
"height": 130,
"width": 366.11716195150507,
"width": "366.11716",
}
`);
@@ -1095,11 +1095,11 @@ describe("Test Linear Elements", () => {
arrayToMap(h.elements),
),
).toMatchInlineSnapshot(`
{
"x": 271.11716195150507,
"y": 45,
}
`);
{
"x": "271.11716",
"y": 45,
}
`);
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
.toMatchInlineSnapshot(`
"Online whiteboard
@@ -1112,15 +1112,15 @@ describe("Test Linear Elements", () => {
true,
),
).toMatchInlineSnapshot(`
[
20,
35,
501.11716195150507,
95,
205.4589377083102,
52.5,
]
`);
[
20,
35,
"501.11716",
95,
"205.45894",
"52.50000",
]
`);
});
it("should resize and position the bound text correctly when 2 pointer linear element resized", () => {

View File

@@ -242,3 +242,20 @@ expect.extend({
};
},
});
/**
* Serializer for IEE754 float pointing numbers to avoid random failures due to tiny precision differences
*/
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
return printer(val.toFixed(5), config, indentation, depth, refs);
},
test(val) {
return (
typeof val === "number" &&
Number.isFinite(val) &&
!Number.isNaN(val) &&
!Number.isInteger(val)
);
},
});

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB