@haklex/rich-ext-excalidraw 0.1.1 → 0.3.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.
@@ -0,0 +1,226 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
+ import { D as excalidrawStaticContainer, S as excalidrawFullscreenPopup, T as excalidrawLoading, _ as excalidrawDialogTitle, c as excalidrawActionGroup, g as excalidrawDialogMeta, 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";
3
+ import { Component, useCallback, useEffect, useRef, useState } from "react";
4
+ import { Fragment, jsx, jsxs } 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 { Maximize2, ScanSearch, X, ZoomIn, ZoomOut } from "lucide-react";
9
+ //#region \0@oxc-project+runtime@0.127.0/helpers/typeof.js
10
+ function _typeof(o) {
11
+ "@babel/helpers - typeof";
12
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
13
+ return typeof o;
14
+ } : function(o) {
15
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
16
+ }, _typeof(o);
17
+ }
18
+ //#endregion
19
+ //#region \0@oxc-project+runtime@0.127.0/helpers/toPrimitive.js
20
+ function toPrimitive(t, r) {
21
+ if ("object" != _typeof(t) || !t) return t;
22
+ var e = t[Symbol.toPrimitive];
23
+ if (void 0 !== e) {
24
+ var i = e.call(t, r || "default");
25
+ if ("object" != _typeof(i)) return i;
26
+ throw new TypeError("@@toPrimitive must return a primitive value.");
27
+ }
28
+ return ("string" === r ? String : Number)(t);
29
+ }
30
+ //#endregion
31
+ //#region \0@oxc-project+runtime@0.127.0/helpers/toPropertyKey.js
32
+ function toPropertyKey(t) {
33
+ var i = toPrimitive(t, "string");
34
+ return "symbol" == _typeof(i) ? i : i + "";
35
+ }
36
+ //#endregion
37
+ //#region \0@oxc-project+runtime@0.127.0/helpers/defineProperty.js
38
+ function _defineProperty(e, r, t) {
39
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
40
+ value: t,
41
+ enumerable: !0,
42
+ configurable: !0,
43
+ writable: !0
44
+ }) : e[r] = t, e;
45
+ }
46
+ //#endregion
47
+ //#region src/ExcalidrawDisplayRenderer.tsx
48
+ var ExcalidrawDisplayRenderer_exports = /* @__PURE__ */ __exportAll({ ExcalidrawDisplayRenderer: () => ExcalidrawDisplayRenderer });
49
+ var ExcalidrawDisplayRenderer = ({ snapshot }) => {
50
+ return /* @__PURE__ */ jsx(ExcalidrawStaticCanvas, {
51
+ snapshot,
52
+ theme: useColorScheme()
53
+ });
54
+ };
55
+ var ExcalidrawExpandContent = ({ dismiss, ExcalidrawComponent, data, theme }) => {
56
+ const apiRef = useRef(null);
57
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
58
+ className: excalidrawDialogHeader,
59
+ children: [/* @__PURE__ */ jsxs("div", {
60
+ className: excalidrawDialogHeaderTitle,
61
+ children: [/* @__PURE__ */ jsx("span", {
62
+ className: excalidrawDialogTitle,
63
+ children: "Whiteboard"
64
+ }), /* @__PURE__ */ jsx("span", {
65
+ className: excalidrawDialogMeta,
66
+ children: "excalidraw"
67
+ })]
68
+ }), /* @__PURE__ */ jsx("button", {
69
+ className: excalidrawHeaderClose,
70
+ type: "button",
71
+ onClick: dismiss,
72
+ children: /* @__PURE__ */ jsx(X, { size: 18 })
73
+ })]
74
+ }), /* @__PURE__ */ jsx("div", {
75
+ className: excalidrawDialogCanvas,
76
+ children: /* @__PURE__ */ jsx(ExcalidrawComponent, {
77
+ viewModeEnabled: true,
78
+ zenModeEnabled: true,
79
+ UIOptions: readonlyUIOptions,
80
+ initialData: data,
81
+ theme,
82
+ excalidrawAPI: (api) => {
83
+ apiRef.current = api;
84
+ setTimeout(() => api.scrollToContent(), 100);
85
+ }
86
+ })
87
+ })] });
88
+ };
89
+ var ExcalidrawStaticCanvas = ({ snapshot, theme }) => {
90
+ const { snapshot: data, loading: dataLoading, error: dataError } = useExcalidrawData(snapshot);
91
+ const [ExcalidrawComponent, setExcalidrawComponent] = useState(null);
92
+ const [libLoading, setLibLoading] = useState(true);
93
+ const apiRef = useRef(null);
94
+ const { className: portalClassName } = usePortalTheme();
95
+ useEffect(() => {
96
+ import("@excalidraw/excalidraw").then((mod) => {
97
+ const Comp = mod.Excalidraw;
98
+ if (Comp) setExcalidrawComponent(() => Comp);
99
+ setLibLoading(false);
100
+ }).catch((error) => {
101
+ console.error("Error loading excalidraw", error);
102
+ setLibLoading(false);
103
+ });
104
+ }, []);
105
+ const handleExpand = useCallback(() => {
106
+ if (!ExcalidrawComponent || !data) return;
107
+ presentDialog({
108
+ content: ({ dismiss }) => /* @__PURE__ */ jsx(ExcalidrawExpandContent, {
109
+ ExcalidrawComponent,
110
+ data,
111
+ dismiss,
112
+ theme
113
+ }),
114
+ className: excalidrawFullscreenPopup,
115
+ portalClassName,
116
+ theme,
117
+ showCloseButton: false,
118
+ clickOutsideToDismiss: true
119
+ });
120
+ }, [
121
+ ExcalidrawComponent,
122
+ data,
123
+ theme,
124
+ portalClassName
125
+ ]);
126
+ if (dataLoading || libLoading) return /* @__PURE__ */ jsx("div", {
127
+ className: excalidrawStaticContainer,
128
+ children: /* @__PURE__ */ jsx("div", {
129
+ className: excalidrawLoading,
130
+ children: "Loading excalidraw..."
131
+ })
132
+ });
133
+ if (dataError || !data) return /* @__PURE__ */ jsx("div", {
134
+ className: excalidrawStaticContainer,
135
+ children: /* @__PURE__ */ jsx("div", {
136
+ className: excalidrawError,
137
+ children: dataError || "No data"
138
+ })
139
+ });
140
+ if (!ExcalidrawComponent) return /* @__PURE__ */ jsx("div", {
141
+ className: excalidrawStaticContainer,
142
+ children: /* @__PURE__ */ jsx("div", {
143
+ className: excalidrawError,
144
+ children: "Failed to load excalidraw"
145
+ })
146
+ });
147
+ return /* @__PURE__ */ jsxs("div", {
148
+ suppressHydrationWarning: true,
149
+ className: excalidrawStaticContainer,
150
+ "data-color-scheme": theme,
151
+ "data-theme": theme,
152
+ children: [/* @__PURE__ */ jsx(ExcalidrawErrorBoundary, {
153
+ fallback: /* @__PURE__ */ jsx("div", {
154
+ className: excalidrawError,
155
+ children: "Failed to render excalidraw"
156
+ }),
157
+ children: /* @__PURE__ */ jsx(ExcalidrawComponent, {
158
+ viewModeEnabled: true,
159
+ zenModeEnabled: true,
160
+ UIOptions: readonlyUIOptions,
161
+ initialData: data,
162
+ theme,
163
+ excalidrawAPI: (api) => {
164
+ apiRef.current = api;
165
+ setTimeout(() => api.scrollToContent(), 100);
166
+ }
167
+ })
168
+ }), /* @__PURE__ */ jsxs("div", {
169
+ className: excalidrawActionGroup,
170
+ children: [
171
+ /* @__PURE__ */ jsx("button", {
172
+ className: excalidrawActionButton,
173
+ title: "Zoom In",
174
+ type: "button",
175
+ onClick: () => {
176
+ const api = apiRef.current;
177
+ if (!api) return;
178
+ const zoom = api.getAppState().zoom.value;
179
+ api.updateScene({ appState: { zoom: { value: zoom * 1.25 } } });
180
+ },
181
+ children: /* @__PURE__ */ jsx(ZoomIn, { size: 20 })
182
+ }),
183
+ /* @__PURE__ */ jsx("button", {
184
+ className: excalidrawActionButton,
185
+ title: "Zoom Out",
186
+ type: "button",
187
+ onClick: () => {
188
+ const api = apiRef.current;
189
+ if (!api) return;
190
+ const zoom = api.getAppState().zoom.value;
191
+ api.updateScene({ appState: { zoom: { value: zoom / 1.25 } } });
192
+ },
193
+ children: /* @__PURE__ */ jsx(ZoomOut, { size: 20 })
194
+ }),
195
+ /* @__PURE__ */ jsx("button", {
196
+ className: excalidrawActionButton,
197
+ title: "Fit to Content",
198
+ type: "button",
199
+ onClick: () => apiRef.current?.scrollToContent(),
200
+ children: /* @__PURE__ */ jsx(ScanSearch, { size: 20 })
201
+ }),
202
+ /* @__PURE__ */ jsx("button", {
203
+ className: excalidrawActionButton,
204
+ title: "Expand",
205
+ type: "button",
206
+ onClick: handleExpand,
207
+ children: /* @__PURE__ */ jsx(Maximize2, { size: 20 })
208
+ })
209
+ ]
210
+ })]
211
+ });
212
+ };
213
+ var ExcalidrawErrorBoundary = class extends Component {
214
+ constructor(..._args) {
215
+ super(..._args);
216
+ _defineProperty(this, "state", { hasError: false });
217
+ }
218
+ static getDerivedStateFromError() {
219
+ return { hasError: true };
220
+ }
221
+ render() {
222
+ return this.state.hasError ? this.props.fallback : this.props.children;
223
+ }
224
+ };
225
+ //#endregion
226
+ export { ExcalidrawDisplayRenderer_exports as n, _defineProperty as r, ExcalidrawDisplayRenderer as t };
@@ -0,0 +1,481 @@
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 { SegmentedControl, dismissTopDialog, presentDialog } from "@haklex/rich-editor-ui";
7
+ import { usePortalTheme } from "@haklex/rich-style-token";
8
+ import { Clipboard, Download, Pencil, Save, X } from "lucide-react";
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
+ import("@excalidraw/excalidraw").then((mod) => {
398
+ const Comp = mod.Excalidraw || mod.default?.Excalidraw;
399
+ if (Comp) setExcalidrawComponent(() => Comp);
400
+ setLibLoading(false);
401
+ }).catch(() => setLibLoading(false));
402
+ }, []);
403
+ const baseRefRef = useRef(baseRef);
404
+ const baseDataRefOuter = useRef(baseData);
405
+ useEffect(() => {
406
+ if (baseRef) baseRefRef.current = baseRef;
407
+ }, [baseRef]);
408
+ useEffect(() => {
409
+ if (baseData) baseDataRefOuter.current = baseData;
410
+ }, [baseData]);
411
+ const handleOpenEditor = useCallback(() => {
412
+ if (!ExcalidrawComponent || dataLoading) return;
413
+ presentDialog({
414
+ content: ({ dismiss }) => /* @__PURE__ */ jsx(ExcalidrawEditorDialogContent, {
415
+ ExcalidrawComponent,
416
+ baseData: baseDataRefOuter.current,
417
+ baseRef: baseRefRef.current,
418
+ dismiss,
419
+ initialData: initialDataRef.current,
420
+ initialSnapshot: snapshotRef.current,
421
+ saveSnapshot: saveSnapshotRef.current,
422
+ theme,
423
+ onSave: (ref) => onSnapshotChangeRef.current(ref),
424
+ onClose: (doc) => {
425
+ if (doc) {
426
+ initialDataRef.current = doc;
427
+ setPreviewKey((k) => k + 1);
428
+ }
429
+ }
430
+ }),
431
+ className: excalidrawFullscreenPopup,
432
+ portalClassName,
433
+ theme,
434
+ showCloseButton: false,
435
+ clickOutsideToDismiss: false
436
+ });
437
+ }, [
438
+ ExcalidrawComponent,
439
+ dataLoading,
440
+ theme,
441
+ portalClassName
442
+ ]);
443
+ if (dataLoading || libLoading || !ExcalidrawComponent) return /* @__PURE__ */ jsx("div", {
444
+ className: excalidrawEditorContainer,
445
+ children: /* @__PURE__ */ jsx("div", {
446
+ className: excalidrawLoading,
447
+ children: "Loading excalidraw editor..."
448
+ })
449
+ });
450
+ if (dataError) return /* @__PURE__ */ jsx("div", {
451
+ className: excalidrawEditorContainer,
452
+ children: /* @__PURE__ */ jsx("div", {
453
+ className: excalidrawError,
454
+ children: dataError
455
+ })
456
+ });
457
+ return /* @__PURE__ */ jsxs("div", {
458
+ className: excalidrawEditorContainer,
459
+ children: [/* @__PURE__ */ jsx(ExcalidrawComponent, {
460
+ viewModeEnabled: true,
461
+ zenModeEnabled: true,
462
+ UIOptions: readonlyUIOptions,
463
+ initialData: initialDataRef.current,
464
+ theme,
465
+ excalidrawAPI: (api) => {
466
+ previewApiRef.current = api;
467
+ setTimeout(() => api.scrollToContent(), 100);
468
+ }
469
+ }, previewKey), /* @__PURE__ */ jsx("button", {
470
+ className: excalidrawEditOverlay,
471
+ type: "button",
472
+ onClick: handleOpenEditor,
473
+ children: /* @__PURE__ */ jsxs("span", {
474
+ className: excalidrawEditLabel,
475
+ children: [/* @__PURE__ */ jsx(Pencil, { size: 16 }), "Edit Whiteboard"]
476
+ })
477
+ })]
478
+ });
479
+ };
480
+ //#endregion
481
+ export { ExcalidrawEditRenderer_exports as n, ExcalidrawEditRenderer as t };