Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 4b4de3db1a build(deps): bump braces from 3.0.2 to 3.0.3 in /dev-docs
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-25 16:56:26 +00:00
15 changed files with 89 additions and 182 deletions
+17 -9
View File
@@ -1547,7 +1547,7 @@
"@docusaurus/theme-search-algolia" "2.2.0"
"@docusaurus/types" "2.2.0"
"@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2":
"@docusaurus/react-loadable@5.5.2":
version "5.5.2"
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce"
integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==
@@ -2790,11 +2790,11 @@ brace-expansion@^1.1.7:
concat-map "0.0.1"
braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.0.1"
fill-range "^7.1.1"
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.20.3, browserslist@^4.21.2:
version "4.21.2"
@@ -4004,10 +4004,10 @@ filesize@^8.0.6:
resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
@@ -6260,6 +6260,14 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
dependencies:
"@babel/runtime" "^7.10.3"
"react-loadable@npm:@docusaurus/react-loadable@5.5.2":
version "5.5.2"
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce"
integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==
dependencies:
"@types/react" "*"
prop-types "^15.6.2"
react-router-config@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"
+2 -10
View File
@@ -26,7 +26,6 @@ import {
TTDDialogTrigger,
StoreAction,
reconcileElements,
normalizeIndices,
} from "../packages/excalidraw";
import type {
AppState,
@@ -306,21 +305,14 @@ const initializeScene = async (opts: {
key: roomLinkData.roomKey,
};
} else if (scene) {
const normalizedScene = {
...scene,
// non-collab scenes are always always normalized on init
// collab scenes are normalized only on "first-in-room" as part of collabAPI
elements: normalizeIndices(scene.elements),
};
return isExternalScene && jsonBackendMatch
? {
scene: normalizedScene,
scene,
isExternalScene,
id: jsonBackendMatch[1],
key: jsonBackendMatch[2],
}
: { scene: normalizedScene, isExternalScene: false };
: { scene, isExternalScene: false };
}
return { scene: null, isExternalScene: false };
};
+1 -11
View File
@@ -18,7 +18,6 @@ import {
restoreElements,
zoomToFitBounds,
reconcileElements,
normalizeIndices,
} from "../../packages/excalidraw";
import type { Collaborator, Gesture } from "../../packages/excalidraw/types";
import {
@@ -638,16 +637,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
fetchScene: true,
roomLinkData: existingRoomLinkData,
});
if (sceneData) {
scenePromise.resolve({
...sceneData,
// normalize fractional indices on init for shared scenes, while making sure there are no other collaborators
elements: normalizeIndices([...sceneData.elements]),
});
} else {
scenePromise.resolve(null);
}
scenePromise.resolve(sceneData);
});
this.portal.socket.on(
+1 -1
View File
@@ -254,7 +254,7 @@ export const loadScene = async (
await importFromBackend(id, privateKey),
localDataState?.appState,
localDataState?.elements,
{ repairBindings: true },
{ repairBindings: true, refreshDimensions: false },
);
} else {
data = restore(localDataState || null, null, null, {
+34 -2
View File
@@ -224,7 +224,8 @@ import type {
ScrollBars,
} from "../scene/types";
import { getStateForZoom } from "../scene/zoom";
import { findShapeByKey, getBoundTextShape, getElementShape } from "../shapes";
import { findShapeByKey, getElementShape } from "../shapes";
import type { GeometricShape } from "../../utils/geometry/shape";
import { getSelectionBoxShape } from "../../utils/geometry/shape";
import { isPointInShape } from "../../utils/collision";
import type {
@@ -4514,6 +4515,37 @@ class App extends React.Component<AppProps, AppState> {
return null;
}
private getBoundTextShape(element: ExcalidrawElement): GeometricShape | null {
const boundTextElement = getBoundTextElement(
element,
this.scene.getNonDeletedElementsMap(),
);
if (boundTextElement) {
if (element.type === "arrow") {
return getElementShape(
{
...boundTextElement,
// arrow's bound text accurate position is not stored in the element's property
// but rather calculated and returned from the following static method
...LinearElementEditor.getBoundTextElementPosition(
element,
boundTextElement,
this.scene.getNonDeletedElementsMap(),
),
},
this.scene.getNonDeletedElementsMap(),
);
}
return getElementShape(
boundTextElement,
this.scene.getNonDeletedElementsMap(),
);
}
return null;
}
private getElementAtPosition(
x: number,
y: number,
@@ -4645,7 +4677,7 @@ class App extends React.Component<AppProps, AppState> {
const hitBoundTextOfElement = hitElementBoundText(
x,
y,
getBoundTextShape(element, this.scene.getNonDeletedElementsMap()),
this.getBoundTextShape(element),
);
if (hitBoundTextOfElement) {
return true;
+1 -5
View File
@@ -154,11 +154,7 @@ export const loadSceneOrLibraryFromBlob = async (
},
localAppState,
localElements,
{
repairBindings: true,
normalizeIndices: true,
refreshDimensions: false,
},
{ repairBindings: true, refreshDimensions: false },
),
};
} else if (isValidLibrary(data)) {
+26 -35
View File
@@ -46,9 +46,9 @@ import { arrayToMap } from "../utils";
import type { MarkOptional, Mutable } from "../utility-types";
import { detectLineHeight, getContainerElement } from "../element/textElement";
import { normalizeLink } from "./url";
import { syncInvalidIndices } from "../fractionalIndex";
import { getSizeFromPoints } from "../points";
import { getLineHeight } from "../fonts";
import { normalizeIndices, syncInvalidIndices } from "../fractionalIndex";
type RestoredAppState = Omit<
AppState,
@@ -405,41 +405,36 @@ export const restoreElements = (
elements: ImportedDataState["elements"],
/** NOTE doesn't serve for reconciliation */
localElements: readonly ExcalidrawElement[] | null | undefined,
opts?:
| {
refreshDimensions?: boolean;
repairBindings?: boolean;
normalizeIndices?: boolean;
}
| undefined,
opts?: { refreshDimensions?: boolean; repairBindings?: boolean } | undefined,
): OrderedExcalidrawElement[] => {
// used to detect duplicate top-level element ids
const existingIds = new Set<string>();
const localElementsMap = localElements ? arrayToMap(localElements) : null;
const restoredElementsTemp = (elements || []).reduce((elements, element) => {
// filtering out selection, which is legacy, no longer kept in elements,
// and causing issues if retained
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
let migratedElement: ExcalidrawElement | null = restoreElement(element);
if (migratedElement) {
const localElement = localElementsMap?.get(element.id);
if (localElement && localElement.version > migratedElement.version) {
migratedElement = bumpVersion(migratedElement, localElement.version);
}
if (existingIds.has(migratedElement.id)) {
migratedElement = { ...migratedElement, id: randomId() };
}
existingIds.add(migratedElement.id);
const restoredElements = syncInvalidIndices(
(elements || []).reduce((elements, element) => {
// filtering out selection, which is legacy, no longer kept in elements,
// and causing issues if retained
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
let migratedElement: ExcalidrawElement | null = restoreElement(element);
if (migratedElement) {
const localElement = localElementsMap?.get(element.id);
if (localElement && localElement.version > migratedElement.version) {
migratedElement = bumpVersion(
migratedElement,
localElement.version,
);
}
if (existingIds.has(migratedElement.id)) {
migratedElement = { ...migratedElement, id: randomId() };
}
existingIds.add(migratedElement.id);
elements.push(migratedElement);
elements.push(migratedElement);
}
}
}
return elements;
}, [] as ExcalidrawElement[]);
const restoredElements = opts?.normalizeIndices
? normalizeIndices(restoredElementsTemp)
: syncInvalidIndices(restoredElementsTemp);
return elements;
}, [] as ExcalidrawElement[]),
);
if (!opts?.repairBindings) {
return restoredElements;
@@ -606,11 +601,7 @@ export const restore = (
*/
localAppState: Partial<AppState> | null | undefined,
localElements: readonly ExcalidrawElement[] | null | undefined,
elementsConfig?: {
refreshDimensions?: boolean;
repairBindings?: boolean;
normalizeIndices?: boolean;
},
elementsConfig?: { refreshDimensions?: boolean; repairBindings?: boolean },
): RestoredDataState => {
return {
elements: restoreElements(data?.elements, localElements, elementsConfig),
+2 -9
View File
@@ -18,7 +18,6 @@ import {
isImageElement,
isTextElement,
} from "./typeChecks";
import { getBoundTextShape } from "../shapes";
export const shouldTestInside = (element: ExcalidrawElement) => {
if (element.type === "arrow") {
@@ -98,12 +97,6 @@ export const hitElementBoundingBoxOnly = (
) => {
return (
!hitElementItself(hitArgs) &&
// bound text is considered part of the element (even if it's outside the bounding box)
!hitElementBoundText(
hitArgs.x,
hitArgs.y,
getBoundTextShape(hitArgs.element, elementsMap),
) &&
hitElementBoundingBox(hitArgs.x, hitArgs.y, hitArgs.element, elementsMap)
);
};
@@ -112,6 +105,6 @@ export const hitElementBoundText = (
x: number,
y: number,
textShape: GeometricShape | null,
): boolean => {
return !!textShape && isPointInShape([x, y], textShape);
) => {
return textShape && isPointInShape([x, y], textShape);
};
+2 -1
View File
@@ -635,7 +635,8 @@ export const getMaxCharWidth = (font: FontString) => {
export const getBoundTextElementId = (container: ExcalidrawElement | null) => {
return container?.boundElements?.length
? container?.boundElements?.find((ele) => ele.type === "text")?.id || null
? container?.boundElements?.filter((ele) => ele.type === "text")[0]?.id ||
null
: null;
};
-8
View File
@@ -6,14 +6,6 @@ import type {
OrderedExcalidrawElement,
} from "./element/types";
import { InvalidFractionalIndexError } from "./errors";
import { arrayToMap } from "./utils";
/**
* Normalizes indices for all elements, to prevent possible issues caused by using stale (too old, too long) indices.
*/
export const normalizeIndices = (elements: ExcalidrawElement[]) => {
return syncMovedIndices(elements, arrayToMap(elements));
};
/**
* Envisioned relation between array order and fractional indices:
-2
View File
@@ -222,8 +222,6 @@ export {
restoreLibraryItems,
} from "./data/restore";
export { normalizeIndices } from "./fractionalIndex";
export { reconcileElements } from "./data/reconcile";
export {
-15
View File
@@ -1,15 +0,0 @@
import { isMaybeMermaidDefinition } from "./mermaid";
describe("isMaybeMermaidDefinition", () => {
it("should return true for a valid mermaid definition", () => {
expect(isMaybeMermaidDefinition("flowchart")).toBe(true);
expect(isMaybeMermaidDefinition("flowchart LR")).toBe(true);
expect(isMaybeMermaidDefinition("flowchart LR\nola")).toBe(true);
expect(isMaybeMermaidDefinition("%%{}%%flowchart")).toBe(true);
expect(isMaybeMermaidDefinition("%%{}%% flowchart")).toBe(true);
expect(isMaybeMermaidDefinition("graphs")).toBe(false);
expect(isMaybeMermaidDefinition("this flowchart")).toBe(false);
expect(isMaybeMermaidDefinition("this\nflowchart")).toBe(false);
});
});
+3 -4
View File
@@ -2,7 +2,6 @@
export const isMaybeMermaidDefinition = (text: string) => {
const chartTypes = [
"flowchart",
"graph",
"sequenceDiagram",
"classDiagram",
"stateDiagram",
@@ -24,9 +23,9 @@ export const isMaybeMermaidDefinition = (text: string) => {
];
const re = new RegExp(
`^(?:%%{.*?}%%[\\s\\n]*)?\\b(?:${chartTypes
.map((x) => `\\s*${x}(-beta)?`)
.join("|")})\\b`,
`^(?:%%{.*?}%%[\\s\\n]*)?\\b${chartTypes
.map((x) => `${x}(-beta)?`)
.join("|")}\\b`,
);
return re.test(text.trim());
-30
View File
@@ -20,8 +20,6 @@ import {
} from "./components/icons";
import { getElementAbsoluteCoords } from "./element";
import { shouldTestInside } from "./element/collision";
import { LinearElementEditor } from "./element/linearElementEditor";
import { getBoundTextElement } from "./element/textElement";
import type { ElementsMap, ExcalidrawElement } from "./element/types";
import { KEYS } from "./keys";
import { ShapeCache } from "./scene/ShapeCache";
@@ -161,31 +159,3 @@ export const getElementShape = (
}
}
};
export const getBoundTextShape = (
element: ExcalidrawElement,
elementsMap: ElementsMap,
): GeometricShape | null => {
const boundTextElement = getBoundTextElement(element, elementsMap);
if (boundTextElement) {
if (element.type === "arrow") {
return getElementShape(
{
...boundTextElement,
// arrow's bound text accurate position is not stored in the element's property
// but rather calculated and returned from the following static method
...LinearElementEditor.getBoundTextElementPosition(
element,
boundTextElement,
elementsMap,
),
},
elementsMap,
);
}
return getElementShape(boundTextElement, elementsMap);
}
return null;
};
@@ -4,7 +4,6 @@ import type {
ExcalidrawFreeDrawElement,
ExcalidrawLinearElement,
ExcalidrawTextElement,
FractionalIndex,
} from "../../element/types";
import * as sizeHelpers from "../../element/sizeHelpers";
import { API } from "../helpers/api";
@@ -580,45 +579,6 @@ describe("restore", () => {
});
});
describe("normalize indices", () => {
it("shoudl normalize indices of all elements when normalize is true", () => {
const ellipse = API.createElement({
type: "ellipse",
index: "Zz" as FractionalIndex,
});
const container = API.createElement({
type: "rectangle",
index: undefined,
});
const boundElement = API.createElement({
type: "text",
containerId: container.id,
index: "a0000000000000000000000" as FractionalIndex,
});
const restoredElements = restore.restoreElements(
[ellipse, container, boundElement],
null,
{ normalizeIndices: true },
);
expect(restoredElements).toEqual([
expect.objectContaining({
id: ellipse.id,
index: "a0",
}),
expect.objectContaining({
id: container.id,
index: "a1",
}),
expect.objectContaining({
id: boundElement.id,
index: "a2",
}),
]);
});
});
describe("repairing bindings", () => {
it("should repair container boundElements when repair is true", () => {
const container = API.createElement({