|
@@ -374,6 +374,7 @@ import {
|
|
|
resetCursor,
|
|
|
setCursorForShape,
|
|
|
} from "../cursor";
|
|
|
+import { Emitter } from "../emitter";
|
|
|
|
|
|
const AppContext = React.createContext<AppClassProperties>(null!);
|
|
|
const AppPropsContext = React.createContext<AppProps>(null!);
|
|
@@ -505,6 +506,30 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
laserPathManager: LaserPathManager = new LaserPathManager(this);
|
|
|
|
|
|
+ onChangeEmitter = new Emitter<
|
|
|
+ [
|
|
|
+ elements: readonly ExcalidrawElement[],
|
|
|
+ appState: AppState,
|
|
|
+ files: BinaryFiles,
|
|
|
+ ]
|
|
|
+ >();
|
|
|
+
|
|
|
+ onPointerDownEmitter = new Emitter<
|
|
|
+ [
|
|
|
+ activeTool: AppState["activeTool"],
|
|
|
+ pointerDownState: PointerDownState,
|
|
|
+ event: React.PointerEvent<HTMLElement>,
|
|
|
+ ]
|
|
|
+ >();
|
|
|
+
|
|
|
+ onPointerUpEmitter = new Emitter<
|
|
|
+ [
|
|
|
+ activeTool: AppState["activeTool"],
|
|
|
+ pointerDownState: PointerDownState,
|
|
|
+ event: PointerEvent,
|
|
|
+ ]
|
|
|
+ >();
|
|
|
+
|
|
|
constructor(props: AppProps) {
|
|
|
super(props);
|
|
|
const defaultAppState = getDefaultAppState();
|
|
@@ -568,6 +593,9 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
resetCursor: this.resetCursor,
|
|
|
updateFrameRendering: this.updateFrameRendering,
|
|
|
toggleSidebar: this.toggleSidebar,
|
|
|
+ onChange: (cb) => this.onChangeEmitter.on(cb),
|
|
|
+ onPointerDown: (cb) => this.onPointerDownEmitter.on(cb),
|
|
|
+ onPointerUp: (cb) => this.onPointerUpEmitter.on(cb),
|
|
|
} as const;
|
|
|
if (typeof excalidrawRef === "function") {
|
|
|
excalidrawRef(api);
|
|
@@ -1750,6 +1778,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.scene.destroy();
|
|
|
this.library.destroy();
|
|
|
this.laserPathManager.destroy();
|
|
|
+ this.onChangeEmitter.destroy();
|
|
|
ShapeCache.destroy();
|
|
|
SnapCache.destroy();
|
|
|
clearTimeout(touchTimeout);
|
|
@@ -2034,6 +2063,11 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.state,
|
|
|
this.files,
|
|
|
);
|
|
|
+ this.onChangeEmitter.trigger(
|
|
|
+ this.scene.getElementsIncludingDeleted(),
|
|
|
+ this.state,
|
|
|
+ this.files,
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -4699,6 +4733,11 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
}
|
|
|
|
|
|
this.props?.onPointerDown?.(this.state.activeTool, pointerDownState);
|
|
|
+ this.onPointerDownEmitter.trigger(
|
|
|
+ this.state.activeTool,
|
|
|
+ pointerDownState,
|
|
|
+ event,
|
|
|
+ );
|
|
|
|
|
|
const onPointerMove =
|
|
|
this.onPointerMoveFromPointerDownHandler(pointerDownState);
|
|
@@ -6551,6 +6590,12 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.setState({ pendingImageElementId: null });
|
|
|
}
|
|
|
|
|
|
+ this.onPointerUpEmitter.trigger(
|
|
|
+ this.state.activeTool,
|
|
|
+ pointerDownState,
|
|
|
+ childEvent,
|
|
|
+ );
|
|
|
+
|
|
|
if (draggingElement?.type === "freedraw") {
|
|
|
const pointerCoords = viewportCoordsToSceneCoords(
|
|
|
childEvent,
|