rita-workspace 0.5.27 → 0.5.28

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.
Files changed (3) hide show
  1. package/dist/index.js +122 -19
  2. package/dist/index.mjs +122 -19
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -432,19 +432,34 @@ function useWorkspaceLang() {
432
432
  return { lang: context.lang, t: context.t };
433
433
  }
434
434
  var TAB_ID_KEY = "rita-workspace-tab-id";
435
+ var TAB_ENTRY_KEY = "rita-workspace-tab-entry";
436
+ function generateFreshTabId() {
437
+ return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
438
+ }
435
439
  var TAB_ID = (() => {
436
440
  try {
437
441
  const existing = sessionStorage.getItem(TAB_ID_KEY);
438
442
  if (existing) return existing;
439
443
  } catch {
440
444
  }
441
- const fresh = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
445
+ const fresh = generateFreshTabId();
442
446
  try {
443
447
  sessionStorage.setItem(TAB_ID_KEY, fresh);
444
448
  } catch {
445
449
  }
446
450
  return fresh;
447
451
  })();
452
+ function regenerateTabId() {
453
+ TAB_ID = generateFreshTabId();
454
+ try {
455
+ sessionStorage.setItem(TAB_ID_KEY, TAB_ID);
456
+ } catch {
457
+ }
458
+ try {
459
+ sessionStorage.removeItem(TAB_ENTRY_KEY);
460
+ } catch {
461
+ }
462
+ }
448
463
  var TABS_KEY = "rita-workspace-tabs";
449
464
  var TAB_CHANNEL = "rita-workspace-tabs";
450
465
  function broadcastWorkspaceChange() {
@@ -477,7 +492,6 @@ function getTabsMap() {
477
492
  return {};
478
493
  }
479
494
  }
480
- var TAB_ENTRY_KEY = "rita-workspace-tab-entry";
481
495
  function setTabDrawing(drawingId) {
482
496
  const tabs = getTabsMap();
483
497
  if (drawingId) {
@@ -516,6 +530,28 @@ function isDrawingOpenedEarlierInOtherTab(drawingId) {
516
530
  ([tabId, entry]) => tabId !== TAB_ID && entry.drawingId === drawingId && entry.openedAt <= myOpenedAt
517
531
  );
518
532
  }
533
+ function detectTabIdCollision() {
534
+ return new Promise((resolve) => {
535
+ let channel;
536
+ try {
537
+ channel = new BroadcastChannel(TAB_CHANNEL);
538
+ } catch {
539
+ resolve(false);
540
+ return;
541
+ }
542
+ let collided = false;
543
+ channel.onmessage = (event) => {
544
+ if (event.data?.type === "id-collision" && event.data?.tabId === TAB_ID) {
545
+ collided = true;
546
+ }
547
+ };
548
+ channel.postMessage({ type: "id-claim", tabId: TAB_ID });
549
+ setTimeout(() => {
550
+ channel.close();
551
+ resolve(collided);
552
+ }, 300);
553
+ });
554
+ }
519
555
  function cleanupStaleTabs() {
520
556
  const tabs = getTabsMap();
521
557
  const otherTabIds = Object.keys(tabs).filter((id) => id !== TAB_ID);
@@ -597,6 +633,8 @@ function WorkspaceProvider({ children, lang = "en" }) {
597
633
  channel.onmessage = (event) => {
598
634
  if (event.data?.type === "ping") {
599
635
  channel?.postMessage({ type: "pong", tabId: TAB_ID });
636
+ } else if (event.data?.type === "id-claim" && event.data?.tabId === TAB_ID) {
637
+ channel?.postMessage({ type: "id-collision", tabId: TAB_ID });
600
638
  } else if (event.data?.type === "workspace-changed" && event.data?.tabId !== TAB_ID) {
601
639
  refreshDrawingsRef.current();
602
640
  }
@@ -608,18 +646,32 @@ function WorkspaceProvider({ children, lang = "en" }) {
608
646
  };
609
647
  }, []);
610
648
  const hasCleanedUpRef = (0, import_react.useRef)(false);
649
+ const [tabIdReady, setTabIdReady] = (0, import_react.useState)(false);
611
650
  (0, import_react.useEffect)(() => {
612
- cleanupStaleTabs();
613
- const timer = setTimeout(() => {
614
- hasCleanedUpRef.current = true;
615
- const drawingId = activeDrawingIdRef.current;
616
- if (drawingId) {
617
- setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
651
+ let cancelled = false;
652
+ let timer = null;
653
+ (async () => {
654
+ if (await detectTabIdCollision()) {
655
+ regenerateTabId();
618
656
  }
619
- }, 600);
620
- return () => clearTimeout(timer);
657
+ if (cancelled) return;
658
+ setTabIdReady(true);
659
+ cleanupStaleTabs();
660
+ timer = setTimeout(() => {
661
+ hasCleanedUpRef.current = true;
662
+ const drawingId = activeDrawingIdRef.current;
663
+ if (drawingId) {
664
+ setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
665
+ }
666
+ }, 600);
667
+ })();
668
+ return () => {
669
+ cancelled = true;
670
+ if (timer) clearTimeout(timer);
671
+ };
621
672
  }, []);
622
673
  (0, import_react.useEffect)(() => {
674
+ if (!tabIdReady) return;
623
675
  const drawingId = activeDrawing?.id || null;
624
676
  setTabDrawing(drawingId);
625
677
  if (hasCleanedUpRef.current) {
@@ -679,7 +731,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
679
731
  document.removeEventListener("visibilitychange", onVisibilityChange);
680
732
  stopPolling();
681
733
  };
682
- }, [activeDrawing?.id]);
734
+ }, [activeDrawing?.id, tabIdReady]);
683
735
  (0, import_react.useEffect)(() => {
684
736
  const onUnload = () => {
685
737
  const tabs = getTabsMap();
@@ -771,7 +823,17 @@ function WorkspaceProvider({ children, lang = "en" }) {
771
823
  const now = Date.now();
772
824
  const tempId = `temp-${now}`;
773
825
  const allDrawings = await getAllDrawings();
774
- const defaultName = `${t.newDrawing} ${allDrawings.length + 1}`;
826
+ const prefix = t.newDrawing;
827
+ const suffixRegex = new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")} (\\d+)$`);
828
+ let maxSuffix = 0;
829
+ for (const d of allDrawings) {
830
+ const m = d.name.match(suffixRegex);
831
+ if (m) {
832
+ const n = parseInt(m[1], 10);
833
+ if (!isNaN(n) && n > maxSuffix) maxSuffix = n;
834
+ }
835
+ }
836
+ const defaultName = `${prefix} ${maxSuffix + 1}`;
775
837
  const tempDrawing = {
776
838
  id: tempId,
777
839
  name: name || defaultName,
@@ -835,7 +897,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
835
897
  }
836
898
  }, [refreshDrawings]);
837
899
  const removeDrawing = (0, import_react.useCallback)(async (id) => {
838
- if (!workspace || drawingsRef.current.length <= 1) return;
900
+ if (!workspace) return;
839
901
  const removedDrawing = drawingsRef.current.find((d) => d.id === id);
840
902
  const wasActive = activeDrawingIdRef.current === id;
841
903
  const remaining = drawingsRef.current.filter((d) => d.id !== id);
@@ -850,6 +912,9 @@ function WorkspaceProvider({ children, lang = "en" }) {
850
912
  if (updatedWorkspace) {
851
913
  setWorkspace(updatedWorkspace);
852
914
  }
915
+ if (remaining.length === 0) {
916
+ await createNewDrawing();
917
+ }
853
918
  broadcastWorkspaceChange();
854
919
  } catch (err) {
855
920
  if (removedDrawing) {
@@ -857,7 +922,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
857
922
  }
858
923
  setError(err instanceof Error ? err.message : "Failed to delete drawing");
859
924
  }
860
- }, [workspace]);
925
+ }, [workspace, createNewDrawing]);
861
926
  const duplicateCurrentDrawing = (0, import_react.useCallback)(async () => {
862
927
  if (!activeDrawingIdRef.current || !workspace) return null;
863
928
  const source = drawingsRef.current.find((d) => d.id === activeDrawingIdRef.current);
@@ -904,6 +969,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
904
969
  updateData.files = files;
905
970
  }
906
971
  await updateDrawing(activeDrawing.id, updateData);
972
+ const now = Date.now();
973
+ const patch = {
974
+ elements,
975
+ appState,
976
+ ...files ? { files } : {},
977
+ updatedAt: now
978
+ };
979
+ setDrawings((prev) => prev.map((d) => d.id === activeDrawing.id ? { ...d, ...patch } : d));
980
+ setActiveDrawing2((prev) => prev && prev.id === activeDrawing.id ? { ...prev, ...patch } : prev);
907
981
  } catch (err) {
908
982
  setError(err instanceof Error ? err.message : "Failed to save drawing");
909
983
  }
@@ -919,6 +993,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
919
993
  updateData.files = files;
920
994
  }
921
995
  await updateDrawing(id, updateData);
996
+ const now = Date.now();
997
+ const patch = {
998
+ elements,
999
+ appState,
1000
+ ...files ? { files } : {},
1001
+ updatedAt: now
1002
+ };
1003
+ setDrawings((prev) => prev.map((d) => d.id === id ? { ...d, ...patch } : d));
1004
+ setActiveDrawing2((prev) => prev && prev.id === id ? { ...prev, ...patch } : prev);
922
1005
  } catch (err) {
923
1006
  setError(err instanceof Error ? err.message : "Failed to save drawing");
924
1007
  }
@@ -926,11 +1009,18 @@ function WorkspaceProvider({ children, lang = "en" }) {
926
1009
  const exportWorkspace = (0, import_react.useCallback)(async () => {
927
1010
  try {
928
1011
  const exportData = {
929
- version: 1,
1012
+ version: 2,
930
1013
  name: workspace?.name || "Min Arbetsyta",
931
1014
  exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1015
+ folders: folders.map((f) => ({
1016
+ id: f.id,
1017
+ name: f.name,
1018
+ createdAt: f.createdAt,
1019
+ updatedAt: f.updatedAt
1020
+ })),
932
1021
  drawings: drawings.map((d) => ({
933
1022
  name: d.name,
1023
+ folderId: d.folderId ?? null,
934
1024
  elements: d.elements,
935
1025
  appState: d.appState,
936
1026
  files: d.files,
@@ -950,7 +1040,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
950
1040
  } catch (err) {
951
1041
  setError(err instanceof Error ? err.message : "Failed to export workspace");
952
1042
  }
953
- }, [workspace, drawings]);
1043
+ }, [workspace, drawings, folders]);
954
1044
  const importWorkspace = (0, import_react.useCallback)(async () => {
955
1045
  if (!workspace) return;
956
1046
  try {
@@ -967,8 +1057,17 @@ function WorkspaceProvider({ children, lang = "en" }) {
967
1057
  if (!data.version || !Array.isArray(data.drawings)) {
968
1058
  throw new Error("Invalid workspace file");
969
1059
  }
1060
+ const folderIdMap = /* @__PURE__ */ new Map();
1061
+ if (Array.isArray(data.folders)) {
1062
+ for (const f of data.folders) {
1063
+ if (!f?.name || !f?.id) continue;
1064
+ const created = await createFolder(f.name);
1065
+ folderIdMap.set(f.id, created.id);
1066
+ }
1067
+ }
970
1068
  for (const d of data.drawings) {
971
- const drawing = await createDrawing(d.name || t.newDrawing);
1069
+ const mappedFolderId = d.folderId ? folderIdMap.get(d.folderId) ?? null : null;
1070
+ const drawing = await createDrawing(d.name || t.newDrawing, [], {}, mappedFolderId);
972
1071
  await updateDrawing(drawing.id, {
973
1072
  elements: d.elements || [],
974
1073
  appState: d.appState || {},
@@ -976,11 +1075,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
976
1075
  });
977
1076
  await addDrawingToWorkspace(workspace.id, drawing.id);
978
1077
  }
979
- const allDrawings = await getAllDrawings();
980
- const ws = await getOrCreateDefaultWorkspace();
1078
+ const [allDrawings, allFolders, ws] = await Promise.all([
1079
+ getAllDrawings(),
1080
+ getAllFolders(),
1081
+ getOrCreateDefaultWorkspace()
1082
+ ]);
981
1083
  const wsDrawings = allDrawings.filter((dr) => ws.drawingIds.includes(dr.id));
982
1084
  setWorkspace(ws);
983
1085
  setDrawings(wsDrawings);
1086
+ setFolders(allFolders);
984
1087
  } catch (err) {
985
1088
  setError(err instanceof Error ? err.message : "Failed to import workspace");
986
1089
  }
package/dist/index.mjs CHANGED
@@ -361,19 +361,34 @@ function useWorkspaceLang() {
361
361
  return { lang: context.lang, t: context.t };
362
362
  }
363
363
  var TAB_ID_KEY = "rita-workspace-tab-id";
364
+ var TAB_ENTRY_KEY = "rita-workspace-tab-entry";
365
+ function generateFreshTabId() {
366
+ return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
367
+ }
364
368
  var TAB_ID = (() => {
365
369
  try {
366
370
  const existing = sessionStorage.getItem(TAB_ID_KEY);
367
371
  if (existing) return existing;
368
372
  } catch {
369
373
  }
370
- const fresh = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
374
+ const fresh = generateFreshTabId();
371
375
  try {
372
376
  sessionStorage.setItem(TAB_ID_KEY, fresh);
373
377
  } catch {
374
378
  }
375
379
  return fresh;
376
380
  })();
381
+ function regenerateTabId() {
382
+ TAB_ID = generateFreshTabId();
383
+ try {
384
+ sessionStorage.setItem(TAB_ID_KEY, TAB_ID);
385
+ } catch {
386
+ }
387
+ try {
388
+ sessionStorage.removeItem(TAB_ENTRY_KEY);
389
+ } catch {
390
+ }
391
+ }
377
392
  var TABS_KEY = "rita-workspace-tabs";
378
393
  var TAB_CHANNEL = "rita-workspace-tabs";
379
394
  function broadcastWorkspaceChange() {
@@ -406,7 +421,6 @@ function getTabsMap() {
406
421
  return {};
407
422
  }
408
423
  }
409
- var TAB_ENTRY_KEY = "rita-workspace-tab-entry";
410
424
  function setTabDrawing(drawingId) {
411
425
  const tabs = getTabsMap();
412
426
  if (drawingId) {
@@ -445,6 +459,28 @@ function isDrawingOpenedEarlierInOtherTab(drawingId) {
445
459
  ([tabId, entry]) => tabId !== TAB_ID && entry.drawingId === drawingId && entry.openedAt <= myOpenedAt
446
460
  );
447
461
  }
462
+ function detectTabIdCollision() {
463
+ return new Promise((resolve) => {
464
+ let channel;
465
+ try {
466
+ channel = new BroadcastChannel(TAB_CHANNEL);
467
+ } catch {
468
+ resolve(false);
469
+ return;
470
+ }
471
+ let collided = false;
472
+ channel.onmessage = (event) => {
473
+ if (event.data?.type === "id-collision" && event.data?.tabId === TAB_ID) {
474
+ collided = true;
475
+ }
476
+ };
477
+ channel.postMessage({ type: "id-claim", tabId: TAB_ID });
478
+ setTimeout(() => {
479
+ channel.close();
480
+ resolve(collided);
481
+ }, 300);
482
+ });
483
+ }
448
484
  function cleanupStaleTabs() {
449
485
  const tabs = getTabsMap();
450
486
  const otherTabIds = Object.keys(tabs).filter((id) => id !== TAB_ID);
@@ -526,6 +562,8 @@ function WorkspaceProvider({ children, lang = "en" }) {
526
562
  channel.onmessage = (event) => {
527
563
  if (event.data?.type === "ping") {
528
564
  channel?.postMessage({ type: "pong", tabId: TAB_ID });
565
+ } else if (event.data?.type === "id-claim" && event.data?.tabId === TAB_ID) {
566
+ channel?.postMessage({ type: "id-collision", tabId: TAB_ID });
529
567
  } else if (event.data?.type === "workspace-changed" && event.data?.tabId !== TAB_ID) {
530
568
  refreshDrawingsRef.current();
531
569
  }
@@ -537,18 +575,32 @@ function WorkspaceProvider({ children, lang = "en" }) {
537
575
  };
538
576
  }, []);
539
577
  const hasCleanedUpRef = useRef(false);
578
+ const [tabIdReady, setTabIdReady] = useState(false);
540
579
  useEffect(() => {
541
- cleanupStaleTabs();
542
- const timer = setTimeout(() => {
543
- hasCleanedUpRef.current = true;
544
- const drawingId = activeDrawingIdRef.current;
545
- if (drawingId) {
546
- setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
580
+ let cancelled = false;
581
+ let timer = null;
582
+ (async () => {
583
+ if (await detectTabIdCollision()) {
584
+ regenerateTabId();
547
585
  }
548
- }, 600);
549
- return () => clearTimeout(timer);
586
+ if (cancelled) return;
587
+ setTabIdReady(true);
588
+ cleanupStaleTabs();
589
+ timer = setTimeout(() => {
590
+ hasCleanedUpRef.current = true;
591
+ const drawingId = activeDrawingIdRef.current;
592
+ if (drawingId) {
593
+ setIsDrawingConflict(isDrawingOpenedEarlierInOtherTab(drawingId));
594
+ }
595
+ }, 600);
596
+ })();
597
+ return () => {
598
+ cancelled = true;
599
+ if (timer) clearTimeout(timer);
600
+ };
550
601
  }, []);
551
602
  useEffect(() => {
603
+ if (!tabIdReady) return;
552
604
  const drawingId = activeDrawing?.id || null;
553
605
  setTabDrawing(drawingId);
554
606
  if (hasCleanedUpRef.current) {
@@ -608,7 +660,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
608
660
  document.removeEventListener("visibilitychange", onVisibilityChange);
609
661
  stopPolling();
610
662
  };
611
- }, [activeDrawing?.id]);
663
+ }, [activeDrawing?.id, tabIdReady]);
612
664
  useEffect(() => {
613
665
  const onUnload = () => {
614
666
  const tabs = getTabsMap();
@@ -700,7 +752,17 @@ function WorkspaceProvider({ children, lang = "en" }) {
700
752
  const now = Date.now();
701
753
  const tempId = `temp-${now}`;
702
754
  const allDrawings = await getAllDrawings();
703
- const defaultName = `${t.newDrawing} ${allDrawings.length + 1}`;
755
+ const prefix = t.newDrawing;
756
+ const suffixRegex = new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")} (\\d+)$`);
757
+ let maxSuffix = 0;
758
+ for (const d of allDrawings) {
759
+ const m = d.name.match(suffixRegex);
760
+ if (m) {
761
+ const n = parseInt(m[1], 10);
762
+ if (!isNaN(n) && n > maxSuffix) maxSuffix = n;
763
+ }
764
+ }
765
+ const defaultName = `${prefix} ${maxSuffix + 1}`;
704
766
  const tempDrawing = {
705
767
  id: tempId,
706
768
  name: name || defaultName,
@@ -764,7 +826,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
764
826
  }
765
827
  }, [refreshDrawings]);
766
828
  const removeDrawing = useCallback(async (id) => {
767
- if (!workspace || drawingsRef.current.length <= 1) return;
829
+ if (!workspace) return;
768
830
  const removedDrawing = drawingsRef.current.find((d) => d.id === id);
769
831
  const wasActive = activeDrawingIdRef.current === id;
770
832
  const remaining = drawingsRef.current.filter((d) => d.id !== id);
@@ -779,6 +841,9 @@ function WorkspaceProvider({ children, lang = "en" }) {
779
841
  if (updatedWorkspace) {
780
842
  setWorkspace(updatedWorkspace);
781
843
  }
844
+ if (remaining.length === 0) {
845
+ await createNewDrawing();
846
+ }
782
847
  broadcastWorkspaceChange();
783
848
  } catch (err) {
784
849
  if (removedDrawing) {
@@ -786,7 +851,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
786
851
  }
787
852
  setError(err instanceof Error ? err.message : "Failed to delete drawing");
788
853
  }
789
- }, [workspace]);
854
+ }, [workspace, createNewDrawing]);
790
855
  const duplicateCurrentDrawing = useCallback(async () => {
791
856
  if (!activeDrawingIdRef.current || !workspace) return null;
792
857
  const source = drawingsRef.current.find((d) => d.id === activeDrawingIdRef.current);
@@ -833,6 +898,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
833
898
  updateData.files = files;
834
899
  }
835
900
  await updateDrawing(activeDrawing.id, updateData);
901
+ const now = Date.now();
902
+ const patch = {
903
+ elements,
904
+ appState,
905
+ ...files ? { files } : {},
906
+ updatedAt: now
907
+ };
908
+ setDrawings((prev) => prev.map((d) => d.id === activeDrawing.id ? { ...d, ...patch } : d));
909
+ setActiveDrawing2((prev) => prev && prev.id === activeDrawing.id ? { ...prev, ...patch } : prev);
836
910
  } catch (err) {
837
911
  setError(err instanceof Error ? err.message : "Failed to save drawing");
838
912
  }
@@ -848,6 +922,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
848
922
  updateData.files = files;
849
923
  }
850
924
  await updateDrawing(id, updateData);
925
+ const now = Date.now();
926
+ const patch = {
927
+ elements,
928
+ appState,
929
+ ...files ? { files } : {},
930
+ updatedAt: now
931
+ };
932
+ setDrawings((prev) => prev.map((d) => d.id === id ? { ...d, ...patch } : d));
933
+ setActiveDrawing2((prev) => prev && prev.id === id ? { ...prev, ...patch } : prev);
851
934
  } catch (err) {
852
935
  setError(err instanceof Error ? err.message : "Failed to save drawing");
853
936
  }
@@ -855,11 +938,18 @@ function WorkspaceProvider({ children, lang = "en" }) {
855
938
  const exportWorkspace = useCallback(async () => {
856
939
  try {
857
940
  const exportData = {
858
- version: 1,
941
+ version: 2,
859
942
  name: workspace?.name || "Min Arbetsyta",
860
943
  exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
944
+ folders: folders.map((f) => ({
945
+ id: f.id,
946
+ name: f.name,
947
+ createdAt: f.createdAt,
948
+ updatedAt: f.updatedAt
949
+ })),
861
950
  drawings: drawings.map((d) => ({
862
951
  name: d.name,
952
+ folderId: d.folderId ?? null,
863
953
  elements: d.elements,
864
954
  appState: d.appState,
865
955
  files: d.files,
@@ -879,7 +969,7 @@ function WorkspaceProvider({ children, lang = "en" }) {
879
969
  } catch (err) {
880
970
  setError(err instanceof Error ? err.message : "Failed to export workspace");
881
971
  }
882
- }, [workspace, drawings]);
972
+ }, [workspace, drawings, folders]);
883
973
  const importWorkspace = useCallback(async () => {
884
974
  if (!workspace) return;
885
975
  try {
@@ -896,8 +986,17 @@ function WorkspaceProvider({ children, lang = "en" }) {
896
986
  if (!data.version || !Array.isArray(data.drawings)) {
897
987
  throw new Error("Invalid workspace file");
898
988
  }
989
+ const folderIdMap = /* @__PURE__ */ new Map();
990
+ if (Array.isArray(data.folders)) {
991
+ for (const f of data.folders) {
992
+ if (!f?.name || !f?.id) continue;
993
+ const created = await createFolder(f.name);
994
+ folderIdMap.set(f.id, created.id);
995
+ }
996
+ }
899
997
  for (const d of data.drawings) {
900
- const drawing = await createDrawing(d.name || t.newDrawing);
998
+ const mappedFolderId = d.folderId ? folderIdMap.get(d.folderId) ?? null : null;
999
+ const drawing = await createDrawing(d.name || t.newDrawing, [], {}, mappedFolderId);
901
1000
  await updateDrawing(drawing.id, {
902
1001
  elements: d.elements || [],
903
1002
  appState: d.appState || {},
@@ -905,11 +1004,15 @@ function WorkspaceProvider({ children, lang = "en" }) {
905
1004
  });
906
1005
  await addDrawingToWorkspace(workspace.id, drawing.id);
907
1006
  }
908
- const allDrawings = await getAllDrawings();
909
- const ws = await getOrCreateDefaultWorkspace();
1007
+ const [allDrawings, allFolders, ws] = await Promise.all([
1008
+ getAllDrawings(),
1009
+ getAllFolders(),
1010
+ getOrCreateDefaultWorkspace()
1011
+ ]);
910
1012
  const wsDrawings = allDrawings.filter((dr) => ws.drawingIds.includes(dr.id));
911
1013
  setWorkspace(ws);
912
1014
  setDrawings(wsDrawings);
1015
+ setFolders(allFolders);
913
1016
  } catch (err) {
914
1017
  setError(err instanceof Error ? err.message : "Failed to import workspace");
915
1018
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rita-workspace",
3
- "version": "0.5.27",
3
+ "version": "0.5.28",
4
4
  "description": "Multi-drawing workspace feature for Rita (Excalidraw fork)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",