docs: migrate example to typescript (#5243)
* docs: migrate example to typescript * fix * fix sidebar * fix
This commit is contained in:
parent
5daff2d3cd
commit
6196fba286
@ -1,12 +1,13 @@
|
|||||||
import { useEffect, useState, useRef, useCallback } from "react";
|
import { useEffect, useState, useRef, useCallback } from "react";
|
||||||
|
|
||||||
import InitialData from "./initialData";
|
|
||||||
import Sidebar from "./sidebar/Sidebar";
|
import Sidebar from "./sidebar/Sidebar";
|
||||||
|
|
||||||
import "./App.scss";
|
import "./App.scss";
|
||||||
import initialData from "./initialData";
|
import initialData from "./initialData";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import {
|
import {
|
||||||
|
resolvablePromise,
|
||||||
|
ResolvablePromise,
|
||||||
withBatchedUpdates,
|
withBatchedUpdates,
|
||||||
withBatchedUpdatesThrottled,
|
withBatchedUpdatesThrottled,
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
@ -14,7 +15,42 @@ import { EVENT } from "../../../constants";
|
|||||||
import { distance2d } from "../../../math";
|
import { distance2d } from "../../../math";
|
||||||
import { fileOpen } from "../../../data/filesystem";
|
import { fileOpen } from "../../../data/filesystem";
|
||||||
import { loadSceneOrLibraryFromBlob } from "../../utils";
|
import { loadSceneOrLibraryFromBlob } from "../../utils";
|
||||||
|
import {
|
||||||
|
AppState,
|
||||||
|
BinaryFileData,
|
||||||
|
ExcalidrawImperativeAPI,
|
||||||
|
ExcalidrawInitialDataState,
|
||||||
|
Gesture,
|
||||||
|
LibraryItems,
|
||||||
|
PointerDownState as ExcalidrawPointerDownState,
|
||||||
|
} from "../../../types";
|
||||||
|
import { ExcalidrawElement } from "../../../element/types";
|
||||||
|
import { ImportedLibraryData } from "../../../data/types";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
ExcalidrawLib: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Comment = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
value: string;
|
||||||
|
id?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PointerDownState = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
hitElement: Comment;
|
||||||
|
onMove: any;
|
||||||
|
onUp: any;
|
||||||
|
hitElementOffsets: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
// This is so that we use the bundled excalidraw.development.js file instead
|
// This is so that we use the bundled excalidraw.development.js file instead
|
||||||
// of the actual source code
|
// of the actual source code
|
||||||
|
|
||||||
@ -28,6 +64,7 @@ const {
|
|||||||
MIME_TYPES,
|
MIME_TYPES,
|
||||||
sceneCoordsToViewportCoords,
|
sceneCoordsToViewportCoords,
|
||||||
viewportCoordsToSceneCoords,
|
viewportCoordsToSceneCoords,
|
||||||
|
restoreElements,
|
||||||
} = window.ExcalidrawLib;
|
} = window.ExcalidrawLib;
|
||||||
|
|
||||||
const COMMENT_SVG = (
|
const COMMENT_SVG = (
|
||||||
@ -41,7 +78,7 @@ const COMMENT_SVG = (
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
class="feather feather-message-circle"
|
className="feather feather-message-circle"
|
||||||
>
|
>
|
||||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
@ -50,18 +87,6 @@ const COMMENT_ICON_DIMENSION = 32;
|
|||||||
const COMMENT_INPUT_HEIGHT = 50;
|
const COMMENT_INPUT_HEIGHT = 50;
|
||||||
const COMMENT_INPUT_WIDTH = 150;
|
const COMMENT_INPUT_WIDTH = 150;
|
||||||
|
|
||||||
const resolvablePromise = () => {
|
|
||||||
let resolve;
|
|
||||||
let reject;
|
|
||||||
const promise = new Promise((_resolve, _reject) => {
|
|
||||||
resolve = _resolve;
|
|
||||||
reject = _reject;
|
|
||||||
});
|
|
||||||
promise.resolve = resolve;
|
|
||||||
promise.reject = reject;
|
|
||||||
return promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTopRightUI = () => {
|
const renderTopRightUI = () => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@ -75,25 +100,31 @@ const renderTopRightUI = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const appRef = useRef(null);
|
const appRef = useRef<any>(null);
|
||||||
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
||||||
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
||||||
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
||||||
const [blobUrl, setBlobUrl] = useState(null);
|
const [blobUrl, setBlobUrl] = useState<string>("");
|
||||||
const [canvasUrl, setCanvasUrl] = useState(null);
|
const [canvasUrl, setCanvasUrl] = useState<string>("");
|
||||||
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
||||||
const [exportEmbedScene, setExportEmbedScene] = useState(false);
|
const [exportEmbedScene, setExportEmbedScene] = useState(false);
|
||||||
const [theme, setTheme] = useState("light");
|
const [theme, setTheme] = useState("light");
|
||||||
const [isCollaborating, setIsCollaborating] = useState(false);
|
const [isCollaborating, setIsCollaborating] = useState(false);
|
||||||
const [commentIcons, setCommentIcons] = useState({});
|
const [commentIcons, setCommentIcons] = useState<{ [id: string]: Comment }>(
|
||||||
const [comment, setComment] = useState(null);
|
{},
|
||||||
|
);
|
||||||
|
const [comment, setComment] = useState<Comment | null>(null);
|
||||||
|
|
||||||
const initialStatePromiseRef = useRef({ promise: null });
|
const initialStatePromiseRef = useRef<{
|
||||||
|
promise: ResolvablePromise<ExcalidrawInitialDataState | null>;
|
||||||
|
}>({ promise: null! });
|
||||||
if (!initialStatePromiseRef.current.promise) {
|
if (!initialStatePromiseRef.current.promise) {
|
||||||
initialStatePromiseRef.current.promise = resolvablePromise();
|
initialStatePromiseRef.current.promise =
|
||||||
|
resolvablePromise<ExcalidrawInitialDataState | null>();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [excalidrawAPI, setExcalidrawAPI] = useState(null);
|
const [excalidrawAPI, setExcalidrawAPI] =
|
||||||
|
useState<ExcalidrawImperativeAPI | null>(null);
|
||||||
|
|
||||||
useHandleLibrary({ excalidrawAPI });
|
useHandleLibrary({ excalidrawAPI });
|
||||||
|
|
||||||
@ -108,16 +139,17 @@ export default function App() {
|
|||||||
reader.readAsDataURL(imageData);
|
reader.readAsDataURL(imageData);
|
||||||
|
|
||||||
reader.onload = function () {
|
reader.onload = function () {
|
||||||
const imagesArray = [
|
const imagesArray: BinaryFileData[] = [
|
||||||
{
|
{
|
||||||
id: "rocket",
|
id: "rocket" as BinaryFileData["id"],
|
||||||
dataURL: reader.result,
|
dataURL: reader.result as BinaryFileData["dataURL"],
|
||||||
mimeType: MIME_TYPES.jpg,
|
mimeType: MIME_TYPES.jpg,
|
||||||
created: 1644915140367,
|
created: 1644915140367,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
initialStatePromiseRef.current.promise.resolve(InitialData);
|
//@ts-ignore
|
||||||
|
initialStatePromiseRef.current.promise.resolve(initialData);
|
||||||
excalidrawAPI.addFiles(imagesArray);
|
excalidrawAPI.addFiles(imagesArray);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -131,7 +163,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
className="custom-element"
|
className="custom-element"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
excalidrawAPI.setActiveTool({
|
excalidrawAPI?.setActiveTool({
|
||||||
type: "custom",
|
type: "custom",
|
||||||
customType: "comment",
|
customType: "comment",
|
||||||
});
|
});
|
||||||
@ -151,7 +183,7 @@ export default function App() {
|
|||||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||||
</svg>`,
|
</svg>`,
|
||||||
)}`;
|
)}`;
|
||||||
excalidrawAPI.setCursor(`url(${url}), auto`);
|
excalidrawAPI?.setCursor(`url(${url}), auto`);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{COMMENT_SVG}
|
{COMMENT_SVG}
|
||||||
@ -168,10 +200,10 @@ export default function App() {
|
|||||||
const file = await fileOpen({ description: "Excalidraw or library file" });
|
const file = await fileOpen({ description: "Excalidraw or library file" });
|
||||||
const contents = await loadSceneOrLibraryFromBlob(file, null, null);
|
const contents = await loadSceneOrLibraryFromBlob(file, null, null);
|
||||||
if (contents.type === MIME_TYPES.excalidraw) {
|
if (contents.type === MIME_TYPES.excalidraw) {
|
||||||
excalidrawAPI.updateScene(contents.data);
|
excalidrawAPI?.updateScene(contents.data as any);
|
||||||
} else if (contents.type === MIME_TYPES.excalidrawlib) {
|
} else if (contents.type === MIME_TYPES.excalidrawlib) {
|
||||||
excalidrawAPI.updateLibrary({
|
excalidrawAPI?.updateLibrary({
|
||||||
libraryItems: contents.data.libraryItems,
|
libraryItems: (contents.data as ImportedLibraryData).libraryItems!,
|
||||||
openLibraryMenu: true,
|
openLibraryMenu: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -179,34 +211,42 @@ export default function App() {
|
|||||||
|
|
||||||
const updateScene = () => {
|
const updateScene = () => {
|
||||||
const sceneData = {
|
const sceneData = {
|
||||||
elements: [
|
elements: restoreElements(
|
||||||
{
|
[
|
||||||
type: "rectangle",
|
{
|
||||||
version: 141,
|
type: "rectangle",
|
||||||
versionNonce: 361174001,
|
version: 141,
|
||||||
isDeleted: false,
|
versionNonce: 361174001,
|
||||||
id: "oDVXy8D6rom3H1-LLH2-f",
|
isDeleted: false,
|
||||||
fillStyle: "hachure",
|
id: "oDVXy8D6rom3H1-LLH2-f",
|
||||||
strokeWidth: 1,
|
fillStyle: "hachure",
|
||||||
strokeStyle: "solid",
|
strokeWidth: 1,
|
||||||
roughness: 1,
|
strokeStyle: "solid",
|
||||||
opacity: 100,
|
roughness: 1,
|
||||||
angle: 0,
|
opacity: 100,
|
||||||
x: 100.50390625,
|
angle: 0,
|
||||||
y: 93.67578125,
|
x: 100.50390625,
|
||||||
strokeColor: "#c92a2a",
|
y: 93.67578125,
|
||||||
backgroundColor: "transparent",
|
strokeColor: "#c92a2a",
|
||||||
width: 186.47265625,
|
backgroundColor: "transparent",
|
||||||
height: 141.9765625,
|
width: 186.47265625,
|
||||||
seed: 1968410350,
|
height: 141.9765625,
|
||||||
groupIds: [],
|
seed: 1968410350,
|
||||||
},
|
groupIds: [],
|
||||||
],
|
boundElements: null,
|
||||||
|
locked: false,
|
||||||
|
link: null,
|
||||||
|
updated: 1,
|
||||||
|
strokeSharpness: "round",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
),
|
||||||
appState: {
|
appState: {
|
||||||
viewBackgroundColor: "#edf2ff",
|
viewBackgroundColor: "#edf2ff",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
excalidrawAPI.updateScene(sceneData);
|
excalidrawAPI?.updateScene(sceneData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLinkOpen = useCallback((element, event) => {
|
const onLinkOpen = useCallback((element, event) => {
|
||||||
@ -224,19 +264,26 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onCopy = async (type) => {
|
const onCopy = async (type: string) => {
|
||||||
await exportToClipboard({
|
await exportToClipboard({
|
||||||
elements: excalidrawAPI.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
appState: excalidrawAPI.getAppState(),
|
appState: excalidrawAPI?.getAppState(),
|
||||||
files: excalidrawAPI.getFiles(),
|
files: excalidrawAPI?.getFiles(),
|
||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
window.alert(`Copied to clipboard as ${type} sucessfully`);
|
window.alert(`Copied to clipboard as ${type} sucessfully`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [pointerData, setPointerData] = useState(null);
|
const [pointerData, setPointerData] = useState<{
|
||||||
|
pointer: { x: number; y: number };
|
||||||
|
button: "down" | "up";
|
||||||
|
pointersMap: Gesture["pointers"];
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const onPointerDown = (activeTool, pointerDownState) => {
|
const onPointerDown = (
|
||||||
|
activeTool: AppState["activeTool"],
|
||||||
|
pointerDownState: ExcalidrawPointerDownState,
|
||||||
|
) => {
|
||||||
if (activeTool.type === "custom" && activeTool.customType === "comment") {
|
if (activeTool.type === "custom" && activeTool.customType === "comment") {
|
||||||
const { x, y } = pointerDownState.origin;
|
const { x, y } = pointerDownState.origin;
|
||||||
setComment({ x, y, value: "" });
|
setComment({ x, y, value: "" });
|
||||||
@ -244,48 +291,53 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const rerenderCommentIcons = () => {
|
const rerenderCommentIcons = () => {
|
||||||
const commentIconsElements =
|
const commentIconsElements = appRef.current.querySelectorAll(
|
||||||
appRef.current.querySelectorAll(".comment-icon");
|
".comment-icon",
|
||||||
|
) as HTMLElement[];
|
||||||
commentIconsElements.forEach((ele) => {
|
commentIconsElements.forEach((ele) => {
|
||||||
const id = ele.id;
|
const id = ele.id;
|
||||||
const appstate = excalidrawAPI.getAppState();
|
const appstate = excalidrawAPI?.getAppState();
|
||||||
const { x, y } = sceneCoordsToViewportCoords(
|
const { x, y } = sceneCoordsToViewportCoords(
|
||||||
{ sceneX: commentIcons[id].x, sceneY: commentIcons[id].y },
|
{ sceneX: commentIcons[id].x, sceneY: commentIcons[id].y },
|
||||||
appstate,
|
appstate,
|
||||||
);
|
);
|
||||||
ele.style.left = `${
|
ele.style.left = `${
|
||||||
x - COMMENT_ICON_DIMENSION / 2 - appstate.offsetLeft
|
x - COMMENT_ICON_DIMENSION / 2 - appstate!.offsetLeft
|
||||||
}px`;
|
}px`;
|
||||||
ele.style.top = `${
|
ele.style.top = `${
|
||||||
y - COMMENT_ICON_DIMENSION / 2 - appstate.offsetTop
|
y - COMMENT_ICON_DIMENSION / 2 - appstate!.offsetTop
|
||||||
}px`;
|
}px`;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerMoveFromPointerDownHandler = (pointerDownState) => {
|
const onPointerMoveFromPointerDownHandler = (
|
||||||
|
pointerDownState: PointerDownState,
|
||||||
|
) => {
|
||||||
return withBatchedUpdatesThrottled((event) => {
|
return withBatchedUpdatesThrottled((event) => {
|
||||||
const { x, y } = viewportCoordsToSceneCoords(
|
const { x, y } = viewportCoordsToSceneCoords(
|
||||||
{
|
{
|
||||||
clientX: event.clientX - pointerDownState.hitElementOffsets.x,
|
clientX: event.clientX - pointerDownState.hitElementOffsets.x,
|
||||||
clientY: event.clientY - pointerDownState.hitElementOffsets.y,
|
clientY: event.clientY - pointerDownState.hitElementOffsets.y,
|
||||||
},
|
},
|
||||||
excalidrawAPI.getAppState(),
|
excalidrawAPI?.getAppState(),
|
||||||
);
|
);
|
||||||
setCommentIcons({
|
setCommentIcons({
|
||||||
...commentIcons,
|
...commentIcons,
|
||||||
[pointerDownState.hitElement.id]: {
|
[pointerDownState.hitElement.id!]: {
|
||||||
...commentIcons[pointerDownState.hitElement.id],
|
...commentIcons[pointerDownState.hitElement.id!],
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const onPointerUpFromPointerDownHandler = (pointerDownState) => {
|
const onPointerUpFromPointerDownHandler = (
|
||||||
|
pointerDownState: PointerDownState,
|
||||||
|
) => {
|
||||||
return withBatchedUpdates((event) => {
|
return withBatchedUpdates((event) => {
|
||||||
window.removeEventListener(EVENT.POINTER_MOVE, pointerDownState.onMove);
|
window.removeEventListener(EVENT.POINTER_MOVE, pointerDownState.onMove);
|
||||||
window.removeEventListener(EVENT.POINTER_UP, pointerDownState.onUp);
|
window.removeEventListener(EVENT.POINTER_UP, pointerDownState.onUp);
|
||||||
excalidrawAPI.setActiveTool({ type: "selection" });
|
excalidrawAPI?.setActiveTool({ type: "selection" });
|
||||||
const distance = distance2d(
|
const distance = distance2d(
|
||||||
pointerDownState.x,
|
pointerDownState.x,
|
||||||
pointerDownState.y,
|
pointerDownState.y,
|
||||||
@ -308,18 +360,18 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
const renderCommentIcons = () => {
|
const renderCommentIcons = () => {
|
||||||
return Object.values(commentIcons).map((commentIcon) => {
|
return Object.values(commentIcons).map((commentIcon) => {
|
||||||
const appState = excalidrawAPI.getAppState();
|
const appState = excalidrawAPI?.getAppState();
|
||||||
const { x, y } = sceneCoordsToViewportCoords(
|
const { x, y } = sceneCoordsToViewportCoords(
|
||||||
{ sceneX: commentIcon.x, sceneY: commentIcon.y },
|
{ sceneX: commentIcon.x, sceneY: commentIcon.y },
|
||||||
excalidrawAPI.getAppState(),
|
excalidrawAPI?.getAppState(),
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id={commentIcon.id}
|
id={commentIcon.id}
|
||||||
key={commentIcon.id}
|
key={commentIcon.id}
|
||||||
style={{
|
style={{
|
||||||
top: `${y - COMMENT_ICON_DIMENSION / 2 - appState.offsetTop}px`,
|
top: `${y - COMMENT_ICON_DIMENSION / 2 - appState!.offsetTop}px`,
|
||||||
left: `${x - COMMENT_ICON_DIMENSION / 2 - appState.offsetLeft}px`,
|
left: `${x - COMMENT_ICON_DIMENSION / 2 - appState!.offsetLeft}px`,
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
width: `${COMMENT_ICON_DIMENSION}px`,
|
width: `${COMMENT_ICON_DIMENSION}px`,
|
||||||
@ -334,7 +386,7 @@ export default function App() {
|
|||||||
commentIcon.value = comment.value;
|
commentIcon.value = comment.value;
|
||||||
saveComment();
|
saveComment();
|
||||||
}
|
}
|
||||||
const pointerDownState = {
|
const pointerDownState: any = {
|
||||||
x: event.clientX,
|
x: event.clientX,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
hitElement: commentIcon,
|
hitElement: commentIcon,
|
||||||
@ -350,7 +402,7 @@ export default function App() {
|
|||||||
pointerDownState.onMove = onPointerMove;
|
pointerDownState.onMove = onPointerMove;
|
||||||
pointerDownState.onUp = onPointerUp;
|
pointerDownState.onUp = onPointerUp;
|
||||||
|
|
||||||
excalidrawAPI.setActiveTool({
|
excalidrawAPI?.setActiveTool({
|
||||||
type: "custom",
|
type: "custom",
|
||||||
customType: "comment",
|
customType: "comment",
|
||||||
});
|
});
|
||||||
@ -365,6 +417,9 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveComment = () => {
|
const saveComment = () => {
|
||||||
|
if (!comment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!comment.id && !comment.value) {
|
if (!comment.id && !comment.value) {
|
||||||
setComment(null);
|
setComment(null);
|
||||||
return;
|
return;
|
||||||
@ -383,7 +438,10 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderComment = () => {
|
const renderComment = () => {
|
||||||
const appState = excalidrawAPI.getAppState();
|
if (!comment) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const appState = excalidrawAPI?.getAppState()!;
|
||||||
const { x, y } = sceneCoordsToViewportCoords(
|
const { x, y } = sceneCoordsToViewportCoords(
|
||||||
{ sceneX: comment.x, sceneY: comment.y },
|
{ sceneX: comment.x, sceneY: comment.y },
|
||||||
appState,
|
appState,
|
||||||
@ -450,24 +508,29 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
className="reset-scene"
|
className="reset-scene"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
excalidrawAPI.resetScene();
|
excalidrawAPI?.resetScene();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Reset Scene
|
Reset Scene
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
excalidrawAPI.updateLibrary({
|
const libraryItems: LibraryItems = [
|
||||||
libraryItems: [
|
{
|
||||||
{
|
status: "published",
|
||||||
status: "published",
|
id: "1",
|
||||||
elements: initialData.libraryItems[0],
|
created: 1,
|
||||||
},
|
elements: initialData.libraryItems[1] as any,
|
||||||
{
|
},
|
||||||
status: "unpublished",
|
{
|
||||||
elements: initialData.libraryItems[1],
|
status: "unpublished",
|
||||||
},
|
id: "2",
|
||||||
],
|
created: 2,
|
||||||
|
elements: initialData.libraryItems[1] as any,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
excalidrawAPI?.updateLibrary({
|
||||||
|
libraryItems,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -535,9 +598,9 @@ export default function App() {
|
|||||||
username: "fallback",
|
username: "fallback",
|
||||||
avatarUrl: "https://example.com",
|
avatarUrl: "https://example.com",
|
||||||
});
|
});
|
||||||
excalidrawAPI.updateScene({ collaborators });
|
excalidrawAPI?.updateScene({ collaborators });
|
||||||
} else {
|
} else {
|
||||||
excalidrawAPI.updateScene({
|
excalidrawAPI?.updateScene({
|
||||||
collaborators: new Map(),
|
collaborators: new Map(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -571,12 +634,16 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="excalidraw-wrapper">
|
<div className="excalidraw-wrapper">
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
ref={(api) => setExcalidrawAPI(api)}
|
ref={(api: ExcalidrawImperativeAPI) => setExcalidrawAPI(api)}
|
||||||
initialData={initialStatePromiseRef.current.promise}
|
initialData={initialStatePromiseRef.current.promise}
|
||||||
onChange={(elements, state) => {
|
onChange={(elements: ExcalidrawElement[], state: AppState) => {
|
||||||
console.info("Elements :", elements, "State : ", state);
|
console.info("Elements :", elements, "State : ", state);
|
||||||
}}
|
}}
|
||||||
onPointerUpdate={(payload) => setPointerData(payload)}
|
onPointerUpdate={(payload: {
|
||||||
|
pointer: { x: number; y: number };
|
||||||
|
button: "down" | "up";
|
||||||
|
pointersMap: Gesture["pointers"];
|
||||||
|
}) => setPointerData(payload)}
|
||||||
onCollabButtonClick={() =>
|
onCollabButtonClick={() =>
|
||||||
window.alert("You clicked on collab button")
|
window.alert("You clicked on collab button")
|
||||||
}
|
}
|
||||||
@ -616,7 +683,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const svg = await exportToSvg({
|
const svg = await exportToSvg({
|
||||||
elements: excalidrawAPI.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
appState: {
|
appState: {
|
||||||
...initialData.appState,
|
...initialData.appState,
|
||||||
exportWithDarkMode,
|
exportWithDarkMode,
|
||||||
@ -625,7 +692,7 @@ export default function App() {
|
|||||||
height: 100,
|
height: 100,
|
||||||
},
|
},
|
||||||
embedScene: true,
|
embedScene: true,
|
||||||
files: excalidrawAPI.getFiles(),
|
files: excalidrawAPI?.getFiles(),
|
||||||
});
|
});
|
||||||
appRef.current.querySelector(".export-svg").innerHTML =
|
appRef.current.querySelector(".export-svg").innerHTML =
|
||||||
svg.outerHTML;
|
svg.outerHTML;
|
||||||
@ -638,14 +705,14 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const blob = await exportToBlob({
|
const blob = await exportToBlob({
|
||||||
elements: excalidrawAPI.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
mimeType: "image/png",
|
mimeType: "image/png",
|
||||||
appState: {
|
appState: {
|
||||||
...initialData.appState,
|
...initialData.appState,
|
||||||
exportEmbedScene,
|
exportEmbedScene,
|
||||||
exportWithDarkMode,
|
exportWithDarkMode,
|
||||||
},
|
},
|
||||||
files: excalidrawAPI.getFiles(),
|
files: excalidrawAPI?.getFiles(),
|
||||||
});
|
});
|
||||||
setBlobUrl(window.URL.createObjectURL(blob));
|
setBlobUrl(window.URL.createObjectURL(blob));
|
||||||
}}
|
}}
|
||||||
@ -659,12 +726,12 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const canvas = await exportToCanvas({
|
const canvas = await exportToCanvas({
|
||||||
elements: excalidrawAPI.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
appState: {
|
appState: {
|
||||||
...initialData.appState,
|
...initialData.appState,
|
||||||
exportWithDarkMode,
|
exportWithDarkMode,
|
||||||
},
|
},
|
||||||
files: excalidrawAPI.getFiles(),
|
files: excalidrawAPI?.getFiles(),
|
||||||
});
|
});
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.font = "30px Virgil";
|
ctx.font = "30px Virgil";
|
@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import "./Sidebar.scss";
|
import "./Sidebar.scss";
|
||||||
export default function Sidebar(props) {
|
export default function Sidebar({ children }: { children: React.ReactNode }) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -23,7 +23,7 @@ export default function Sidebar(props) {
|
|||||||
>
|
>
|
||||||
Open Sidebar
|
Open Sidebar
|
||||||
</button>
|
</button>
|
||||||
{props.children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
@ -5,7 +5,7 @@ const devConfig = require("./webpack.dev.config");
|
|||||||
|
|
||||||
const devServerConfig = {
|
const devServerConfig = {
|
||||||
entry: {
|
entry: {
|
||||||
bundle: "./example/index.js",
|
bundle: "./example/index.tsx",
|
||||||
},
|
},
|
||||||
// Server Configuration options
|
// Server Configuration options
|
||||||
devServer: {
|
devServer: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user