diff --git a/src/components/footer/FooterCenter.scss b/src/components/footer/FooterCenter.scss
index 1e17db6c5..ce6565922 100644
--- a/src/components/footer/FooterCenter.scss
+++ b/src/components/footer/FooterCenter.scss
@@ -1,10 +1,11 @@
.footer-center {
pointer-events: none;
& > * {
- pointer-events: all;
+ pointer-events: var(--ui-pointerEvents);
}
display: flex;
width: 100%;
justify-content: flex-start;
+ margin-inline-end: 0.6rem;
}
diff --git a/src/components/welcome-screen/WelcomeScreen.scss b/src/components/welcome-screen/WelcomeScreen.scss
index a1b88d8bd..8f1a09bf3 100644
--- a/src/components/welcome-screen/WelcomeScreen.scss
+++ b/src/components/welcome-screen/WelcomeScreen.scss
@@ -161,7 +161,7 @@
.welcome-screen-menu-item {
box-sizing: border-box;
- pointer-events: all;
+ pointer-events: var(--ui-pointerEvents);
color: var(--color-gray-50);
font-size: 0.875rem;
@@ -202,7 +202,7 @@
}
}
- &:not(:active) .welcome-screen-menu-item:hover {
+ .welcome-screen-menu-item:hover {
text-decoration: none;
background: var(--color-gray-10);
@@ -246,7 +246,7 @@
}
}
- &:not(:active) .welcome-screen-menu-item:hover {
+ .welcome-screen-menu-item:hover {
background: var(--color-gray-85);
.welcome-screen-menu-item__shortcut {
diff --git a/src/constants.ts b/src/constants.ts
index 46ae25b40..90fc66758 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -41,6 +41,14 @@ export const POINTER_BUTTON = {
TOUCH: -1,
} as const;
+export const POINTER_EVENTS = {
+ enabled: "all",
+ disabled: "none",
+ // asserted as any so it can be freely assigned to React Element
+ // "pointerEnvets" CSS prop
+ inheritFromUI: "var(--ui-pointerEvents)" as any,
+} as const;
+
export enum EVENT {
COPY = "copy",
PASTE = "paste",
diff --git a/src/css/styles.scss b/src/css/styles.scss
index d46ab1bc2..4ca58af4f 100644
--- a/src/css/styles.scss
+++ b/src/css/styles.scss
@@ -253,7 +253,7 @@
max-height: 100%;
display: flex;
flex-direction: column;
- pointer-events: initial;
+ pointer-events: var(--ui-pointerEvents);
.panelColumn {
padding: 8px 8px 0 8px;
@@ -301,7 +301,7 @@
pointer-events: none !important;
& > * {
- pointer-events: all;
+ pointer-events: var(--ui-pointerEvents);
}
}
@@ -312,16 +312,16 @@
cursor: default;
pointer-events: none !important;
+ & > * {
+ pointer-events: var(--ui-pointerEvents);
+ }
+
@media (min-width: 1536px) {
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 3rem;
}
}
- .layer-ui__wrapper:not(.disable-pointerEvents) .App-menu_top > * {
- pointer-events: all;
- }
-
.App-menu_top > *:first-child {
justify-self: flex-start;
}
@@ -425,17 +425,6 @@
}
}
- .disable-zen-mode {
- border-radius: var(--border-radius-lg);
- background-color: var(--color-gray-20);
- border: 1px solid var(--color-gray-30);
- padding: 10px 20px;
-
- &:hover {
- background-color: var(--color-gray-30);
- }
- }
-
.scroll-back-to-content {
border-radius: var(--border-radius-lg);
background-color: var(--island-bg-color);
@@ -447,7 +436,7 @@
left: 50%;
bottom: 30px;
transform: translateX(-50%);
- pointer-events: all;
+ pointer-events: var(--ui-pointerEvents);
font-family: inherit;
&:hover {
diff --git a/src/element/linearElementEditor.ts b/src/element/linearElementEditor.ts
index f0dee4faa..adc5aafc4 100644
--- a/src/element/linearElementEditor.ts
+++ b/src/element/linearElementEditor.ts
@@ -42,7 +42,7 @@ import {
} from "./binding";
import { tupleToCoors } from "../utils";
import { isBindingElement } from "./typeChecks";
-import { shouldRotateWithDiscreteAngle } from "../keys";
+import { KEYS, shouldRotateWithDiscreteAngle } from "../keys";
import { getBoundTextElement, handleBindTextResize } from "./textElement";
import { DRAGGING_THRESHOLD } from "../constants";
import { Mutable } from "../utility-types";
@@ -221,7 +221,7 @@ export class LinearElementEditor {
element,
referencePoint,
[scenePointerX, scenePointerY],
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
);
LinearElementEditor.movePoints(element, [
@@ -238,7 +238,7 @@ export class LinearElementEditor {
element,
scenePointerX - linearElementEditor.pointerOffset.x,
scenePointerY - linearElementEditor.pointerOffset.y,
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
);
const deltaX = newDraggingPointPosition[0] - draggingPoint[0];
@@ -254,7 +254,7 @@ export class LinearElementEditor {
element,
scenePointerX - linearElementEditor.pointerOffset.x,
scenePointerY - linearElementEditor.pointerOffset.y,
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
)
: ([
element.points[pointIndex][0] + deltaX,
@@ -647,7 +647,7 @@ export class LinearElementEditor {
element,
scenePointer.x,
scenePointer.y,
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
),
],
});
@@ -798,7 +798,7 @@ export class LinearElementEditor {
element,
lastCommittedPoint,
[scenePointerX, scenePointerY],
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
);
newPoint = [
@@ -810,7 +810,7 @@ export class LinearElementEditor {
element,
scenePointerX - appState.editingLinearElement.pointerOffset.x,
scenePointerY - appState.editingLinearElement.pointerOffset.y,
- appState.gridSize,
+ event[KEYS.CTRL_OR_CMD] ? null : appState.gridSize,
);
}
@@ -1176,6 +1176,7 @@ export class LinearElementEditor {
linearElementEditor: LinearElementEditor,
pointerCoords: PointerCoords,
appState: AppState,
+ snapToGrid: boolean,
) {
const element = LinearElementEditor.getElement(
linearElementEditor.elementId,
@@ -1196,7 +1197,7 @@ export class LinearElementEditor {
element,
pointerCoords.x,
pointerCoords.y,
- appState.gridSize,
+ snapToGrid ? appState.gridSize : null,
);
const points = [
...element.points.slice(0, segmentMidpoint.index!),
diff --git a/src/element/newElement.test.ts b/src/element/newElement.test.ts
index ba7c63ee2..19761231b 100644
--- a/src/element/newElement.test.ts
+++ b/src/element/newElement.test.ts
@@ -203,7 +203,6 @@ describe("duplicating multiple elements", () => {
);
clonedArrows.forEach((arrow) => {
- // console.log(arrow);
expect(
clonedRectangle.boundElements!.find((e) => e.id === arrow.id),
).toEqual(
diff --git a/src/element/subtypes/mathjax/tests/implementation.test.tsx b/src/element/subtypes/mathjax/tests/implementation.test.tsx
index 95a827bc2..c895c74ae 100644
--- a/src/element/subtypes/mathjax/tests/implementation.test.tsx
+++ b/src/element/subtypes/mathjax/tests/implementation.test.tsx
@@ -1,13 +1,13 @@
import { render } from "../../../../tests/test-utils";
import { API } from "../../../../tests/helpers/api";
-import ExcalidrawApp from "../../../../excalidraw-app";
+import { Excalidraw } from "../../../../packages/excalidraw/index";
import { measureTextElement } from "../../../textElement";
import { ensureSubtypesLoaded } from "../../";
describe("mathjax", () => {
it("text-only measurements match", async () => {
- await render(
);
+ await render(
);
await ensureSubtypesLoaded(["math"]);
const text = "A quick brown fox jumps over the lazy dog.";
const elements = [
@@ -19,7 +19,7 @@ describe("mathjax", () => {
expect(metrics1).toStrictEqual(metrics2);
});
it("minimum height remains", async () => {
- await render(
);
+ await render(
);
await ensureSubtypesLoaded(["math"]);
const elements = [
API.createElement({ type: "text", id: "A", text: "a" }),
diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx
index c855de357..fc1e8cf2e 100644
--- a/src/element/textWysiwyg.test.tsx
+++ b/src/element/textWysiwyg.test.tsx
@@ -1,5 +1,5 @@
import ReactDOM from "react-dom";
-import ExcalidrawApp from "../excalidraw-app";
+import { Excalidraw } from "../packages/excalidraw/index";
import { GlobalTestState, render, screen } from "../tests/test-utils";
import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
import { CODES, KEYS } from "../keys";
@@ -41,7 +41,7 @@ describe("textWysiwyg", () => {
describe("start text editing", () => {
const { h } = window;
beforeEach(async () => {
- await render(
);
+ await render(
);
h.elements = [];
});
@@ -243,7 +243,7 @@ describe("textWysiwyg", () => {
});
beforeEach(async () => {
- await render(
);
+ await render(
);
//@ts-ignore
h.app.refreshDeviceState(h.app.excalidrawContainerRef.current!);
@@ -477,7 +477,7 @@ describe("textWysiwyg", () => {
const { h } = window;
beforeEach(async () => {
- await render(
);
+ await render(
);
h.elements = [];
rectangle = UI.createElement("rectangle", {
@@ -1511,7 +1511,7 @@ describe("textWysiwyg", () => {
});
it("should bump the version of labelled arrow when label updated", async () => {
- await render(
);
+ await render(
);
const arrow = UI.createElement("arrow", {
width: 300,
height: 0,
diff --git a/src/hooks/useStable.ts b/src/hooks/useStable.ts
new file mode 100644
index 000000000..56608489d
--- /dev/null
+++ b/src/hooks/useStable.ts
@@ -0,0 +1,7 @@
+import { useRef } from "react";
+
+export const useStable =
>(value: T) => {
+ const ref = useRef(value);
+ Object.assign(ref.current, value);
+ return ref.current;
+};
diff --git a/src/index.tsx b/src/index.tsx
index ea8c39cb1..2165ded77 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,9 +1,9 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
-import ExcalidrawApp from "./excalidraw-app";
+import ExcalidrawApp from "../excalidraw-app";
import { registerSW } from "virtual:pwa-register";
-import "./excalidraw-app/sentry";
+import "../excalidraw-app/sentry";
window.__EXCALIDRAW_SHA__ = import.meta.env.VITE_APP_GIT_SHA;
const rootElement = document.getElementById("root")!;
const root = createRoot(rootElement);
diff --git a/src/locales/en.json b/src/locales/en.json
index 938535c5e..6799d0649 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -264,7 +264,8 @@
"bindTextToElement": "Press enter to add text",
"deepBoxSelect": "Hold CtrlOrCmd to deep select, and to prevent dragging",
"eraserRevert": "Hold Alt to revert the elements marked for deletion",
- "firefox_clipboard_write": "This feature can likely be enabled by setting the \"dom.events.asyncClipboard.clipboardItem\" flag to \"true\". To change the browser flags in Firefox, visit the \"about:config\" page."
+ "firefox_clipboard_write": "This feature can likely be enabled by setting the \"dom.events.asyncClipboard.clipboardItem\" flag to \"true\". To change the browser flags in Firefox, visit the \"about:config\" page.",
+ "disableSnapping": "Hold CtrlOrCmd to disable snapping"
},
"canvasError": {
"cannotShowPreview": "Cannot show preview",
diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md
index 7c86eda84..1c151c772 100644
--- a/src/packages/excalidraw/CHANGELOG.md
+++ b/src/packages/excalidraw/CHANGELOG.md
@@ -11,29 +11,11 @@ The change should be grouped under one of the below section and must contain PR
Please add the latest change on the top under the correct section.
-->
-## Unreleased
-
-### renderEmbeddable
-
-```tsx
-(element: NonDeletedExcalidrawElement, radius: number, appState: UIAppState) => JSX.Element | null;`
-```
-
-The renderEmbeddable function allows you to customize the rendering of a JSX component instead of using the default `