@haklex/rich-ext-excalidraw 0.14.0 → 0.15.0
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/dist/index.mjs +484 -8
- package/dist/slot.d.ts +1 -1
- package/dist/slot.d.ts.map +1 -1
- package/dist/static.mjs +1 -2
- package/dist/{ExcalidrawDisplayRenderer-BWsFJSQ7.js → transformer-B0euMW7k.js} +134 -11
- package/package.json +10 -10
- package/dist/ExcalidrawEditRenderer-BlJTjnpV.js +0 -484
- package/dist/rolldown-runtime-CiIaOW0V.js +0 -13
- package/dist/transformer-zBd4ibNw.js +0 -119
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { PenTool } from "lucide-react";
|
|
7
|
-
import { ViewportGate } from "@haklex/rich-editor-ui";
|
|
1
|
+
import { a as ExcalidrawNode, c as ExcalidrawDisplayRenderer, d as __exportAll, i as $isExcalidrawNode, n as ExcalidrawExpandShell, o as EXCALIDRAW_NODE_KEY, r as $createExcalidrawNode, s as ExcalidrawSSRRenderer, t as EXCALIDRAW_BLOCK_TRANSFORMER, u as _defineProperty } from "./transformer-B0euMW7k.js";
|
|
2
|
+
import { A as ExcalidrawConfigProvider, C as excalidrawHeaderActions, O as excalidrawStatusDot, S as excalidrawFullscreenPopup, T as excalidrawLoading, _ as excalidrawDialogTitle, b as excalidrawEditorContainer, d as excalidrawConfirmBtnDanger, f as excalidrawConfirmBtnPrimary, g as excalidrawDialogMeta, i as excalidrawActionBarBtn, j as useExcalidrawConfig, k as readonlyUIOptions, l as excalidrawConfirmActions, m as excalidrawDialogHeader, n as parseSnapshot, p as excalidrawDialogCanvas, r as serializeSnapshot, t as useExcalidrawData, u as excalidrawConfirmBtn, v as excalidrawEditLabel, w as excalidrawHeaderClose, x as excalidrawError, y as excalidrawEditOverlay } from "./useExcalidrawData-DcXa8vqV.js";
|
|
3
|
+
import { Suspense, createElement, lazy, useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useColorScheme } from "@haklex/rich-editor/static";
|
|
6
|
+
import { Clipboard, Download, PenTool, Pencil, Save, X } from "lucide-react";
|
|
7
|
+
import { SegmentedControl, ViewportGate, dismissTopDialog, presentDialog } from "@haklex/rich-editor-ui";
|
|
8
8
|
import { $getNodeByKey, $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand } from "lexical";
|
|
9
|
+
import { usePortalTheme } from "@haklex/rich-style-token";
|
|
9
10
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
10
11
|
//#region src/ExcalidrawEditNode.ts
|
|
11
|
-
var LazyEditRenderer = lazy(() =>
|
|
12
|
+
var LazyEditRenderer = lazy(() => Promise.resolve().then(() => ExcalidrawEditRenderer_exports).then((m) => ({ default: m.ExcalidrawEditRenderer })));
|
|
12
13
|
var ExcalidrawEditNode = class ExcalidrawEditNode extends ExcalidrawNode {
|
|
13
14
|
static clone(node) {
|
|
14
15
|
return new ExcalidrawEditNode(node.__snapshot, node.__key);
|
|
@@ -71,6 +72,481 @@ function $isExcalidrawEditNode(node) {
|
|
|
71
72
|
return node instanceof ExcalidrawEditNode;
|
|
72
73
|
}
|
|
73
74
|
//#endregion
|
|
75
|
+
//#region src/ExcalidrawEditRenderer.tsx
|
|
76
|
+
var ExcalidrawEditRenderer_exports = /* @__PURE__ */ __exportAll({ ExcalidrawEditRenderer: () => ExcalidrawEditRenderer });
|
|
77
|
+
var SAVE_DEBOUNCE_MS = 2e3;
|
|
78
|
+
var ExcalidrawEditorDialogContent = ({ dismiss, ExcalidrawComponent, initialData, initialSnapshot, theme, onSave, saveSnapshot, onClose, baseRef, baseData }) => {
|
|
79
|
+
const { className: portalClassName } = usePortalTheme();
|
|
80
|
+
const apiRef = useRef(null);
|
|
81
|
+
const saveTimerRef = useRef(void 0);
|
|
82
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
83
|
+
const isDirtyRef = useRef(false);
|
|
84
|
+
const confirmDialogOpenRef = useRef(false);
|
|
85
|
+
const initializedRef = useRef(false);
|
|
86
|
+
const stableRef = useRef(false);
|
|
87
|
+
const baseRefRef = useRef(baseRef);
|
|
88
|
+
const baseDataRef = useRef(baseData);
|
|
89
|
+
const [storageMode, setStorageMode] = useState(() => {
|
|
90
|
+
if (!saveSnapshot || !initialSnapshot) return "inline";
|
|
91
|
+
return initialSnapshot.type === "delta" ? "delta" : initialSnapshot.type === "remote" ? "remote" : "inline";
|
|
92
|
+
});
|
|
93
|
+
const storageModeRef = useRef(storageMode);
|
|
94
|
+
const [savedRef, setSavedRef] = useState(() => {
|
|
95
|
+
if (!saveSnapshot || !initialSnapshot) return "";
|
|
96
|
+
if (initialSnapshot.type === "remote") return initialSnapshot.url;
|
|
97
|
+
if (initialSnapshot.type === "delta") return initialSnapshot.baseUrl;
|
|
98
|
+
return "";
|
|
99
|
+
});
|
|
100
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const stableTimer = setTimeout(() => {
|
|
103
|
+
stableRef.current = true;
|
|
104
|
+
}, 500);
|
|
105
|
+
return () => {
|
|
106
|
+
clearTimeout(stableTimer);
|
|
107
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
108
|
+
};
|
|
109
|
+
}, []);
|
|
110
|
+
const getSnapshot = useCallback(() => {
|
|
111
|
+
const api = apiRef.current;
|
|
112
|
+
if (!api) return;
|
|
113
|
+
const appState = api.getAppState();
|
|
114
|
+
return {
|
|
115
|
+
elements: api.getSceneElements(),
|
|
116
|
+
appState: {
|
|
117
|
+
viewBackgroundColor: appState.viewBackgroundColor,
|
|
118
|
+
gridSize: appState.gridSize
|
|
119
|
+
},
|
|
120
|
+
files: api.getFiles()
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
const performSave = useCallback(() => {
|
|
124
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
125
|
+
const doc = getSnapshot();
|
|
126
|
+
if (!doc) return Promise.resolve();
|
|
127
|
+
const mode = storageModeRef.current;
|
|
128
|
+
if (mode === "delta" && saveSnapshot) {
|
|
129
|
+
setIsSaving(true);
|
|
130
|
+
return (async () => {
|
|
131
|
+
try {
|
|
132
|
+
const currentBaseUrl = baseRefRef.current;
|
|
133
|
+
const currentBaseData = baseDataRef.current;
|
|
134
|
+
if (!currentBaseUrl || !currentBaseData) {
|
|
135
|
+
const ref = await saveSnapshot(doc, baseRefRef.current || void 0);
|
|
136
|
+
baseRefRef.current = ref;
|
|
137
|
+
baseDataRef.current = doc;
|
|
138
|
+
setSavedRef(ref);
|
|
139
|
+
}
|
|
140
|
+
isDirtyRef.current = false;
|
|
141
|
+
setIsDirty(false);
|
|
142
|
+
} finally {
|
|
143
|
+
setIsSaving(false);
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
}
|
|
147
|
+
if (mode === "remote" && saveSnapshot) {
|
|
148
|
+
if (baseRefRef.current && baseDataRef.current && JSON.stringify(doc) === JSON.stringify(baseDataRef.current)) {
|
|
149
|
+
isDirtyRef.current = false;
|
|
150
|
+
setIsDirty(false);
|
|
151
|
+
return Promise.resolve();
|
|
152
|
+
}
|
|
153
|
+
setIsSaving(true);
|
|
154
|
+
return saveSnapshot(doc, baseRefRef.current || void 0).then((ref) => {
|
|
155
|
+
baseRefRef.current = ref;
|
|
156
|
+
baseDataRef.current = doc;
|
|
157
|
+
isDirtyRef.current = false;
|
|
158
|
+
setIsDirty(false);
|
|
159
|
+
setIsSaving(false);
|
|
160
|
+
setSavedRef(ref);
|
|
161
|
+
}, () => {
|
|
162
|
+
setIsSaving(false);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
isDirtyRef.current = false;
|
|
166
|
+
setIsDirty(false);
|
|
167
|
+
return Promise.resolve();
|
|
168
|
+
}, [saveSnapshot, getSnapshot]);
|
|
169
|
+
const emitSnapshot = useCallback(async () => {
|
|
170
|
+
const doc = getSnapshot();
|
|
171
|
+
if (!doc) return;
|
|
172
|
+
const mode = storageModeRef.current;
|
|
173
|
+
if (mode === "delta" && saveSnapshot) {
|
|
174
|
+
const currentBaseUrl = baseRefRef.current;
|
|
175
|
+
const currentBaseData = baseDataRef.current;
|
|
176
|
+
if (currentBaseUrl && currentBaseData) {
|
|
177
|
+
const { diff } = await import("jsondiffpatch");
|
|
178
|
+
const delta = diff(currentBaseData, structuredClone(doc));
|
|
179
|
+
onSave(delta ? {
|
|
180
|
+
type: "delta",
|
|
181
|
+
baseUrl: currentBaseUrl,
|
|
182
|
+
delta
|
|
183
|
+
} : {
|
|
184
|
+
type: "remote",
|
|
185
|
+
url: currentBaseUrl
|
|
186
|
+
});
|
|
187
|
+
} else onSave({
|
|
188
|
+
type: "remote",
|
|
189
|
+
url: await saveSnapshot(doc, baseRefRef.current || void 0)
|
|
190
|
+
});
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (mode === "remote") {
|
|
194
|
+
const ref = baseRefRef.current;
|
|
195
|
+
if (ref) onSave({
|
|
196
|
+
type: "remote",
|
|
197
|
+
url: ref
|
|
198
|
+
});
|
|
199
|
+
else if (saveSnapshot) onSave({
|
|
200
|
+
type: "remote",
|
|
201
|
+
url: await saveSnapshot(doc)
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
onSave({
|
|
206
|
+
type: "inline",
|
|
207
|
+
data: doc
|
|
208
|
+
});
|
|
209
|
+
}, [
|
|
210
|
+
onSave,
|
|
211
|
+
saveSnapshot,
|
|
212
|
+
getSnapshot
|
|
213
|
+
]);
|
|
214
|
+
const handleChange = useCallback((elements) => {
|
|
215
|
+
if (!initializedRef.current) {
|
|
216
|
+
initializedRef.current = true;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!stableRef.current) return;
|
|
220
|
+
if (elements.length === 0) return;
|
|
221
|
+
if (!isDirtyRef.current) {
|
|
222
|
+
isDirtyRef.current = true;
|
|
223
|
+
setIsDirty(true);
|
|
224
|
+
}
|
|
225
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
226
|
+
saveTimerRef.current = setTimeout(() => performSave(), SAVE_DEBOUNCE_MS);
|
|
227
|
+
}, [performSave]);
|
|
228
|
+
const handleSaveAndClose = useCallback(() => {
|
|
229
|
+
performSave().then(async () => {
|
|
230
|
+
await emitSnapshot();
|
|
231
|
+
onClose(getSnapshot());
|
|
232
|
+
dismiss();
|
|
233
|
+
});
|
|
234
|
+
}, [
|
|
235
|
+
performSave,
|
|
236
|
+
emitSnapshot,
|
|
237
|
+
getSnapshot,
|
|
238
|
+
onClose,
|
|
239
|
+
dismiss
|
|
240
|
+
]);
|
|
241
|
+
const handleDiscard = useCallback(() => {
|
|
242
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
243
|
+
dismiss();
|
|
244
|
+
}, [dismiss]);
|
|
245
|
+
const showConfirmDialog = useCallback(() => {
|
|
246
|
+
if (confirmDialogOpenRef.current) return;
|
|
247
|
+
confirmDialogOpenRef.current = true;
|
|
248
|
+
presentDialog({
|
|
249
|
+
title: "Unsaved Changes",
|
|
250
|
+
description: "You have unsaved changes that will be lost if you close now.",
|
|
251
|
+
content: ({ dismiss: dismissConfirm }) => {
|
|
252
|
+
const wrappedDismiss = () => {
|
|
253
|
+
confirmDialogOpenRef.current = false;
|
|
254
|
+
dismissConfirm();
|
|
255
|
+
};
|
|
256
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
257
|
+
className: excalidrawConfirmActions,
|
|
258
|
+
children: [
|
|
259
|
+
/* @__PURE__ */ jsx("button", {
|
|
260
|
+
className: excalidrawConfirmBtn,
|
|
261
|
+
type: "button",
|
|
262
|
+
onClick: wrappedDismiss,
|
|
263
|
+
children: "Continue Editing"
|
|
264
|
+
}),
|
|
265
|
+
/* @__PURE__ */ jsx("button", {
|
|
266
|
+
className: excalidrawConfirmBtnDanger,
|
|
267
|
+
type: "button",
|
|
268
|
+
onClick: () => {
|
|
269
|
+
wrappedDismiss();
|
|
270
|
+
handleDiscard();
|
|
271
|
+
},
|
|
272
|
+
children: "Discard"
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ jsx("button", {
|
|
275
|
+
className: excalidrawConfirmBtnPrimary,
|
|
276
|
+
type: "button",
|
|
277
|
+
onClick: () => {
|
|
278
|
+
wrappedDismiss();
|
|
279
|
+
handleSaveAndClose();
|
|
280
|
+
},
|
|
281
|
+
children: "Save & Close"
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
});
|
|
285
|
+
},
|
|
286
|
+
portalClassName,
|
|
287
|
+
theme,
|
|
288
|
+
showCloseButton: false,
|
|
289
|
+
clickOutsideToDismiss: false
|
|
290
|
+
});
|
|
291
|
+
}, [
|
|
292
|
+
handleDiscard,
|
|
293
|
+
handleSaveAndClose,
|
|
294
|
+
portalClassName,
|
|
295
|
+
theme
|
|
296
|
+
]);
|
|
297
|
+
const attemptClose = useCallback(() => {
|
|
298
|
+
if (isDirtyRef.current) showConfirmDialog();
|
|
299
|
+
else emitSnapshot().then(() => {
|
|
300
|
+
onClose(getSnapshot());
|
|
301
|
+
dismiss();
|
|
302
|
+
});
|
|
303
|
+
}, [
|
|
304
|
+
dismiss,
|
|
305
|
+
showConfirmDialog,
|
|
306
|
+
emitSnapshot,
|
|
307
|
+
getSnapshot,
|
|
308
|
+
onClose
|
|
309
|
+
]);
|
|
310
|
+
useEffect(() => {
|
|
311
|
+
const handleKeyDown = (e) => {
|
|
312
|
+
if (e.key === "Escape") {
|
|
313
|
+
e.preventDefault();
|
|
314
|
+
e.stopImmediatePropagation();
|
|
315
|
+
if (confirmDialogOpenRef.current) {
|
|
316
|
+
confirmDialogOpenRef.current = false;
|
|
317
|
+
dismissTopDialog();
|
|
318
|
+
} else attemptClose();
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
322
|
+
return () => document.removeEventListener("keydown", handleKeyDown, true);
|
|
323
|
+
}, [attemptClose]);
|
|
324
|
+
const handleManualUpload = useCallback(() => {
|
|
325
|
+
performSave();
|
|
326
|
+
}, [performSave]);
|
|
327
|
+
const handleExportJson = useCallback(() => {
|
|
328
|
+
const doc = getSnapshot();
|
|
329
|
+
if (!doc) return;
|
|
330
|
+
const blob = new Blob([JSON.stringify(doc, null, 2)], { type: "application/json" });
|
|
331
|
+
const url = URL.createObjectURL(blob);
|
|
332
|
+
const a = document.createElement("a");
|
|
333
|
+
a.href = url;
|
|
334
|
+
a.download = "excalidraw-snapshot.json";
|
|
335
|
+
a.click();
|
|
336
|
+
URL.revokeObjectURL(url);
|
|
337
|
+
}, [getSnapshot]);
|
|
338
|
+
const handleCopyJson = useCallback(() => {
|
|
339
|
+
const doc = getSnapshot();
|
|
340
|
+
if (!doc) return;
|
|
341
|
+
navigator.clipboard.writeText(JSON.stringify(doc));
|
|
342
|
+
}, [getSnapshot]);
|
|
343
|
+
const handleRefChange = useCallback((e) => {
|
|
344
|
+
const { value } = e.target;
|
|
345
|
+
setSavedRef(value);
|
|
346
|
+
baseRefRef.current = value;
|
|
347
|
+
baseDataRef.current = void 0;
|
|
348
|
+
}, []);
|
|
349
|
+
const handleStorageModeChange = useCallback((newMode) => {
|
|
350
|
+
setStorageMode(newMode);
|
|
351
|
+
storageModeRef.current = newMode;
|
|
352
|
+
if (newMode === "inline") setSavedRef("");
|
|
353
|
+
performSave();
|
|
354
|
+
}, [performSave]);
|
|
355
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
356
|
+
className: excalidrawDialogHeader,
|
|
357
|
+
children: [
|
|
358
|
+
/* @__PURE__ */ jsx("span", {
|
|
359
|
+
className: excalidrawStatusDot,
|
|
360
|
+
style: { backgroundColor: isDirty ? "#f59e0b" : "#22c55e" }
|
|
361
|
+
}),
|
|
362
|
+
/* @__PURE__ */ jsx("span", {
|
|
363
|
+
className: excalidrawDialogTitle,
|
|
364
|
+
children: "Canvas Editor"
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ jsx("span", {
|
|
367
|
+
className: excalidrawDialogMeta,
|
|
368
|
+
children: "excalidraw"
|
|
369
|
+
}),
|
|
370
|
+
/* @__PURE__ */ jsxs("div", {
|
|
371
|
+
className: excalidrawHeaderActions,
|
|
372
|
+
children: [
|
|
373
|
+
saveSnapshot && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
374
|
+
/* @__PURE__ */ jsx(SegmentedControl, {
|
|
375
|
+
value: storageMode,
|
|
376
|
+
items: [
|
|
377
|
+
{
|
|
378
|
+
value: "inline",
|
|
379
|
+
label: "Inline"
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
value: "remote",
|
|
383
|
+
label: "Remote"
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
value: "delta",
|
|
387
|
+
label: "Delta"
|
|
388
|
+
}
|
|
389
|
+
],
|
|
390
|
+
onChange: handleStorageModeChange
|
|
391
|
+
}),
|
|
392
|
+
/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" }),
|
|
393
|
+
/* @__PURE__ */ jsxs("button", {
|
|
394
|
+
className: "_1c3wdzlg",
|
|
395
|
+
disabled: isSaving,
|
|
396
|
+
type: "button",
|
|
397
|
+
onClick: handleManualUpload,
|
|
398
|
+
children: [/* @__PURE__ */ jsx(Save, { size: 14 }), /* @__PURE__ */ jsx("span", { children: isSaving ? "Saving..." : "Save" })]
|
|
399
|
+
}),
|
|
400
|
+
/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" })
|
|
401
|
+
] }),
|
|
402
|
+
/* @__PURE__ */ jsxs("button", {
|
|
403
|
+
className: excalidrawActionBarBtn,
|
|
404
|
+
type: "button",
|
|
405
|
+
onClick: handleExportJson,
|
|
406
|
+
children: [/* @__PURE__ */ jsx(Download, { size: 14 }), "JSON"]
|
|
407
|
+
}),
|
|
408
|
+
/* @__PURE__ */ jsxs("button", {
|
|
409
|
+
className: excalidrawActionBarBtn,
|
|
410
|
+
type: "button",
|
|
411
|
+
onClick: handleCopyJson,
|
|
412
|
+
children: [/* @__PURE__ */ jsx(Clipboard, { size: 14 }), "Copy"]
|
|
413
|
+
}),
|
|
414
|
+
storageMode !== "inline" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" }), /* @__PURE__ */ jsx("input", {
|
|
415
|
+
className: "_1c3wdzli",
|
|
416
|
+
placeholder: "base URL / ref",
|
|
417
|
+
spellCheck: false,
|
|
418
|
+
type: "text",
|
|
419
|
+
value: savedRef,
|
|
420
|
+
onChange: handleRefChange
|
|
421
|
+
})] })
|
|
422
|
+
]
|
|
423
|
+
}),
|
|
424
|
+
/* @__PURE__ */ jsx("button", {
|
|
425
|
+
className: excalidrawHeaderClose,
|
|
426
|
+
type: "button",
|
|
427
|
+
onClick: attemptClose,
|
|
428
|
+
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
429
|
+
})
|
|
430
|
+
]
|
|
431
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
432
|
+
className: excalidrawDialogCanvas,
|
|
433
|
+
children: /* @__PURE__ */ jsx(ExcalidrawComponent, {
|
|
434
|
+
initialData,
|
|
435
|
+
theme,
|
|
436
|
+
excalidrawAPI: (api) => {
|
|
437
|
+
apiRef.current = api;
|
|
438
|
+
},
|
|
439
|
+
onChange: handleChange
|
|
440
|
+
})
|
|
441
|
+
})] });
|
|
442
|
+
};
|
|
443
|
+
var ExcalidrawEditRenderer = ({ snapshot, onSnapshotChange }) => {
|
|
444
|
+
const theme = useColorScheme();
|
|
445
|
+
const { saveSnapshot } = useExcalidrawConfig();
|
|
446
|
+
const { snapshot: initialData, loading: dataLoading, error: dataError, baseRef, baseData } = useExcalidrawData(snapshot);
|
|
447
|
+
const [ExcalidrawComponent, setExcalidrawComponent] = useState(null);
|
|
448
|
+
const [libLoading, setLibLoading] = useState(true);
|
|
449
|
+
const previewApiRef = useRef(null);
|
|
450
|
+
const initialDataRef = useRef(void 0);
|
|
451
|
+
const [previewKey, setPreviewKey] = useState(0);
|
|
452
|
+
const onSnapshotChangeRef = useRef(onSnapshotChange);
|
|
453
|
+
onSnapshotChangeRef.current = onSnapshotChange;
|
|
454
|
+
const saveSnapshotRef = useRef(saveSnapshot);
|
|
455
|
+
saveSnapshotRef.current = saveSnapshot;
|
|
456
|
+
const snapshotRef = useRef(snapshot);
|
|
457
|
+
snapshotRef.current = snapshot;
|
|
458
|
+
const { className: portalClassName } = usePortalTheme();
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
if (initialData && !initialDataRef.current) initialDataRef.current = initialData;
|
|
461
|
+
}, [initialData]);
|
|
462
|
+
useEffect(() => {
|
|
463
|
+
Promise.all([import("@excalidraw/excalidraw"), import("@excalidraw/excalidraw/index.css")]).then(([mod]) => {
|
|
464
|
+
const Comp = mod.Excalidraw || mod.default?.Excalidraw;
|
|
465
|
+
if (Comp) setExcalidrawComponent(() => Comp);
|
|
466
|
+
setLibLoading(false);
|
|
467
|
+
}).catch((err) => {
|
|
468
|
+
console.error("[excalidraw] failed to load", err);
|
|
469
|
+
setLibLoading(false);
|
|
470
|
+
});
|
|
471
|
+
}, []);
|
|
472
|
+
const baseRefRef = useRef(baseRef);
|
|
473
|
+
const baseDataRefOuter = useRef(baseData);
|
|
474
|
+
useEffect(() => {
|
|
475
|
+
if (baseRef) baseRefRef.current = baseRef;
|
|
476
|
+
}, [baseRef]);
|
|
477
|
+
useEffect(() => {
|
|
478
|
+
if (baseData) baseDataRefOuter.current = baseData;
|
|
479
|
+
}, [baseData]);
|
|
480
|
+
const handleOpenEditor = useCallback(() => {
|
|
481
|
+
if (!ExcalidrawComponent || dataLoading) return;
|
|
482
|
+
presentDialog({
|
|
483
|
+
content: ({ dismiss }) => /* @__PURE__ */ jsx(ExcalidrawEditorDialogContent, {
|
|
484
|
+
ExcalidrawComponent,
|
|
485
|
+
baseData: baseDataRefOuter.current,
|
|
486
|
+
baseRef: baseRefRef.current,
|
|
487
|
+
dismiss,
|
|
488
|
+
initialData: initialDataRef.current,
|
|
489
|
+
initialSnapshot: snapshotRef.current,
|
|
490
|
+
saveSnapshot: saveSnapshotRef.current,
|
|
491
|
+
theme,
|
|
492
|
+
onSave: (ref) => onSnapshotChangeRef.current(ref),
|
|
493
|
+
onClose: (doc) => {
|
|
494
|
+
if (doc) {
|
|
495
|
+
initialDataRef.current = doc;
|
|
496
|
+
setPreviewKey((k) => k + 1);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}),
|
|
500
|
+
className: excalidrawFullscreenPopup,
|
|
501
|
+
portalClassName,
|
|
502
|
+
theme,
|
|
503
|
+
showCloseButton: false,
|
|
504
|
+
clickOutsideToDismiss: false
|
|
505
|
+
});
|
|
506
|
+
}, [
|
|
507
|
+
ExcalidrawComponent,
|
|
508
|
+
dataLoading,
|
|
509
|
+
theme,
|
|
510
|
+
portalClassName
|
|
511
|
+
]);
|
|
512
|
+
if (dataLoading || libLoading || !ExcalidrawComponent) return /* @__PURE__ */ jsx("div", {
|
|
513
|
+
className: excalidrawEditorContainer,
|
|
514
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
515
|
+
className: excalidrawLoading,
|
|
516
|
+
children: "Loading excalidraw editor..."
|
|
517
|
+
})
|
|
518
|
+
});
|
|
519
|
+
if (dataError) return /* @__PURE__ */ jsx("div", {
|
|
520
|
+
className: excalidrawEditorContainer,
|
|
521
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
522
|
+
className: excalidrawError,
|
|
523
|
+
children: dataError
|
|
524
|
+
})
|
|
525
|
+
});
|
|
526
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
527
|
+
className: excalidrawEditorContainer,
|
|
528
|
+
children: [/* @__PURE__ */ jsx(ExcalidrawComponent, {
|
|
529
|
+
viewModeEnabled: true,
|
|
530
|
+
zenModeEnabled: true,
|
|
531
|
+
UIOptions: readonlyUIOptions,
|
|
532
|
+
initialData: initialDataRef.current,
|
|
533
|
+
theme,
|
|
534
|
+
excalidrawAPI: (api) => {
|
|
535
|
+
previewApiRef.current = api;
|
|
536
|
+
setTimeout(() => api.scrollToContent(), 100);
|
|
537
|
+
}
|
|
538
|
+
}, previewKey), /* @__PURE__ */ jsx("button", {
|
|
539
|
+
className: excalidrawEditOverlay,
|
|
540
|
+
type: "button",
|
|
541
|
+
onClick: handleOpenEditor,
|
|
542
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
543
|
+
className: excalidrawEditLabel,
|
|
544
|
+
children: [/* @__PURE__ */ jsx(Pencil, { size: 16 }), "Edit Whiteboard"]
|
|
545
|
+
})
|
|
546
|
+
})]
|
|
547
|
+
});
|
|
548
|
+
};
|
|
549
|
+
//#endregion
|
|
74
550
|
//#region src/ExcalidrawPlugin.tsx
|
|
75
551
|
var INSERT_EXCALIDRAW_COMMAND = createCommand("INSERT_EXCALIDRAW");
|
|
76
552
|
function ExcalidrawPlugin() {
|
package/dist/slot.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export declare const EXCALIDRAW_NODE_KEY: "Excalidraw";
|
|
|
3
3
|
export interface ExcalidrawSlotProps {
|
|
4
4
|
snapshot: string;
|
|
5
5
|
}
|
|
6
|
-
declare module '@haklex/rich-editor' {
|
|
6
|
+
declare module '@haklex/rich-editor/static' {
|
|
7
7
|
interface RendererConfig {
|
|
8
8
|
Excalidraw?: ComponentType<ExcalidrawSlotProps>;
|
|
9
9
|
}
|
package/dist/slot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../src/slot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,mBAAmB,EAAG,YAAqB,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,QAAQ,
|
|
1
|
+
{"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../src/slot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,mBAAmB,EAAG,YAAqB,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,QAAQ,4BAA4B,CAAC;IAC1C,UAAU,cAAc;QACtB,UAAU,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;KACjD;CACF"}
|
package/dist/static.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
+
import { a as ExcalidrawNode, c as ExcalidrawDisplayRenderer, i as $isExcalidrawNode, n as ExcalidrawExpandShell, o as EXCALIDRAW_NODE_KEY, r as $createExcalidrawNode, s as ExcalidrawSSRRenderer, t as EXCALIDRAW_BLOCK_TRANSFORMER } from "./transformer-B0euMW7k.js";
|
|
1
2
|
import { A as ExcalidrawConfigProvider, S as excalidrawFullscreenPopup, j as useExcalidrawConfig } from "./useExcalidrawData-DcXa8vqV.js";
|
|
2
|
-
import { t as ExcalidrawDisplayRenderer } from "./ExcalidrawDisplayRenderer-BWsFJSQ7.js";
|
|
3
|
-
import { a as ExcalidrawNode, i as $isExcalidrawNode, n as ExcalidrawExpandShell, o as EXCALIDRAW_NODE_KEY, r as $createExcalidrawNode, s as ExcalidrawSSRRenderer, t as EXCALIDRAW_BLOCK_TRANSFORMER } from "./transformer-zBd4ibNw.js";
|
|
4
3
|
export { $createExcalidrawNode, $isExcalidrawNode, EXCALIDRAW_BLOCK_TRANSFORMER, EXCALIDRAW_NODE_KEY, ExcalidrawConfigProvider, ExcalidrawDisplayRenderer, ExcalidrawDisplayRenderer as ExcalidrawRenderer, ExcalidrawDisplayRenderer as ExcalidrawStaticRenderer, ExcalidrawExpandShell, ExcalidrawNode, ExcalidrawSSRRenderer, excalidrawFullscreenPopup, useExcalidrawConfig };
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import { D as excalidrawStaticContainer, E as excalidrawPlaceholder, T as excalidrawLoading, _ as excalidrawDialogTitle, c as excalidrawActionGroup, h as excalidrawDialogHeaderTitle, k as readonlyUIOptions, m as excalidrawDialogHeader, p as excalidrawDialogCanvas, s as excalidrawActionButton, t as useExcalidrawData, w as excalidrawHeaderClose, x as excalidrawError } from "./useExcalidrawData-DcXa8vqV.js";
|
|
2
|
+
import { Component, Suspense, lazy, useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { createRendererDecoration, useColorScheme } from "@haklex/rich-editor/static";
|
|
5
|
+
import { Maximize2, ScanSearch, X, ZoomIn, ZoomOut } from "lucide-react";
|
|
6
|
+
import { ViewportGate } from "@haklex/rich-editor-ui";
|
|
7
|
+
import { DecoratorNode } from "lexical";
|
|
8
|
+
import { EXCALIDRAW_BLOCK_TRANSFORMER } from "@haklex/rich-headless/transformers";
|
|
9
|
+
//#region \0rolldown/runtime.js
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __exportAll = (all, no_symbols) => {
|
|
12
|
+
let target = {};
|
|
13
|
+
for (var name in all) __defProp(target, name, {
|
|
14
|
+
get: all[name],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region \0@oxc-project+runtime@0.130.0/helpers/typeof.js
|
|
8
22
|
function _typeof(o) {
|
|
9
23
|
"@babel/helpers - typeof";
|
|
10
24
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -14,7 +28,7 @@ function _typeof(o) {
|
|
|
14
28
|
}, _typeof(o);
|
|
15
29
|
}
|
|
16
30
|
//#endregion
|
|
17
|
-
//#region \0@oxc-project+runtime@0.
|
|
31
|
+
//#region \0@oxc-project+runtime@0.130.0/helpers/toPrimitive.js
|
|
18
32
|
function toPrimitive(t, r) {
|
|
19
33
|
if ("object" != _typeof(t) || !t) return t;
|
|
20
34
|
var e = t[Symbol.toPrimitive];
|
|
@@ -26,13 +40,13 @@ function toPrimitive(t, r) {
|
|
|
26
40
|
return ("string" === r ? String : Number)(t);
|
|
27
41
|
}
|
|
28
42
|
//#endregion
|
|
29
|
-
//#region \0@oxc-project+runtime@0.
|
|
43
|
+
//#region \0@oxc-project+runtime@0.130.0/helpers/toPropertyKey.js
|
|
30
44
|
function toPropertyKey(t) {
|
|
31
45
|
var i = toPrimitive(t, "string");
|
|
32
46
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
33
47
|
}
|
|
34
48
|
//#endregion
|
|
35
|
-
//#region \0@oxc-project+runtime@0.
|
|
49
|
+
//#region \0@oxc-project+runtime@0.130.0/helpers/defineProperty.js
|
|
36
50
|
function _defineProperty(e, r, t) {
|
|
37
51
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
38
52
|
value: t,
|
|
@@ -188,4 +202,113 @@ var ExcalidrawErrorBoundary = class extends Component {
|
|
|
188
202
|
}
|
|
189
203
|
};
|
|
190
204
|
//#endregion
|
|
191
|
-
|
|
205
|
+
//#region src/ExcalidrawSSRRenderer.tsx
|
|
206
|
+
var LazyDisplayRenderer = lazy(() => Promise.resolve().then(() => ExcalidrawDisplayRenderer_exports).then((m) => ({ default: m.ExcalidrawDisplayRenderer })));
|
|
207
|
+
var ExcalidrawPlaceholder = ({ snapshot }) => {
|
|
208
|
+
let label = "Excalidraw Whiteboard";
|
|
209
|
+
try {
|
|
210
|
+
const data = JSON.parse(snapshot);
|
|
211
|
+
if (data && typeof data === "object") {
|
|
212
|
+
const elementCount = Array.isArray(data.elements) ? data.elements.length : 0;
|
|
213
|
+
if (elementCount > 0) label = `Excalidraw Whiteboard (${elementCount} elements)`;
|
|
214
|
+
}
|
|
215
|
+
} catch {}
|
|
216
|
+
return /* @__PURE__ */ jsx("div", {
|
|
217
|
+
"aria-label": label,
|
|
218
|
+
className: excalidrawPlaceholder,
|
|
219
|
+
children: /* @__PURE__ */ jsx("span", { children: label })
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
var ExcalidrawSSRRenderer = ({ onExpand, snapshot }) => {
|
|
223
|
+
return /* @__PURE__ */ jsx(ViewportGate, {
|
|
224
|
+
fallback: /* @__PURE__ */ jsx(ExcalidrawPlaceholder, { snapshot }),
|
|
225
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
226
|
+
fallback: /* @__PURE__ */ jsx(ExcalidrawPlaceholder, { snapshot }),
|
|
227
|
+
children: /* @__PURE__ */ jsx(LazyDisplayRenderer, {
|
|
228
|
+
snapshot,
|
|
229
|
+
onExpand
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/slot.ts
|
|
236
|
+
var EXCALIDRAW_NODE_KEY = "Excalidraw";
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/ExcalidrawNode.ts
|
|
239
|
+
var ExcalidrawNode = class ExcalidrawNode extends DecoratorNode {
|
|
240
|
+
static getType() {
|
|
241
|
+
return "excalidraw";
|
|
242
|
+
}
|
|
243
|
+
static clone(node) {
|
|
244
|
+
return new ExcalidrawNode(node.__snapshot, node.__key);
|
|
245
|
+
}
|
|
246
|
+
constructor(snapshot, key) {
|
|
247
|
+
super(key);
|
|
248
|
+
_defineProperty(this, "__snapshot", void 0);
|
|
249
|
+
this.__snapshot = snapshot;
|
|
250
|
+
}
|
|
251
|
+
createDOM(_config) {
|
|
252
|
+
const div = document.createElement("div");
|
|
253
|
+
div.className = "rich-excalidraw-wrapper";
|
|
254
|
+
return div;
|
|
255
|
+
}
|
|
256
|
+
updateDOM() {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
isInline() {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
static importJSON(serializedNode) {
|
|
263
|
+
return $createExcalidrawNode(serializedNode.snapshot);
|
|
264
|
+
}
|
|
265
|
+
exportJSON() {
|
|
266
|
+
return {
|
|
267
|
+
...super.exportJSON(),
|
|
268
|
+
type: "excalidraw",
|
|
269
|
+
snapshot: this.__snapshot,
|
|
270
|
+
version: 1
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
getSnapshot() {
|
|
274
|
+
return this.__snapshot;
|
|
275
|
+
}
|
|
276
|
+
setSnapshot(snapshot) {
|
|
277
|
+
const writable = this.getWritable();
|
|
278
|
+
writable.__snapshot = snapshot;
|
|
279
|
+
}
|
|
280
|
+
decorate(_editor, _config) {
|
|
281
|
+
return createRendererDecoration(EXCALIDRAW_NODE_KEY, ExcalidrawSSRRenderer, { snapshot: this.__snapshot });
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
function $createExcalidrawNode(snapshot) {
|
|
285
|
+
return new ExcalidrawNode(snapshot);
|
|
286
|
+
}
|
|
287
|
+
function $isExcalidrawNode(node) {
|
|
288
|
+
return node instanceof ExcalidrawNode;
|
|
289
|
+
}
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/ExcalidrawExpandShell.tsx
|
|
292
|
+
var ExcalidrawExpandShell = ({ children, dismiss, meta = "excalidraw", title = "Whiteboard" }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
293
|
+
className: excalidrawDialogHeader,
|
|
294
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className: excalidrawDialogHeaderTitle,
|
|
296
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
297
|
+
className: excalidrawDialogTitle,
|
|
298
|
+
children: title
|
|
299
|
+
}), meta != null && /* @__PURE__ */ jsx("span", {
|
|
300
|
+
className: "_1c3wdzld",
|
|
301
|
+
children: meta
|
|
302
|
+
})]
|
|
303
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
304
|
+
className: excalidrawHeaderClose,
|
|
305
|
+
type: "button",
|
|
306
|
+
onClick: dismiss,
|
|
307
|
+
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
308
|
+
})]
|
|
309
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
310
|
+
className: excalidrawDialogCanvas,
|
|
311
|
+
children
|
|
312
|
+
})] });
|
|
313
|
+
//#endregion
|
|
314
|
+
export { ExcalidrawNode as a, ExcalidrawDisplayRenderer as c, __exportAll as d, $isExcalidrawNode as i, ExcalidrawDisplayRenderer_exports as l, ExcalidrawExpandShell as n, EXCALIDRAW_NODE_KEY as o, $createExcalidrawNode as r, ExcalidrawSSRRenderer as s, EXCALIDRAW_BLOCK_TRANSFORMER as t, _defineProperty as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haklex/rich-ext-excalidraw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Excalidraw whiteboard extension",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,23 +25,23 @@
|
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"jsondiffpatch": "^0.7.
|
|
29
|
-
"@haklex/rich-headless": "0.
|
|
28
|
+
"jsondiffpatch": "^0.7.6",
|
|
29
|
+
"@haklex/rich-headless": "0.15.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@excalidraw/excalidraw": "^0.18.0",
|
|
33
33
|
"@lexical/react": "^0.44.0",
|
|
34
|
-
"@types/react": "^19.2.
|
|
34
|
+
"@types/react": "^19.2.15",
|
|
35
35
|
"@types/react-dom": "^19.2.3",
|
|
36
36
|
"@vanilla-extract/css": "^1.20.1",
|
|
37
37
|
"@vanilla-extract/vite-plugin": "^5.2.2",
|
|
38
38
|
"lexical": "^0.44.0",
|
|
39
|
-
"lucide-react": "^1.
|
|
39
|
+
"lucide-react": "^1.16.0",
|
|
40
40
|
"react": "19.2.5",
|
|
41
41
|
"react-dom": "19.2.5",
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
|
-
"
|
|
44
|
-
"vite
|
|
43
|
+
"unplugin-dts": "^1.0.1",
|
|
44
|
+
"vite": "^8.0.13"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@excalidraw/excalidraw": ">=0.18.0",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"lucide-react": "^1.0.0",
|
|
51
51
|
"react": ">=19",
|
|
52
52
|
"react-dom": ">=19",
|
|
53
|
-
"@haklex/rich-editor": "0.
|
|
54
|
-
"@haklex/rich-editor-ui": "0.
|
|
55
|
-
"@haklex/rich-style-token": "0.
|
|
53
|
+
"@haklex/rich-editor": "0.15.0",
|
|
54
|
+
"@haklex/rich-editor-ui": "0.15.0",
|
|
55
|
+
"@haklex/rich-style-token": "0.15.0"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
|
|
2
|
-
import { C as excalidrawHeaderActions, O as excalidrawStatusDot, S as excalidrawFullscreenPopup, T as excalidrawLoading, _ as excalidrawDialogTitle, b as excalidrawEditorContainer, d as excalidrawConfirmBtnDanger, f as excalidrawConfirmBtnPrimary, g as excalidrawDialogMeta, i as excalidrawActionBarBtn, j as useExcalidrawConfig, k as readonlyUIOptions, l as excalidrawConfirmActions, m as excalidrawDialogHeader, p as excalidrawDialogCanvas, t as useExcalidrawData, u as excalidrawConfirmBtn, v as excalidrawEditLabel, w as excalidrawHeaderClose, x as excalidrawError, y as excalidrawEditOverlay } from "./useExcalidrawData-DcXa8vqV.js";
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import { useColorScheme } from "@haklex/rich-editor";
|
|
6
|
-
import { Clipboard, Download, Pencil, Save, X } from "lucide-react";
|
|
7
|
-
import { SegmentedControl, dismissTopDialog, presentDialog } from "@haklex/rich-editor-ui";
|
|
8
|
-
import { usePortalTheme } from "@haklex/rich-style-token";
|
|
9
|
-
//#region src/ExcalidrawEditRenderer.tsx
|
|
10
|
-
var ExcalidrawEditRenderer_exports = /* @__PURE__ */ __exportAll({ ExcalidrawEditRenderer: () => ExcalidrawEditRenderer });
|
|
11
|
-
var SAVE_DEBOUNCE_MS = 2e3;
|
|
12
|
-
var ExcalidrawEditorDialogContent = ({ dismiss, ExcalidrawComponent, initialData, initialSnapshot, theme, onSave, saveSnapshot, onClose, baseRef, baseData }) => {
|
|
13
|
-
const { className: portalClassName } = usePortalTheme();
|
|
14
|
-
const apiRef = useRef(null);
|
|
15
|
-
const saveTimerRef = useRef(void 0);
|
|
16
|
-
const [isDirty, setIsDirty] = useState(false);
|
|
17
|
-
const isDirtyRef = useRef(false);
|
|
18
|
-
const confirmDialogOpenRef = useRef(false);
|
|
19
|
-
const initializedRef = useRef(false);
|
|
20
|
-
const stableRef = useRef(false);
|
|
21
|
-
const baseRefRef = useRef(baseRef);
|
|
22
|
-
const baseDataRef = useRef(baseData);
|
|
23
|
-
const [storageMode, setStorageMode] = useState(() => {
|
|
24
|
-
if (!saveSnapshot || !initialSnapshot) return "inline";
|
|
25
|
-
return initialSnapshot.type === "delta" ? "delta" : initialSnapshot.type === "remote" ? "remote" : "inline";
|
|
26
|
-
});
|
|
27
|
-
const storageModeRef = useRef(storageMode);
|
|
28
|
-
const [savedRef, setSavedRef] = useState(() => {
|
|
29
|
-
if (!saveSnapshot || !initialSnapshot) return "";
|
|
30
|
-
if (initialSnapshot.type === "remote") return initialSnapshot.url;
|
|
31
|
-
if (initialSnapshot.type === "delta") return initialSnapshot.baseUrl;
|
|
32
|
-
return "";
|
|
33
|
-
});
|
|
34
|
-
const [isSaving, setIsSaving] = useState(false);
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
const stableTimer = setTimeout(() => {
|
|
37
|
-
stableRef.current = true;
|
|
38
|
-
}, 500);
|
|
39
|
-
return () => {
|
|
40
|
-
clearTimeout(stableTimer);
|
|
41
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
42
|
-
};
|
|
43
|
-
}, []);
|
|
44
|
-
const getSnapshot = useCallback(() => {
|
|
45
|
-
const api = apiRef.current;
|
|
46
|
-
if (!api) return;
|
|
47
|
-
const appState = api.getAppState();
|
|
48
|
-
return {
|
|
49
|
-
elements: api.getSceneElements(),
|
|
50
|
-
appState: {
|
|
51
|
-
viewBackgroundColor: appState.viewBackgroundColor,
|
|
52
|
-
gridSize: appState.gridSize
|
|
53
|
-
},
|
|
54
|
-
files: api.getFiles()
|
|
55
|
-
};
|
|
56
|
-
}, []);
|
|
57
|
-
const performSave = useCallback(() => {
|
|
58
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
59
|
-
const doc = getSnapshot();
|
|
60
|
-
if (!doc) return Promise.resolve();
|
|
61
|
-
const mode = storageModeRef.current;
|
|
62
|
-
if (mode === "delta" && saveSnapshot) {
|
|
63
|
-
setIsSaving(true);
|
|
64
|
-
return (async () => {
|
|
65
|
-
try {
|
|
66
|
-
const currentBaseUrl = baseRefRef.current;
|
|
67
|
-
const currentBaseData = baseDataRef.current;
|
|
68
|
-
if (!currentBaseUrl || !currentBaseData) {
|
|
69
|
-
const ref = await saveSnapshot(doc, baseRefRef.current || void 0);
|
|
70
|
-
baseRefRef.current = ref;
|
|
71
|
-
baseDataRef.current = doc;
|
|
72
|
-
setSavedRef(ref);
|
|
73
|
-
}
|
|
74
|
-
isDirtyRef.current = false;
|
|
75
|
-
setIsDirty(false);
|
|
76
|
-
} finally {
|
|
77
|
-
setIsSaving(false);
|
|
78
|
-
}
|
|
79
|
-
})();
|
|
80
|
-
}
|
|
81
|
-
if (mode === "remote" && saveSnapshot) {
|
|
82
|
-
if (baseRefRef.current && baseDataRef.current && JSON.stringify(doc) === JSON.stringify(baseDataRef.current)) {
|
|
83
|
-
isDirtyRef.current = false;
|
|
84
|
-
setIsDirty(false);
|
|
85
|
-
return Promise.resolve();
|
|
86
|
-
}
|
|
87
|
-
setIsSaving(true);
|
|
88
|
-
return saveSnapshot(doc, baseRefRef.current || void 0).then((ref) => {
|
|
89
|
-
baseRefRef.current = ref;
|
|
90
|
-
baseDataRef.current = doc;
|
|
91
|
-
isDirtyRef.current = false;
|
|
92
|
-
setIsDirty(false);
|
|
93
|
-
setIsSaving(false);
|
|
94
|
-
setSavedRef(ref);
|
|
95
|
-
}, () => {
|
|
96
|
-
setIsSaving(false);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
isDirtyRef.current = false;
|
|
100
|
-
setIsDirty(false);
|
|
101
|
-
return Promise.resolve();
|
|
102
|
-
}, [saveSnapshot, getSnapshot]);
|
|
103
|
-
const emitSnapshot = useCallback(async () => {
|
|
104
|
-
const doc = getSnapshot();
|
|
105
|
-
if (!doc) return;
|
|
106
|
-
const mode = storageModeRef.current;
|
|
107
|
-
if (mode === "delta" && saveSnapshot) {
|
|
108
|
-
const currentBaseUrl = baseRefRef.current;
|
|
109
|
-
const currentBaseData = baseDataRef.current;
|
|
110
|
-
if (currentBaseUrl && currentBaseData) {
|
|
111
|
-
const { diff } = await import("jsondiffpatch");
|
|
112
|
-
const delta = diff(currentBaseData, structuredClone(doc));
|
|
113
|
-
onSave(delta ? {
|
|
114
|
-
type: "delta",
|
|
115
|
-
baseUrl: currentBaseUrl,
|
|
116
|
-
delta
|
|
117
|
-
} : {
|
|
118
|
-
type: "remote",
|
|
119
|
-
url: currentBaseUrl
|
|
120
|
-
});
|
|
121
|
-
} else onSave({
|
|
122
|
-
type: "remote",
|
|
123
|
-
url: await saveSnapshot(doc, baseRefRef.current || void 0)
|
|
124
|
-
});
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (mode === "remote") {
|
|
128
|
-
const ref = baseRefRef.current;
|
|
129
|
-
if (ref) onSave({
|
|
130
|
-
type: "remote",
|
|
131
|
-
url: ref
|
|
132
|
-
});
|
|
133
|
-
else if (saveSnapshot) onSave({
|
|
134
|
-
type: "remote",
|
|
135
|
-
url: await saveSnapshot(doc)
|
|
136
|
-
});
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
onSave({
|
|
140
|
-
type: "inline",
|
|
141
|
-
data: doc
|
|
142
|
-
});
|
|
143
|
-
}, [
|
|
144
|
-
onSave,
|
|
145
|
-
saveSnapshot,
|
|
146
|
-
getSnapshot
|
|
147
|
-
]);
|
|
148
|
-
const handleChange = useCallback((elements) => {
|
|
149
|
-
if (!initializedRef.current) {
|
|
150
|
-
initializedRef.current = true;
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (!stableRef.current) return;
|
|
154
|
-
if (elements.length === 0) return;
|
|
155
|
-
if (!isDirtyRef.current) {
|
|
156
|
-
isDirtyRef.current = true;
|
|
157
|
-
setIsDirty(true);
|
|
158
|
-
}
|
|
159
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
160
|
-
saveTimerRef.current = setTimeout(() => performSave(), SAVE_DEBOUNCE_MS);
|
|
161
|
-
}, [performSave]);
|
|
162
|
-
const handleSaveAndClose = useCallback(() => {
|
|
163
|
-
performSave().then(async () => {
|
|
164
|
-
await emitSnapshot();
|
|
165
|
-
onClose(getSnapshot());
|
|
166
|
-
dismiss();
|
|
167
|
-
});
|
|
168
|
-
}, [
|
|
169
|
-
performSave,
|
|
170
|
-
emitSnapshot,
|
|
171
|
-
getSnapshot,
|
|
172
|
-
onClose,
|
|
173
|
-
dismiss
|
|
174
|
-
]);
|
|
175
|
-
const handleDiscard = useCallback(() => {
|
|
176
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
177
|
-
dismiss();
|
|
178
|
-
}, [dismiss]);
|
|
179
|
-
const showConfirmDialog = useCallback(() => {
|
|
180
|
-
if (confirmDialogOpenRef.current) return;
|
|
181
|
-
confirmDialogOpenRef.current = true;
|
|
182
|
-
presentDialog({
|
|
183
|
-
title: "Unsaved Changes",
|
|
184
|
-
description: "You have unsaved changes that will be lost if you close now.",
|
|
185
|
-
content: ({ dismiss: dismissConfirm }) => {
|
|
186
|
-
const wrappedDismiss = () => {
|
|
187
|
-
confirmDialogOpenRef.current = false;
|
|
188
|
-
dismissConfirm();
|
|
189
|
-
};
|
|
190
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
191
|
-
className: excalidrawConfirmActions,
|
|
192
|
-
children: [
|
|
193
|
-
/* @__PURE__ */ jsx("button", {
|
|
194
|
-
className: excalidrawConfirmBtn,
|
|
195
|
-
type: "button",
|
|
196
|
-
onClick: wrappedDismiss,
|
|
197
|
-
children: "Continue Editing"
|
|
198
|
-
}),
|
|
199
|
-
/* @__PURE__ */ jsx("button", {
|
|
200
|
-
className: excalidrawConfirmBtnDanger,
|
|
201
|
-
type: "button",
|
|
202
|
-
onClick: () => {
|
|
203
|
-
wrappedDismiss();
|
|
204
|
-
handleDiscard();
|
|
205
|
-
},
|
|
206
|
-
children: "Discard"
|
|
207
|
-
}),
|
|
208
|
-
/* @__PURE__ */ jsx("button", {
|
|
209
|
-
className: excalidrawConfirmBtnPrimary,
|
|
210
|
-
type: "button",
|
|
211
|
-
onClick: () => {
|
|
212
|
-
wrappedDismiss();
|
|
213
|
-
handleSaveAndClose();
|
|
214
|
-
},
|
|
215
|
-
children: "Save & Close"
|
|
216
|
-
})
|
|
217
|
-
]
|
|
218
|
-
});
|
|
219
|
-
},
|
|
220
|
-
portalClassName,
|
|
221
|
-
theme,
|
|
222
|
-
showCloseButton: false,
|
|
223
|
-
clickOutsideToDismiss: false
|
|
224
|
-
});
|
|
225
|
-
}, [
|
|
226
|
-
handleDiscard,
|
|
227
|
-
handleSaveAndClose,
|
|
228
|
-
portalClassName,
|
|
229
|
-
theme
|
|
230
|
-
]);
|
|
231
|
-
const attemptClose = useCallback(() => {
|
|
232
|
-
if (isDirtyRef.current) showConfirmDialog();
|
|
233
|
-
else emitSnapshot().then(() => {
|
|
234
|
-
onClose(getSnapshot());
|
|
235
|
-
dismiss();
|
|
236
|
-
});
|
|
237
|
-
}, [
|
|
238
|
-
dismiss,
|
|
239
|
-
showConfirmDialog,
|
|
240
|
-
emitSnapshot,
|
|
241
|
-
getSnapshot,
|
|
242
|
-
onClose
|
|
243
|
-
]);
|
|
244
|
-
useEffect(() => {
|
|
245
|
-
const handleKeyDown = (e) => {
|
|
246
|
-
if (e.key === "Escape") {
|
|
247
|
-
e.preventDefault();
|
|
248
|
-
e.stopImmediatePropagation();
|
|
249
|
-
if (confirmDialogOpenRef.current) {
|
|
250
|
-
confirmDialogOpenRef.current = false;
|
|
251
|
-
dismissTopDialog();
|
|
252
|
-
} else attemptClose();
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
document.addEventListener("keydown", handleKeyDown, true);
|
|
256
|
-
return () => document.removeEventListener("keydown", handleKeyDown, true);
|
|
257
|
-
}, [attemptClose]);
|
|
258
|
-
const handleManualUpload = useCallback(() => {
|
|
259
|
-
performSave();
|
|
260
|
-
}, [performSave]);
|
|
261
|
-
const handleExportJson = useCallback(() => {
|
|
262
|
-
const doc = getSnapshot();
|
|
263
|
-
if (!doc) return;
|
|
264
|
-
const blob = new Blob([JSON.stringify(doc, null, 2)], { type: "application/json" });
|
|
265
|
-
const url = URL.createObjectURL(blob);
|
|
266
|
-
const a = document.createElement("a");
|
|
267
|
-
a.href = url;
|
|
268
|
-
a.download = "excalidraw-snapshot.json";
|
|
269
|
-
a.click();
|
|
270
|
-
URL.revokeObjectURL(url);
|
|
271
|
-
}, [getSnapshot]);
|
|
272
|
-
const handleCopyJson = useCallback(() => {
|
|
273
|
-
const doc = getSnapshot();
|
|
274
|
-
if (!doc) return;
|
|
275
|
-
navigator.clipboard.writeText(JSON.stringify(doc));
|
|
276
|
-
}, [getSnapshot]);
|
|
277
|
-
const handleRefChange = useCallback((e) => {
|
|
278
|
-
const { value } = e.target;
|
|
279
|
-
setSavedRef(value);
|
|
280
|
-
baseRefRef.current = value;
|
|
281
|
-
baseDataRef.current = void 0;
|
|
282
|
-
}, []);
|
|
283
|
-
const handleStorageModeChange = useCallback((newMode) => {
|
|
284
|
-
setStorageMode(newMode);
|
|
285
|
-
storageModeRef.current = newMode;
|
|
286
|
-
if (newMode === "inline") setSavedRef("");
|
|
287
|
-
performSave();
|
|
288
|
-
}, [performSave]);
|
|
289
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
290
|
-
className: excalidrawDialogHeader,
|
|
291
|
-
children: [
|
|
292
|
-
/* @__PURE__ */ jsx("span", {
|
|
293
|
-
className: excalidrawStatusDot,
|
|
294
|
-
style: { backgroundColor: isDirty ? "#f59e0b" : "#22c55e" }
|
|
295
|
-
}),
|
|
296
|
-
/* @__PURE__ */ jsx("span", {
|
|
297
|
-
className: excalidrawDialogTitle,
|
|
298
|
-
children: "Canvas Editor"
|
|
299
|
-
}),
|
|
300
|
-
/* @__PURE__ */ jsx("span", {
|
|
301
|
-
className: excalidrawDialogMeta,
|
|
302
|
-
children: "excalidraw"
|
|
303
|
-
}),
|
|
304
|
-
/* @__PURE__ */ jsxs("div", {
|
|
305
|
-
className: excalidrawHeaderActions,
|
|
306
|
-
children: [
|
|
307
|
-
saveSnapshot && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
308
|
-
/* @__PURE__ */ jsx(SegmentedControl, {
|
|
309
|
-
value: storageMode,
|
|
310
|
-
items: [
|
|
311
|
-
{
|
|
312
|
-
value: "inline",
|
|
313
|
-
label: "Inline"
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
value: "remote",
|
|
317
|
-
label: "Remote"
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
value: "delta",
|
|
321
|
-
label: "Delta"
|
|
322
|
-
}
|
|
323
|
-
],
|
|
324
|
-
onChange: handleStorageModeChange
|
|
325
|
-
}),
|
|
326
|
-
/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" }),
|
|
327
|
-
/* @__PURE__ */ jsxs("button", {
|
|
328
|
-
className: "_1c3wdzlg",
|
|
329
|
-
disabled: isSaving,
|
|
330
|
-
type: "button",
|
|
331
|
-
onClick: handleManualUpload,
|
|
332
|
-
children: [/* @__PURE__ */ jsx(Save, { size: 14 }), /* @__PURE__ */ jsx("span", { children: isSaving ? "Saving..." : "Save" })]
|
|
333
|
-
}),
|
|
334
|
-
/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" })
|
|
335
|
-
] }),
|
|
336
|
-
/* @__PURE__ */ jsxs("button", {
|
|
337
|
-
className: excalidrawActionBarBtn,
|
|
338
|
-
type: "button",
|
|
339
|
-
onClick: handleExportJson,
|
|
340
|
-
children: [/* @__PURE__ */ jsx(Download, { size: 14 }), "JSON"]
|
|
341
|
-
}),
|
|
342
|
-
/* @__PURE__ */ jsxs("button", {
|
|
343
|
-
className: excalidrawActionBarBtn,
|
|
344
|
-
type: "button",
|
|
345
|
-
onClick: handleCopyJson,
|
|
346
|
-
children: [/* @__PURE__ */ jsx(Clipboard, { size: 14 }), "Copy"]
|
|
347
|
-
}),
|
|
348
|
-
storageMode !== "inline" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", { className: "_1c3wdzlh" }), /* @__PURE__ */ jsx("input", {
|
|
349
|
-
className: "_1c3wdzli",
|
|
350
|
-
placeholder: "base URL / ref",
|
|
351
|
-
spellCheck: false,
|
|
352
|
-
type: "text",
|
|
353
|
-
value: savedRef,
|
|
354
|
-
onChange: handleRefChange
|
|
355
|
-
})] })
|
|
356
|
-
]
|
|
357
|
-
}),
|
|
358
|
-
/* @__PURE__ */ jsx("button", {
|
|
359
|
-
className: excalidrawHeaderClose,
|
|
360
|
-
type: "button",
|
|
361
|
-
onClick: attemptClose,
|
|
362
|
-
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
363
|
-
})
|
|
364
|
-
]
|
|
365
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
366
|
-
className: excalidrawDialogCanvas,
|
|
367
|
-
children: /* @__PURE__ */ jsx(ExcalidrawComponent, {
|
|
368
|
-
initialData,
|
|
369
|
-
theme,
|
|
370
|
-
excalidrawAPI: (api) => {
|
|
371
|
-
apiRef.current = api;
|
|
372
|
-
},
|
|
373
|
-
onChange: handleChange
|
|
374
|
-
})
|
|
375
|
-
})] });
|
|
376
|
-
};
|
|
377
|
-
var ExcalidrawEditRenderer = ({ snapshot, onSnapshotChange }) => {
|
|
378
|
-
const theme = useColorScheme();
|
|
379
|
-
const { saveSnapshot } = useExcalidrawConfig();
|
|
380
|
-
const { snapshot: initialData, loading: dataLoading, error: dataError, baseRef, baseData } = useExcalidrawData(snapshot);
|
|
381
|
-
const [ExcalidrawComponent, setExcalidrawComponent] = useState(null);
|
|
382
|
-
const [libLoading, setLibLoading] = useState(true);
|
|
383
|
-
const previewApiRef = useRef(null);
|
|
384
|
-
const initialDataRef = useRef(void 0);
|
|
385
|
-
const [previewKey, setPreviewKey] = useState(0);
|
|
386
|
-
const onSnapshotChangeRef = useRef(onSnapshotChange);
|
|
387
|
-
onSnapshotChangeRef.current = onSnapshotChange;
|
|
388
|
-
const saveSnapshotRef = useRef(saveSnapshot);
|
|
389
|
-
saveSnapshotRef.current = saveSnapshot;
|
|
390
|
-
const snapshotRef = useRef(snapshot);
|
|
391
|
-
snapshotRef.current = snapshot;
|
|
392
|
-
const { className: portalClassName } = usePortalTheme();
|
|
393
|
-
useEffect(() => {
|
|
394
|
-
if (initialData && !initialDataRef.current) initialDataRef.current = initialData;
|
|
395
|
-
}, [initialData]);
|
|
396
|
-
useEffect(() => {
|
|
397
|
-
Promise.all([import("@excalidraw/excalidraw"), import("@excalidraw/excalidraw/index.css")]).then(([mod]) => {
|
|
398
|
-
const Comp = mod.Excalidraw || mod.default?.Excalidraw;
|
|
399
|
-
if (Comp) setExcalidrawComponent(() => Comp);
|
|
400
|
-
setLibLoading(false);
|
|
401
|
-
}).catch((err) => {
|
|
402
|
-
console.error("[excalidraw] failed to load", err);
|
|
403
|
-
setLibLoading(false);
|
|
404
|
-
});
|
|
405
|
-
}, []);
|
|
406
|
-
const baseRefRef = useRef(baseRef);
|
|
407
|
-
const baseDataRefOuter = useRef(baseData);
|
|
408
|
-
useEffect(() => {
|
|
409
|
-
if (baseRef) baseRefRef.current = baseRef;
|
|
410
|
-
}, [baseRef]);
|
|
411
|
-
useEffect(() => {
|
|
412
|
-
if (baseData) baseDataRefOuter.current = baseData;
|
|
413
|
-
}, [baseData]);
|
|
414
|
-
const handleOpenEditor = useCallback(() => {
|
|
415
|
-
if (!ExcalidrawComponent || dataLoading) return;
|
|
416
|
-
presentDialog({
|
|
417
|
-
content: ({ dismiss }) => /* @__PURE__ */ jsx(ExcalidrawEditorDialogContent, {
|
|
418
|
-
ExcalidrawComponent,
|
|
419
|
-
baseData: baseDataRefOuter.current,
|
|
420
|
-
baseRef: baseRefRef.current,
|
|
421
|
-
dismiss,
|
|
422
|
-
initialData: initialDataRef.current,
|
|
423
|
-
initialSnapshot: snapshotRef.current,
|
|
424
|
-
saveSnapshot: saveSnapshotRef.current,
|
|
425
|
-
theme,
|
|
426
|
-
onSave: (ref) => onSnapshotChangeRef.current(ref),
|
|
427
|
-
onClose: (doc) => {
|
|
428
|
-
if (doc) {
|
|
429
|
-
initialDataRef.current = doc;
|
|
430
|
-
setPreviewKey((k) => k + 1);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}),
|
|
434
|
-
className: excalidrawFullscreenPopup,
|
|
435
|
-
portalClassName,
|
|
436
|
-
theme,
|
|
437
|
-
showCloseButton: false,
|
|
438
|
-
clickOutsideToDismiss: false
|
|
439
|
-
});
|
|
440
|
-
}, [
|
|
441
|
-
ExcalidrawComponent,
|
|
442
|
-
dataLoading,
|
|
443
|
-
theme,
|
|
444
|
-
portalClassName
|
|
445
|
-
]);
|
|
446
|
-
if (dataLoading || libLoading || !ExcalidrawComponent) return /* @__PURE__ */ jsx("div", {
|
|
447
|
-
className: excalidrawEditorContainer,
|
|
448
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
449
|
-
className: excalidrawLoading,
|
|
450
|
-
children: "Loading excalidraw editor..."
|
|
451
|
-
})
|
|
452
|
-
});
|
|
453
|
-
if (dataError) return /* @__PURE__ */ jsx("div", {
|
|
454
|
-
className: excalidrawEditorContainer,
|
|
455
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
456
|
-
className: excalidrawError,
|
|
457
|
-
children: dataError
|
|
458
|
-
})
|
|
459
|
-
});
|
|
460
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
461
|
-
className: excalidrawEditorContainer,
|
|
462
|
-
children: [/* @__PURE__ */ jsx(ExcalidrawComponent, {
|
|
463
|
-
viewModeEnabled: true,
|
|
464
|
-
zenModeEnabled: true,
|
|
465
|
-
UIOptions: readonlyUIOptions,
|
|
466
|
-
initialData: initialDataRef.current,
|
|
467
|
-
theme,
|
|
468
|
-
excalidrawAPI: (api) => {
|
|
469
|
-
previewApiRef.current = api;
|
|
470
|
-
setTimeout(() => api.scrollToContent(), 100);
|
|
471
|
-
}
|
|
472
|
-
}, previewKey), /* @__PURE__ */ jsx("button", {
|
|
473
|
-
className: excalidrawEditOverlay,
|
|
474
|
-
type: "button",
|
|
475
|
-
onClick: handleOpenEditor,
|
|
476
|
-
children: /* @__PURE__ */ jsxs("span", {
|
|
477
|
-
className: excalidrawEditLabel,
|
|
478
|
-
children: [/* @__PURE__ */ jsx(Pencil, { size: 16 }), "Edit Whiteboard"]
|
|
479
|
-
})
|
|
480
|
-
})]
|
|
481
|
-
});
|
|
482
|
-
};
|
|
483
|
-
//#endregion
|
|
484
|
-
export { ExcalidrawEditRenderer_exports as n, ExcalidrawEditRenderer as t };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) __defProp(target, name, {
|
|
6
|
-
get: all[name],
|
|
7
|
-
enumerable: true
|
|
8
|
-
});
|
|
9
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
-
return target;
|
|
11
|
-
};
|
|
12
|
-
//#endregion
|
|
13
|
-
export { __exportAll as t };
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { E as excalidrawPlaceholder, _ as excalidrawDialogTitle, h as excalidrawDialogHeaderTitle, m as excalidrawDialogHeader, p as excalidrawDialogCanvas, w as excalidrawHeaderClose } from "./useExcalidrawData-DcXa8vqV.js";
|
|
2
|
-
import { r as _defineProperty } from "./ExcalidrawDisplayRenderer-BWsFJSQ7.js";
|
|
3
|
-
import { Suspense, lazy } from "react";
|
|
4
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import { X } from "lucide-react";
|
|
6
|
-
import { ViewportGate } from "@haklex/rich-editor-ui";
|
|
7
|
-
import { DecoratorNode } from "lexical";
|
|
8
|
-
import { createRendererDecoration } from "@haklex/rich-editor/static";
|
|
9
|
-
import { EXCALIDRAW_BLOCK_TRANSFORMER } from "@haklex/rich-headless/transformers";
|
|
10
|
-
//#region src/ExcalidrawSSRRenderer.tsx
|
|
11
|
-
var LazyDisplayRenderer = lazy(() => import("./ExcalidrawDisplayRenderer-BWsFJSQ7.js").then((n) => n.n).then((m) => ({ default: m.ExcalidrawDisplayRenderer })));
|
|
12
|
-
var ExcalidrawPlaceholder = ({ snapshot }) => {
|
|
13
|
-
let label = "Excalidraw Whiteboard";
|
|
14
|
-
try {
|
|
15
|
-
const data = JSON.parse(snapshot);
|
|
16
|
-
if (data && typeof data === "object") {
|
|
17
|
-
const elementCount = Array.isArray(data.elements) ? data.elements.length : 0;
|
|
18
|
-
if (elementCount > 0) label = `Excalidraw Whiteboard (${elementCount} elements)`;
|
|
19
|
-
}
|
|
20
|
-
} catch {}
|
|
21
|
-
return /* @__PURE__ */ jsx("div", {
|
|
22
|
-
"aria-label": label,
|
|
23
|
-
className: excalidrawPlaceholder,
|
|
24
|
-
children: /* @__PURE__ */ jsx("span", { children: label })
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
var ExcalidrawSSRRenderer = ({ onExpand, snapshot }) => {
|
|
28
|
-
return /* @__PURE__ */ jsx(ViewportGate, {
|
|
29
|
-
fallback: /* @__PURE__ */ jsx(ExcalidrawPlaceholder, { snapshot }),
|
|
30
|
-
children: /* @__PURE__ */ jsx(Suspense, {
|
|
31
|
-
fallback: /* @__PURE__ */ jsx(ExcalidrawPlaceholder, { snapshot }),
|
|
32
|
-
children: /* @__PURE__ */ jsx(LazyDisplayRenderer, {
|
|
33
|
-
snapshot,
|
|
34
|
-
onExpand
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/slot.ts
|
|
41
|
-
var EXCALIDRAW_NODE_KEY = "Excalidraw";
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region src/ExcalidrawNode.ts
|
|
44
|
-
var ExcalidrawNode = class ExcalidrawNode extends DecoratorNode {
|
|
45
|
-
static getType() {
|
|
46
|
-
return "excalidraw";
|
|
47
|
-
}
|
|
48
|
-
static clone(node) {
|
|
49
|
-
return new ExcalidrawNode(node.__snapshot, node.__key);
|
|
50
|
-
}
|
|
51
|
-
constructor(snapshot, key) {
|
|
52
|
-
super(key);
|
|
53
|
-
_defineProperty(this, "__snapshot", void 0);
|
|
54
|
-
this.__snapshot = snapshot;
|
|
55
|
-
}
|
|
56
|
-
createDOM(_config) {
|
|
57
|
-
const div = document.createElement("div");
|
|
58
|
-
div.className = "rich-excalidraw-wrapper";
|
|
59
|
-
return div;
|
|
60
|
-
}
|
|
61
|
-
updateDOM() {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
isInline() {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
static importJSON(serializedNode) {
|
|
68
|
-
return $createExcalidrawNode(serializedNode.snapshot);
|
|
69
|
-
}
|
|
70
|
-
exportJSON() {
|
|
71
|
-
return {
|
|
72
|
-
...super.exportJSON(),
|
|
73
|
-
type: "excalidraw",
|
|
74
|
-
snapshot: this.__snapshot,
|
|
75
|
-
version: 1
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
getSnapshot() {
|
|
79
|
-
return this.__snapshot;
|
|
80
|
-
}
|
|
81
|
-
setSnapshot(snapshot) {
|
|
82
|
-
const writable = this.getWritable();
|
|
83
|
-
writable.__snapshot = snapshot;
|
|
84
|
-
}
|
|
85
|
-
decorate(_editor, _config) {
|
|
86
|
-
return createRendererDecoration(EXCALIDRAW_NODE_KEY, ExcalidrawSSRRenderer, { snapshot: this.__snapshot });
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
function $createExcalidrawNode(snapshot) {
|
|
90
|
-
return new ExcalidrawNode(snapshot);
|
|
91
|
-
}
|
|
92
|
-
function $isExcalidrawNode(node) {
|
|
93
|
-
return node instanceof ExcalidrawNode;
|
|
94
|
-
}
|
|
95
|
-
//#endregion
|
|
96
|
-
//#region src/ExcalidrawExpandShell.tsx
|
|
97
|
-
var ExcalidrawExpandShell = ({ children, dismiss, meta = "excalidraw", title = "Whiteboard" }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
98
|
-
className: excalidrawDialogHeader,
|
|
99
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
100
|
-
className: excalidrawDialogHeaderTitle,
|
|
101
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
102
|
-
className: excalidrawDialogTitle,
|
|
103
|
-
children: title
|
|
104
|
-
}), meta != null && /* @__PURE__ */ jsx("span", {
|
|
105
|
-
className: "_1c3wdzld",
|
|
106
|
-
children: meta
|
|
107
|
-
})]
|
|
108
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
109
|
-
className: excalidrawHeaderClose,
|
|
110
|
-
type: "button",
|
|
111
|
-
onClick: dismiss,
|
|
112
|
-
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
113
|
-
})]
|
|
114
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
115
|
-
className: excalidrawDialogCanvas,
|
|
116
|
-
children
|
|
117
|
-
})] });
|
|
118
|
-
//#endregion
|
|
119
|
-
export { ExcalidrawNode as a, $isExcalidrawNode as i, ExcalidrawExpandShell as n, EXCALIDRAW_NODE_KEY as o, $createExcalidrawNode as r, ExcalidrawSSRRenderer as s, EXCALIDRAW_BLOCK_TRANSFORMER as t };
|