@haklex/rich-ext-excalidraw 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/dist/ExcalidrawConfigContext.d.ts +10 -0
- package/dist/ExcalidrawConfigContext.d.ts.map +1 -0
- package/dist/ExcalidrawDisplayRenderer.d.ts +6 -0
- package/dist/ExcalidrawDisplayRenderer.d.ts.map +1 -0
- package/dist/ExcalidrawEditNode.d.ts +14 -0
- package/dist/ExcalidrawEditNode.d.ts.map +1 -0
- package/dist/ExcalidrawEditRenderer.d.ts +8 -0
- package/dist/ExcalidrawEditRenderer.d.ts.map +1 -0
- package/dist/ExcalidrawNode-Biawr0pH.js +537 -0
- package/dist/ExcalidrawNode.d.ts +22 -0
- package/dist/ExcalidrawNode.d.ts.map +1 -0
- package/dist/ExcalidrawPlugin.d.ts +3 -0
- package/dist/ExcalidrawPlugin.d.ts.map +1 -0
- package/dist/ExcalidrawRenderer.d.ts +3 -0
- package/dist/ExcalidrawRenderer.d.ts.map +1 -0
- package/dist/ExcalidrawSSRRenderer.d.ts +6 -0
- package/dist/ExcalidrawSSRRenderer.d.ts.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +601 -0
- package/dist/rich-ext-excalidraw.css +1 -0
- package/dist/static.d.ts +13 -0
- package/dist/static.d.ts.map +1 -0
- package/dist/static.mjs +14 -0
- package/dist/styles.css.d.ts +26 -0
- package/dist/styles.css.d.ts.map +1 -0
- package/dist/transformer.d.ts +2 -0
- package/dist/transformer.d.ts.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/useExcalidrawData.d.ts +12 -0
- package/dist/useExcalidrawData.d.ts.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Innei
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Additional Terms and Conditions
|
|
25
|
+
|
|
26
|
+
----------------
|
|
27
|
+
|
|
28
|
+
Use of this software is governed by the terms of MIT and, in addition, by the terms and conditions described in the additional file (ADDITIONAL_TERMS.md). By using this software, you agree to abide by these additional terms and conditions.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface ExcalidrawConfig {
|
|
3
|
+
apiUrl?: string;
|
|
4
|
+
saveSnapshot?: (snapshot: object) => Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
export declare function ExcalidrawConfigProvider({ apiUrl, saveSnapshot, children, }: ExcalidrawConfig & {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function useExcalidrawConfig(): ExcalidrawConfig;
|
|
10
|
+
//# sourceMappingURL=ExcalidrawConfigContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawConfigContext.d.ts","sourceRoot":"","sources":["../src/ExcalidrawConfigContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACrD;AAID,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,YAAY,EACZ,QAAQ,GACT,EAAE,gBAAgB,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAU5C;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawDisplayRenderer.d.ts","sourceRoot":"","sources":["../src/ExcalidrawDisplayRenderer.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAiC,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAA;AAO9E,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,6BAA6B,CAsCvE,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SlashMenuItemConfig } from '@haklex/rich-editor';
|
|
2
|
+
import { EditorConfig, LexicalEditor, LexicalNode, NodeKey } from 'lexical';
|
|
3
|
+
import { ReactElement } from 'react';
|
|
4
|
+
import { ExcalidrawNode, SerializedExcalidrawNode } from './ExcalidrawNode';
|
|
5
|
+
export declare class ExcalidrawEditNode extends ExcalidrawNode {
|
|
6
|
+
static slashMenuItems: SlashMenuItemConfig[];
|
|
7
|
+
static clone(node: ExcalidrawEditNode): ExcalidrawEditNode;
|
|
8
|
+
constructor(snapshot: string, key?: NodeKey);
|
|
9
|
+
static importJSON(serializedNode: SerializedExcalidrawNode): ExcalidrawEditNode;
|
|
10
|
+
decorate(editor: LexicalEditor, _config: EditorConfig): ReactElement;
|
|
11
|
+
}
|
|
12
|
+
export declare function $createExcalidrawEditNode(snapshot: string): ExcalidrawEditNode;
|
|
13
|
+
export declare function $isExcalidrawEditNode(node: LexicalNode | null | undefined): node is ExcalidrawEditNode;
|
|
14
|
+
//# sourceMappingURL=ExcalidrawEditNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawEditNode.d.ts","sourceRoot":"","sources":["../src/ExcalidrawEditNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,cAAc,EAAC,KAAK,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAe/E,qBAAa,kBAAmB,SAAQ,cAAc;IACpD,MAAM,CAAC,cAAc,EAAE,mBAAmB,EAAE,CAa3C;IAED,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB;gBAI9C,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;IAI3C,MAAM,CAAC,UAAU,CACf,cAAc,EAAE,wBAAwB,GACvC,kBAAkB;IAIrB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAsCrE;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAEpB;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACnC,IAAI,IAAI,kBAAkB,CAE5B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { ExcalidrawSnapshot } from './types';
|
|
3
|
+
export interface ExcalidrawEditRendererProps {
|
|
4
|
+
snapshot: ExcalidrawSnapshot | null;
|
|
5
|
+
onSnapshotChange: (snapshot: ExcalidrawSnapshot) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const ExcalidrawEditRenderer: FC<ExcalidrawEditRendererProps>;
|
|
8
|
+
//# sourceMappingURL=ExcalidrawEditRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawEditRenderer.d.ts","sourceRoot":"","sources":["../src/ExcalidrawEditRenderer.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAiB,EAAE,EAAE,MAAM,OAAO,CAAA;AAM9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAGjD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAA;IACnC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACzD;AAsYD,eAAO,MAAM,sBAAsB,EAAE,EAAE,CAAC,2BAA2B,CAiIlE,CAAA"}
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
5
|
+
import { useColorScheme } from "@haklex/rich-editor";
|
|
6
|
+
import { presentDialog } from "@haklex/rich-editor-ui";
|
|
7
|
+
import { usePortalTheme } from "@haklex/rich-style-token";
|
|
8
|
+
import { ZoomIn, ZoomOut, ScanSearch, Maximize2, X } from "lucide-react";
|
|
9
|
+
import { createContext, use, useMemo, useState, useEffect, useRef, useCallback, Component, lazy, Suspense, createElement } from "react";
|
|
10
|
+
import { DecoratorNode } from "lexical";
|
|
11
|
+
const ExcalidrawConfigContext = createContext({});
|
|
12
|
+
function ExcalidrawConfigProvider({
|
|
13
|
+
apiUrl,
|
|
14
|
+
saveSnapshot,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const value = useMemo(
|
|
18
|
+
() => ({ apiUrl, saveSnapshot }),
|
|
19
|
+
[apiUrl, saveSnapshot]
|
|
20
|
+
);
|
|
21
|
+
return /* @__PURE__ */ jsx(ExcalidrawConfigContext.Provider, { value, children });
|
|
22
|
+
}
|
|
23
|
+
function useExcalidrawConfig() {
|
|
24
|
+
return use(ExcalidrawConfigContext);
|
|
25
|
+
}
|
|
26
|
+
const readonlyUIOptions = {
|
|
27
|
+
canvasActions: {
|
|
28
|
+
toggleTheme: false,
|
|
29
|
+
export: false,
|
|
30
|
+
saveAsImage: false,
|
|
31
|
+
loadScene: false,
|
|
32
|
+
changeViewBackgroundColor: false
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var excalidrawStaticContainer = "_1c3wdzl0";
|
|
36
|
+
var excalidrawEditorContainer = "_1c3wdzl1";
|
|
37
|
+
var excalidrawLoading = "_1c3wdzl2";
|
|
38
|
+
var excalidrawError = "_1c3wdzl4";
|
|
39
|
+
var excalidrawActionGroup = "_1c3wdzl5";
|
|
40
|
+
var excalidrawActionButton = "_1c3wdzl6";
|
|
41
|
+
var excalidrawFullscreenPopup = "_1c3wdzl7";
|
|
42
|
+
var excalidrawDialogHeader = "_1c3wdzl8";
|
|
43
|
+
var excalidrawDialogHeaderTitle = "_1c3wdzl9";
|
|
44
|
+
var excalidrawStatusDot = "_1c3wdzla";
|
|
45
|
+
var excalidrawDialogTitle = "_1c3wdzlb";
|
|
46
|
+
var excalidrawDialogMeta = "_1c3wdzlc";
|
|
47
|
+
var excalidrawHeaderActions = "_1c3wdzld";
|
|
48
|
+
var excalidrawHeaderClose = "_1c3wdzle";
|
|
49
|
+
var excalidrawActionBarBtn = "_1c3wdzlf";
|
|
50
|
+
var excalidrawActionBarSep = "_1c3wdzlg";
|
|
51
|
+
var excalidrawActionBarUrl = "_1c3wdzlh";
|
|
52
|
+
var excalidrawDialogCanvas = "_1c3wdzli";
|
|
53
|
+
var excalidrawConfirmActions = "_1c3wdzlj";
|
|
54
|
+
var excalidrawConfirmBtn = "_1c3wdzlk";
|
|
55
|
+
var excalidrawConfirmBtnPrimary = "_1c3wdzll";
|
|
56
|
+
var excalidrawConfirmBtnDanger = "_1c3wdzlm";
|
|
57
|
+
var excalidrawEditOverlay = "_1c3wdzln";
|
|
58
|
+
var excalidrawEditLabel = "_1c3wdzlo";
|
|
59
|
+
function parseSnapshot(raw) {
|
|
60
|
+
if (!raw || !raw.trim()) return null;
|
|
61
|
+
try {
|
|
62
|
+
const json = JSON.parse(raw);
|
|
63
|
+
if (json && typeof json === "object") return { type: "inline", data: json };
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
const lines = raw.split("\n");
|
|
67
|
+
const firstLine = lines[0].trim();
|
|
68
|
+
if (!firstLine.startsWith("http") && !firstLine.startsWith("blob:") && !firstLine.startsWith("ref:"))
|
|
69
|
+
return null;
|
|
70
|
+
const remaining = lines.slice(1).join("\n").trim();
|
|
71
|
+
if (remaining) {
|
|
72
|
+
try {
|
|
73
|
+
const delta = JSON.parse(remaining);
|
|
74
|
+
if (delta && typeof delta === "object")
|
|
75
|
+
return { type: "delta", baseUrl: firstLine, delta };
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { type: "remote", url: firstLine };
|
|
80
|
+
}
|
|
81
|
+
function serializeSnapshot(snapshot) {
|
|
82
|
+
switch (snapshot.type) {
|
|
83
|
+
case "inline":
|
|
84
|
+
return JSON.stringify(snapshot.data);
|
|
85
|
+
case "remote":
|
|
86
|
+
return snapshot.url;
|
|
87
|
+
case "delta":
|
|
88
|
+
return [snapshot.baseUrl, JSON.stringify(snapshot.delta)].join("\n");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function resolveUrl(url, apiUrl) {
|
|
92
|
+
const refLine = url;
|
|
93
|
+
if (url.startsWith("http") || url.startsWith("blob:")) {
|
|
94
|
+
return { fetchUrl: url, refLine };
|
|
95
|
+
}
|
|
96
|
+
if (url.startsWith("ref:") && apiUrl) {
|
|
97
|
+
return { fetchUrl: `${apiUrl}/objects/${url.slice(4)}`, refLine };
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
error: url.startsWith("ref:") ? "Missing apiUrl for ref resolution" : "Unrecognized snapshot format"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function typedToParsed(typed, apiUrl) {
|
|
104
|
+
switch (typed.type) {
|
|
105
|
+
case "inline":
|
|
106
|
+
return { type: "inline", snapshot: typed.data };
|
|
107
|
+
case "remote": {
|
|
108
|
+
const result = resolveUrl(typed.url, apiUrl);
|
|
109
|
+
if ("error" in result) return { type: "error", error: result.error };
|
|
110
|
+
return {
|
|
111
|
+
type: "remote",
|
|
112
|
+
fetchUrl: result.fetchUrl,
|
|
113
|
+
refLine: result.refLine
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case "delta": {
|
|
117
|
+
const result = resolveUrl(typed.baseUrl, apiUrl);
|
|
118
|
+
if ("error" in result) return { type: "error", error: result.error };
|
|
119
|
+
return {
|
|
120
|
+
type: "incremental",
|
|
121
|
+
fetchUrl: result.fetchUrl,
|
|
122
|
+
refLine: result.refLine,
|
|
123
|
+
delta: typed.delta
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function stringToParsed(data, apiUrl) {
|
|
129
|
+
const typed = parseSnapshot(data);
|
|
130
|
+
if (!typed) return { type: "empty" };
|
|
131
|
+
return typedToParsed(typed, apiUrl);
|
|
132
|
+
}
|
|
133
|
+
function useExcalidrawData(data) {
|
|
134
|
+
const { apiUrl } = useExcalidrawConfig();
|
|
135
|
+
const parsed = useMemo(() => {
|
|
136
|
+
if (data === null || data === void 0) return { type: "empty" };
|
|
137
|
+
if (typeof data === "string") return stringToParsed(data, apiUrl);
|
|
138
|
+
return typedToParsed(data, apiUrl);
|
|
139
|
+
}, [data, apiUrl]);
|
|
140
|
+
const [remoteSnapshot, setRemoteSnapshot] = useState();
|
|
141
|
+
const [baseData, setBaseData] = useState();
|
|
142
|
+
const [loading, setLoading] = useState(
|
|
143
|
+
parsed.type === "remote" || parsed.type === "incremental"
|
|
144
|
+
);
|
|
145
|
+
const [error, setError] = useState("");
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (parsed.type !== "remote" && parsed.type !== "incremental") return;
|
|
148
|
+
const { fetchUrl } = parsed;
|
|
149
|
+
const delta = parsed.type === "incremental" ? parsed.delta : void 0;
|
|
150
|
+
let cancelled = false;
|
|
151
|
+
setLoading(true);
|
|
152
|
+
setError("");
|
|
153
|
+
fetch(fetchUrl).then((res) => {
|
|
154
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
155
|
+
return res.json();
|
|
156
|
+
}).then(async (json) => {
|
|
157
|
+
if (cancelled) return;
|
|
158
|
+
setBaseData(json);
|
|
159
|
+
const deltaKeys = delta ? Object.keys(delta) : [];
|
|
160
|
+
if (deltaKeys.length > 0) {
|
|
161
|
+
const { patch } = await import("jsondiffpatch");
|
|
162
|
+
if (cancelled) return;
|
|
163
|
+
const patched = patch(structuredClone(json), delta);
|
|
164
|
+
setRemoteSnapshot(patched);
|
|
165
|
+
} else {
|
|
166
|
+
setRemoteSnapshot(json);
|
|
167
|
+
}
|
|
168
|
+
setLoading(false);
|
|
169
|
+
}).catch((err) => {
|
|
170
|
+
if (!cancelled) {
|
|
171
|
+
setError(err instanceof Error ? err.message : "Failed to load");
|
|
172
|
+
setLoading(false);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return () => {
|
|
176
|
+
cancelled = true;
|
|
177
|
+
};
|
|
178
|
+
}, [parsed]);
|
|
179
|
+
if (parsed.type === "inline") {
|
|
180
|
+
return { snapshot: parsed.snapshot, loading: false, error: "" };
|
|
181
|
+
}
|
|
182
|
+
if (parsed.type === "remote" || parsed.type === "incremental") {
|
|
183
|
+
return {
|
|
184
|
+
snapshot: remoteSnapshot,
|
|
185
|
+
loading,
|
|
186
|
+
error,
|
|
187
|
+
baseRef: parsed.refLine,
|
|
188
|
+
baseData
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (parsed.type === "error") {
|
|
192
|
+
return { snapshot: void 0, loading: false, error: parsed.error };
|
|
193
|
+
}
|
|
194
|
+
return { snapshot: void 0, loading: false, error: "" };
|
|
195
|
+
}
|
|
196
|
+
const ExcalidrawDisplayRenderer = ({
|
|
197
|
+
snapshot
|
|
198
|
+
}) => {
|
|
199
|
+
const theme = useColorScheme();
|
|
200
|
+
const containerRef = useRef(null);
|
|
201
|
+
const [hasEnteredView, setHasEnteredView] = useState(false);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (hasEnteredView) return;
|
|
204
|
+
const target = containerRef.current;
|
|
205
|
+
if (!target) return;
|
|
206
|
+
const observer = new IntersectionObserver(
|
|
207
|
+
(entries) => {
|
|
208
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
209
|
+
setHasEnteredView(true);
|
|
210
|
+
observer.disconnect();
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{ rootMargin: "200px 0px", threshold: 0.1 }
|
|
214
|
+
);
|
|
215
|
+
observer.observe(target);
|
|
216
|
+
return () => observer.disconnect();
|
|
217
|
+
}, [hasEnteredView]);
|
|
218
|
+
if (!hasEnteredView) {
|
|
219
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: excalidrawStaticContainer, children: /* @__PURE__ */ jsx("div", { className: excalidrawLoading, children: "Loading excalidraw..." }) });
|
|
220
|
+
}
|
|
221
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, children: /* @__PURE__ */ jsx(ExcalidrawStaticCanvas, { snapshot, theme }) });
|
|
222
|
+
};
|
|
223
|
+
const ExcalidrawExpandContent = ({ dismiss, ExcalidrawComponent, data, theme }) => {
|
|
224
|
+
const apiRef = useRef(null);
|
|
225
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
226
|
+
/* @__PURE__ */ jsxs("div", { className: excalidrawDialogHeader, children: [
|
|
227
|
+
/* @__PURE__ */ jsxs("div", { className: excalidrawDialogHeaderTitle, children: [
|
|
228
|
+
/* @__PURE__ */ jsx("span", { className: excalidrawDialogTitle, children: "Whiteboard" }),
|
|
229
|
+
/* @__PURE__ */ jsx("span", { className: excalidrawDialogMeta, children: "excalidraw" })
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ jsx(
|
|
232
|
+
"button",
|
|
233
|
+
{
|
|
234
|
+
type: "button",
|
|
235
|
+
className: excalidrawHeaderClose,
|
|
236
|
+
onClick: dismiss,
|
|
237
|
+
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
] }),
|
|
241
|
+
/* @__PURE__ */ jsx("div", { className: excalidrawDialogCanvas, children: /* @__PURE__ */ jsx(
|
|
242
|
+
ExcalidrawComponent,
|
|
243
|
+
{
|
|
244
|
+
initialData: data,
|
|
245
|
+
viewModeEnabled: true,
|
|
246
|
+
zenModeEnabled: true,
|
|
247
|
+
theme,
|
|
248
|
+
UIOptions: readonlyUIOptions,
|
|
249
|
+
excalidrawAPI: (api) => {
|
|
250
|
+
apiRef.current = api;
|
|
251
|
+
setTimeout(() => api.scrollToContent(), 100);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
) })
|
|
255
|
+
] });
|
|
256
|
+
};
|
|
257
|
+
const ExcalidrawStaticCanvas = ({ snapshot, theme }) => {
|
|
258
|
+
const {
|
|
259
|
+
snapshot: data,
|
|
260
|
+
loading: dataLoading,
|
|
261
|
+
error: dataError
|
|
262
|
+
} = useExcalidrawData(snapshot);
|
|
263
|
+
const [ExcalidrawComponent, setExcalidrawComponent] = useState(null);
|
|
264
|
+
const [libLoading, setLibLoading] = useState(true);
|
|
265
|
+
const apiRef = useRef(null);
|
|
266
|
+
const { className: portalClassName } = usePortalTheme();
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
import("@excalidraw/excalidraw").then((mod) => {
|
|
269
|
+
const Comp = mod.Excalidraw;
|
|
270
|
+
if (Comp)
|
|
271
|
+
setExcalidrawComponent(() => Comp);
|
|
272
|
+
setLibLoading(false);
|
|
273
|
+
}).catch((error) => {
|
|
274
|
+
console.error("Error loading excalidraw", error);
|
|
275
|
+
setLibLoading(false);
|
|
276
|
+
});
|
|
277
|
+
}, []);
|
|
278
|
+
const handleExpand = useCallback(() => {
|
|
279
|
+
if (!ExcalidrawComponent || !data) return;
|
|
280
|
+
presentDialog({
|
|
281
|
+
content: ({ dismiss }) => /* @__PURE__ */ jsx(
|
|
282
|
+
ExcalidrawExpandContent,
|
|
283
|
+
{
|
|
284
|
+
dismiss,
|
|
285
|
+
ExcalidrawComponent,
|
|
286
|
+
data,
|
|
287
|
+
theme
|
|
288
|
+
}
|
|
289
|
+
),
|
|
290
|
+
className: excalidrawFullscreenPopup,
|
|
291
|
+
portalClassName,
|
|
292
|
+
theme,
|
|
293
|
+
showCloseButton: false,
|
|
294
|
+
clickOutsideToDismiss: true
|
|
295
|
+
});
|
|
296
|
+
}, [ExcalidrawComponent, data, theme, portalClassName]);
|
|
297
|
+
const loading = dataLoading || libLoading;
|
|
298
|
+
if (loading) {
|
|
299
|
+
return /* @__PURE__ */ jsx("div", { className: excalidrawStaticContainer, children: /* @__PURE__ */ jsx("div", { className: excalidrawLoading, children: "Loading excalidraw..." }) });
|
|
300
|
+
}
|
|
301
|
+
if (dataError || !data) {
|
|
302
|
+
return /* @__PURE__ */ jsx("div", { className: excalidrawStaticContainer, children: /* @__PURE__ */ jsx("div", { className: excalidrawError, children: dataError || "No data" }) });
|
|
303
|
+
}
|
|
304
|
+
if (!ExcalidrawComponent) {
|
|
305
|
+
return /* @__PURE__ */ jsx("div", { className: excalidrawStaticContainer, children: /* @__PURE__ */ jsx("div", { className: excalidrawError, children: "Failed to load excalidraw" }) });
|
|
306
|
+
}
|
|
307
|
+
return /* @__PURE__ */ jsxs(
|
|
308
|
+
"div",
|
|
309
|
+
{
|
|
310
|
+
className: excalidrawStaticContainer,
|
|
311
|
+
"data-theme": theme,
|
|
312
|
+
"data-color-scheme": theme,
|
|
313
|
+
suppressHydrationWarning: true,
|
|
314
|
+
children: [
|
|
315
|
+
/* @__PURE__ */ jsx(
|
|
316
|
+
ExcalidrawErrorBoundary,
|
|
317
|
+
{
|
|
318
|
+
fallback: /* @__PURE__ */ jsx("div", { className: excalidrawError, children: "Failed to render excalidraw" }),
|
|
319
|
+
children: /* @__PURE__ */ jsx(
|
|
320
|
+
ExcalidrawComponent,
|
|
321
|
+
{
|
|
322
|
+
initialData: data,
|
|
323
|
+
viewModeEnabled: true,
|
|
324
|
+
zenModeEnabled: true,
|
|
325
|
+
theme,
|
|
326
|
+
UIOptions: readonlyUIOptions,
|
|
327
|
+
excalidrawAPI: (api) => {
|
|
328
|
+
apiRef.current = api;
|
|
329
|
+
setTimeout(() => api.scrollToContent(), 100);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
),
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: excalidrawActionGroup, children: [
|
|
336
|
+
/* @__PURE__ */ jsx(
|
|
337
|
+
"button",
|
|
338
|
+
{
|
|
339
|
+
type: "button",
|
|
340
|
+
className: excalidrawActionButton,
|
|
341
|
+
title: "Zoom In",
|
|
342
|
+
onClick: () => {
|
|
343
|
+
const api = apiRef.current;
|
|
344
|
+
if (!api) return;
|
|
345
|
+
const zoom = api.getAppState().zoom.value;
|
|
346
|
+
api.updateScene({ appState: { zoom: { value: zoom * 1.25 } } });
|
|
347
|
+
},
|
|
348
|
+
children: /* @__PURE__ */ jsx(ZoomIn, { size: 20 })
|
|
349
|
+
}
|
|
350
|
+
),
|
|
351
|
+
/* @__PURE__ */ jsx(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
type: "button",
|
|
355
|
+
className: excalidrawActionButton,
|
|
356
|
+
title: "Zoom Out",
|
|
357
|
+
onClick: () => {
|
|
358
|
+
const api = apiRef.current;
|
|
359
|
+
if (!api) return;
|
|
360
|
+
const zoom = api.getAppState().zoom.value;
|
|
361
|
+
api.updateScene({ appState: { zoom: { value: zoom / 1.25 } } });
|
|
362
|
+
},
|
|
363
|
+
children: /* @__PURE__ */ jsx(ZoomOut, { size: 20 })
|
|
364
|
+
}
|
|
365
|
+
),
|
|
366
|
+
/* @__PURE__ */ jsx(
|
|
367
|
+
"button",
|
|
368
|
+
{
|
|
369
|
+
type: "button",
|
|
370
|
+
className: excalidrawActionButton,
|
|
371
|
+
title: "Fit to Content",
|
|
372
|
+
onClick: () => apiRef.current?.scrollToContent(),
|
|
373
|
+
children: /* @__PURE__ */ jsx(ScanSearch, { size: 20 })
|
|
374
|
+
}
|
|
375
|
+
),
|
|
376
|
+
/* @__PURE__ */ jsx(
|
|
377
|
+
"button",
|
|
378
|
+
{
|
|
379
|
+
type: "button",
|
|
380
|
+
className: excalidrawActionButton,
|
|
381
|
+
title: "Expand",
|
|
382
|
+
onClick: handleExpand,
|
|
383
|
+
children: /* @__PURE__ */ jsx(Maximize2, { size: 20 })
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
] })
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
class ExcalidrawErrorBoundary extends Component {
|
|
392
|
+
constructor() {
|
|
393
|
+
super(...arguments);
|
|
394
|
+
__publicField(this, "state", { hasError: false });
|
|
395
|
+
}
|
|
396
|
+
static getDerivedStateFromError() {
|
|
397
|
+
return { hasError: true };
|
|
398
|
+
}
|
|
399
|
+
render() {
|
|
400
|
+
return this.state.hasError ? this.props.fallback : this.props.children;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const ExcalidrawDisplayRenderer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
404
|
+
__proto__: null,
|
|
405
|
+
ExcalidrawDisplayRenderer
|
|
406
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
407
|
+
const LazyDisplayRenderer = lazy(
|
|
408
|
+
() => Promise.resolve().then(() => ExcalidrawDisplayRenderer$1).then((m) => ({
|
|
409
|
+
default: m.ExcalidrawDisplayRenderer
|
|
410
|
+
}))
|
|
411
|
+
);
|
|
412
|
+
const ExcalidrawPlaceholder = ({ snapshot }) => {
|
|
413
|
+
let label = "Excalidraw Whiteboard";
|
|
414
|
+
try {
|
|
415
|
+
const data = JSON.parse(snapshot);
|
|
416
|
+
if (data && typeof data === "object") {
|
|
417
|
+
const elementCount = Array.isArray(data.elements) ? data.elements.length : 0;
|
|
418
|
+
if (elementCount > 0) {
|
|
419
|
+
label = `Excalidraw Whiteboard (${elementCount} elements)`;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
return /* @__PURE__ */ jsx(
|
|
425
|
+
"div",
|
|
426
|
+
{
|
|
427
|
+
className: "rich-excalidraw-ssr-placeholder",
|
|
428
|
+
style: {
|
|
429
|
+
position: "relative",
|
|
430
|
+
width: "100%",
|
|
431
|
+
aspectRatio: "16 / 10",
|
|
432
|
+
display: "flex",
|
|
433
|
+
alignItems: "center",
|
|
434
|
+
justifyContent: "center",
|
|
435
|
+
backgroundColor: "var(--rich-excalidraw-bg, #f5f5f5)",
|
|
436
|
+
borderRadius: "8px",
|
|
437
|
+
border: "1px solid var(--rich-excalidraw-border, #e5e5e5)",
|
|
438
|
+
color: "var(--rich-excalidraw-fg, #737373)",
|
|
439
|
+
fontSize: "14px"
|
|
440
|
+
},
|
|
441
|
+
"aria-label": label,
|
|
442
|
+
children: /* @__PURE__ */ jsx("span", { children: label })
|
|
443
|
+
}
|
|
444
|
+
);
|
|
445
|
+
};
|
|
446
|
+
const ExcalidrawSSRRenderer = ({
|
|
447
|
+
snapshot
|
|
448
|
+
}) => {
|
|
449
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ExcalidrawPlaceholder, { snapshot }), children: /* @__PURE__ */ jsx(LazyDisplayRenderer, { snapshot }) });
|
|
450
|
+
};
|
|
451
|
+
class ExcalidrawNode extends DecoratorNode {
|
|
452
|
+
constructor(snapshot, key) {
|
|
453
|
+
super(key);
|
|
454
|
+
__publicField(this, "__snapshot");
|
|
455
|
+
this.__snapshot = snapshot;
|
|
456
|
+
}
|
|
457
|
+
static getType() {
|
|
458
|
+
return "excalidraw";
|
|
459
|
+
}
|
|
460
|
+
static clone(node) {
|
|
461
|
+
return new ExcalidrawNode(node.__snapshot, node.__key);
|
|
462
|
+
}
|
|
463
|
+
createDOM(_config) {
|
|
464
|
+
const div = document.createElement("div");
|
|
465
|
+
div.className = "rich-excalidraw-wrapper";
|
|
466
|
+
return div;
|
|
467
|
+
}
|
|
468
|
+
updateDOM() {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
isInline() {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
static importJSON(serializedNode) {
|
|
475
|
+
return $createExcalidrawNode(serializedNode.snapshot);
|
|
476
|
+
}
|
|
477
|
+
exportJSON() {
|
|
478
|
+
return {
|
|
479
|
+
...super.exportJSON(),
|
|
480
|
+
type: "excalidraw",
|
|
481
|
+
snapshot: this.__snapshot,
|
|
482
|
+
version: 1
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
getSnapshot() {
|
|
486
|
+
return this.__snapshot;
|
|
487
|
+
}
|
|
488
|
+
setSnapshot(snapshot) {
|
|
489
|
+
const writable = this.getWritable();
|
|
490
|
+
writable.__snapshot = snapshot;
|
|
491
|
+
}
|
|
492
|
+
decorate(_editor, _config) {
|
|
493
|
+
return createElement(ExcalidrawSSRRenderer, {
|
|
494
|
+
snapshot: this.__snapshot
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function $createExcalidrawNode(snapshot) {
|
|
499
|
+
return new ExcalidrawNode(snapshot);
|
|
500
|
+
}
|
|
501
|
+
function $isExcalidrawNode(node) {
|
|
502
|
+
return node instanceof ExcalidrawNode;
|
|
503
|
+
}
|
|
504
|
+
export {
|
|
505
|
+
$createExcalidrawNode as $,
|
|
506
|
+
excalidrawActionBarUrl as A,
|
|
507
|
+
excalidrawHeaderClose as B,
|
|
508
|
+
excalidrawDialogCanvas as C,
|
|
509
|
+
ExcalidrawDisplayRenderer$1 as D,
|
|
510
|
+
ExcalidrawConfigProvider as E,
|
|
511
|
+
$isExcalidrawNode as a,
|
|
512
|
+
ExcalidrawDisplayRenderer as b,
|
|
513
|
+
ExcalidrawNode as c,
|
|
514
|
+
ExcalidrawSSRRenderer as d,
|
|
515
|
+
useExcalidrawData as e,
|
|
516
|
+
excalidrawFullscreenPopup as f,
|
|
517
|
+
excalidrawEditorContainer as g,
|
|
518
|
+
excalidrawLoading as h,
|
|
519
|
+
excalidrawError as i,
|
|
520
|
+
excalidrawEditOverlay as j,
|
|
521
|
+
excalidrawEditLabel as k,
|
|
522
|
+
excalidrawConfirmActions as l,
|
|
523
|
+
excalidrawConfirmBtn as m,
|
|
524
|
+
excalidrawConfirmBtnDanger as n,
|
|
525
|
+
excalidrawConfirmBtnPrimary as o,
|
|
526
|
+
parseSnapshot as p,
|
|
527
|
+
excalidrawDialogHeader as q,
|
|
528
|
+
readonlyUIOptions as r,
|
|
529
|
+
serializeSnapshot as s,
|
|
530
|
+
excalidrawStatusDot as t,
|
|
531
|
+
useExcalidrawConfig as u,
|
|
532
|
+
excalidrawDialogTitle as v,
|
|
533
|
+
excalidrawDialogMeta as w,
|
|
534
|
+
excalidrawHeaderActions as x,
|
|
535
|
+
excalidrawActionBarSep as y,
|
|
536
|
+
excalidrawActionBarBtn as z
|
|
537
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EditorConfig, LexicalEditor, LexicalNode, NodeKey, SerializedLexicalNode, Spread, DecoratorNode } from 'lexical';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
export type SerializedExcalidrawNode = Spread<{
|
|
4
|
+
snapshot: string;
|
|
5
|
+
}, SerializedLexicalNode>;
|
|
6
|
+
export declare class ExcalidrawNode extends DecoratorNode<ReactElement> {
|
|
7
|
+
__snapshot: string;
|
|
8
|
+
static getType(): string;
|
|
9
|
+
static clone(node: ExcalidrawNode): ExcalidrawNode;
|
|
10
|
+
constructor(snapshot: string, key?: NodeKey);
|
|
11
|
+
createDOM(_config: EditorConfig): HTMLElement;
|
|
12
|
+
updateDOM(): boolean;
|
|
13
|
+
isInline(): boolean;
|
|
14
|
+
static importJSON(serializedNode: SerializedExcalidrawNode): ExcalidrawNode;
|
|
15
|
+
exportJSON(): SerializedExcalidrawNode;
|
|
16
|
+
getSnapshot(): string;
|
|
17
|
+
setSnapshot(snapshot: string): void;
|
|
18
|
+
decorate(_editor: LexicalEditor, _config: EditorConfig): ReactElement;
|
|
19
|
+
}
|
|
20
|
+
export declare function $createExcalidrawNode(snapshot: string): ExcalidrawNode;
|
|
21
|
+
export declare function $isExcalidrawNode(node: LexicalNode | null | undefined): node is ExcalidrawNode;
|
|
22
|
+
//# sourceMappingURL=ExcalidrawNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawNode.d.ts","sourceRoot":"","sources":["../src/ExcalidrawNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,OAAO,EACP,qBAAqB,EACrB,MAAM,EACP,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAKzC,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAC3C;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EACpB,qBAAqB,CACtB,CAAA;AAED,qBAAa,cAAe,SAAQ,aAAa,CAAC,YAAY,CAAC;IAC7D,UAAU,EAAE,MAAM,CAAA;IAElB,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc;gBAItC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;IAK3C,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAM7C,SAAS,IAAI,OAAO;IAIpB,QAAQ,IAAI,OAAO;IAInB,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,wBAAwB,GAAG,cAAc;IAI3E,UAAU,IAAI,wBAAwB;IAStC,WAAW,IAAI,MAAM;IAIrB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKnC,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,YAAY;CAKtE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAEtE;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACnC,IAAI,IAAI,cAAc,CAExB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawPlugin.d.ts","sourceRoot":"","sources":["../src/ExcalidrawPlugin.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,yBAAyB,0CACM,CAAA;AAE5C,wBAAgB,gBAAgB,SAgB/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawRenderer.d.ts","sourceRoot":"","sources":["../src/ExcalidrawRenderer.tsx"],"names":[],"mappings":"AAAA,YAAY,EAAE,6BAA6B,IAAI,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAC3G,OAAO,EAAE,yBAAyB,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExcalidrawSSRRenderer.d.ts","sourceRoot":"","sources":["../src/ExcalidrawSSRRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAG/B,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAA;CACjB;AA+CD,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CAQhE,CAAA"}
|