kritzel-stencil 0.1.78 → 0.1.80

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 (163) hide show
  1. package/dist/cjs/{index-BRZ6e6oa.js → index-CFnj_FXt.js} +36 -9
  2. package/dist/cjs/index.cjs.js +1 -1
  3. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +333 -177
  4. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  5. package/dist/cjs/loader.cjs.js +2 -2
  6. package/dist/cjs/stencil.cjs.js +3 -3
  7. package/dist/cjs/{workspace.migrations-sUPrO23c.js → workspace.migrations-DUXtSb7C.js} +244 -197
  8. package/dist/collection/classes/core/core.class.js +39 -31
  9. package/dist/collection/classes/core/store.class.js +57 -16
  10. package/dist/collection/classes/core/viewport.class.js +12 -12
  11. package/dist/collection/classes/handlers/context-menu.handler.js +1 -1
  12. package/dist/collection/classes/handlers/line-handle.handler.js +7 -4
  13. package/dist/collection/classes/handlers/move.handler.js +11 -8
  14. package/dist/collection/classes/handlers/resize.handler.js +12 -3
  15. package/dist/collection/classes/handlers/rotation.handler.js +12 -3
  16. package/dist/collection/classes/handlers/selection.handler.js +20 -15
  17. package/dist/collection/classes/managers/anchor.manager.js +4 -4
  18. package/dist/collection/classes/objects/base-object.class.js +6 -6
  19. package/dist/collection/classes/objects/custom-element.class.js +2 -2
  20. package/dist/collection/classes/objects/group.class.js +10 -10
  21. package/dist/collection/classes/objects/image.class.js +2 -2
  22. package/dist/collection/classes/objects/line.class.js +7 -7
  23. package/dist/collection/classes/objects/path.class.js +5 -5
  24. package/dist/collection/classes/objects/selection-box.class.js +1 -1
  25. package/dist/collection/classes/objects/selection-group.class.js +16 -16
  26. package/dist/collection/classes/objects/shape.class.js +37 -31
  27. package/dist/collection/classes/objects/text.class.js +40 -32
  28. package/dist/collection/classes/structures/app-state-map.structure.js +18 -16
  29. package/dist/collection/classes/structures/object-map.structure.js +30 -27
  30. package/dist/collection/classes/tools/brush-tool.class.js +14 -14
  31. package/dist/collection/classes/tools/image-tool.class.js +1 -1
  32. package/dist/collection/classes/tools/line-tool.class.js +14 -14
  33. package/dist/collection/classes/tools/selection-tool.class.js +2 -2
  34. package/dist/collection/classes/tools/shape-tool.class.js +6 -6
  35. package/dist/collection/classes/tools/text-tool.class.js +2 -2
  36. package/dist/collection/collection-manifest.json +1 -1
  37. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +6 -6
  38. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +2 -2
  39. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +70 -11
  40. package/dist/collection/components/core/kritzel-engine/kritzel-engine.css +21 -1
  41. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +159 -60
  42. package/dist/collection/configs/default-engine-config.js +2 -2
  43. package/dist/collection/constants/version.js +1 -1
  44. package/dist/collection/helpers/keyboard.helper.js +15 -11
  45. package/dist/components/index.js +1 -1
  46. package/dist/components/kritzel-active-users.js +1 -1
  47. package/dist/components/kritzel-avatar.js +1 -1
  48. package/dist/components/kritzel-awareness-cursors.js +1 -1
  49. package/dist/components/kritzel-back-to-content.js +1 -1
  50. package/dist/components/kritzel-brush-style.js +1 -1
  51. package/dist/components/kritzel-button.js +1 -1
  52. package/dist/components/kritzel-color-palette.js +1 -1
  53. package/dist/components/kritzel-color.js +1 -1
  54. package/dist/components/kritzel-context-menu.js +1 -1
  55. package/dist/components/kritzel-controls.js +1 -1
  56. package/dist/components/kritzel-current-user-dialog.js +1 -1
  57. package/dist/components/kritzel-current-user.js +1 -1
  58. package/dist/components/kritzel-cursor-trail.js +1 -1
  59. package/dist/components/kritzel-dialog.js +1 -1
  60. package/dist/components/kritzel-dropdown.js +1 -1
  61. package/dist/components/kritzel-editor.js +1 -1
  62. package/dist/components/kritzel-engine.js +1 -1
  63. package/dist/components/kritzel-export.js +1 -1
  64. package/dist/components/kritzel-font-family.js +1 -1
  65. package/dist/components/kritzel-font-size.js +1 -1
  66. package/dist/components/kritzel-font.js +1 -1
  67. package/dist/components/kritzel-icon.js +1 -1
  68. package/dist/components/kritzel-input.js +1 -1
  69. package/dist/components/kritzel-line-endings.js +1 -1
  70. package/dist/components/kritzel-login-dialog.js +1 -1
  71. package/dist/components/kritzel-master-detail.js +1 -1
  72. package/dist/components/kritzel-menu-item.js +1 -1
  73. package/dist/components/kritzel-menu.js +1 -1
  74. package/dist/components/kritzel-more-menu.js +1 -1
  75. package/dist/components/kritzel-numeric-input.js +1 -1
  76. package/dist/components/kritzel-opacity-slider.js +1 -1
  77. package/dist/components/kritzel-pill-tabs.js +1 -1
  78. package/dist/components/kritzel-portal.js +1 -1
  79. package/dist/components/kritzel-settings.js +1 -1
  80. package/dist/components/kritzel-shape-fill.js +1 -1
  81. package/dist/components/kritzel-share-dialog.js +1 -1
  82. package/dist/components/kritzel-slide-toggle.js +1 -1
  83. package/dist/components/kritzel-split-button.js +1 -1
  84. package/dist/components/kritzel-stroke-size.js +1 -1
  85. package/dist/components/kritzel-tool-config.js +1 -1
  86. package/dist/components/kritzel-tooltip.js +1 -1
  87. package/dist/components/kritzel-utility-panel.js +1 -1
  88. package/dist/components/kritzel-workspace-manager.js +1 -1
  89. package/dist/components/{p-Md9Y-b3d.js → p-1ppb4M65.js} +1 -1
  90. package/dist/components/{p-KJ4dHzrS.js → p-7yR-sKH8.js} +1 -1
  91. package/dist/components/{p-CN8IxBlU.js → p-B-Gej_Ak.js} +1 -1
  92. package/dist/components/{p-76W5pG2O.js → p-B4F19Aqj.js} +1 -1
  93. package/dist/components/{p-BuI6Gkzg.js → p-B5WII1Lk.js} +1 -1
  94. package/dist/components/p-BWj1eE2b.js +1 -0
  95. package/dist/components/{p-ZC5YELQJ.js → p-BZ8bK8qT.js} +1 -1
  96. package/dist/components/{p-DkWWzVg8.js → p-BaaFG0p-.js} +1 -1
  97. package/dist/components/{p-6NFl6EB2.js → p-Bat829Bg.js} +1 -1
  98. package/dist/components/p-BcwZ36sO.js +1 -0
  99. package/dist/components/{p-53di1Zko.js → p-BjPmEs5A.js} +1 -1
  100. package/dist/components/{p-D5IhryUR.js → p-Brwz_Dpb.js} +1 -1
  101. package/dist/components/p-BzQmBVwr.js +9 -0
  102. package/dist/components/{p-C2l9mZ1P.js → p-C-MtTi6x.js} +1 -1
  103. package/dist/components/p-C8WnYSHi.js +1 -0
  104. package/dist/components/{p-BLsH_Oi0.js → p-C9zsWWH2.js} +1 -1
  105. package/dist/components/{p-ZQ2bKafG.js → p-CJKsuQun.js} +1 -1
  106. package/dist/components/{p-m1nVDC3G.js → p-CJzg_ejc.js} +1 -1
  107. package/dist/components/{p-Dte67BWd.js → p-CM7rYf9A.js} +1 -1
  108. package/dist/components/{p-Dr3-pKVg.js → p-CMGHx71q.js} +1 -1
  109. package/dist/components/{p-CI9Nbh-x.js → p-CNMpVlot.js} +1 -1
  110. package/dist/components/{p-DDKjsXCe.js → p-CS7r-zhx.js} +1 -1
  111. package/dist/components/{p-DaGZEV0R.js → p-C_fSm7T4.js} +1 -1
  112. package/dist/components/{p-Ck1dhpUQ.js → p-CfEGaTaV.js} +1 -1
  113. package/dist/components/{p-CWMFGEe0.js → p-CvyE2Wg-.js} +1 -1
  114. package/dist/components/{p-D3pNw-SV.js → p-D5BXoK9m.js} +1 -1
  115. package/dist/components/{p-DV7Z_qfa.js → p-D7pwbRUy.js} +1 -1
  116. package/dist/components/{p-CBslLN3-.js → p-DCH4Rlqx.js} +1 -1
  117. package/dist/components/{p-CYh7yV-K.js → p-DEOUiiyI.js} +1 -1
  118. package/dist/components/{p-pCC6t6BH.js → p-DKeBfe_l.js} +1 -1
  119. package/dist/components/{p-DWsCbu01.js → p-DUQmBcTy.js} +1 -1
  120. package/dist/components/{p-D14QNK3X.js → p-DUnKjQN7.js} +1 -1
  121. package/dist/components/{p-BrZ_gL8Q.js → p-DYcsC2zO.js} +1 -1
  122. package/dist/components/{p-D7yzmu1l.js → p-DkT0KZCm.js} +1 -1
  123. package/dist/components/{p-Cns7qSKS.js → p-DrsORMoT.js} +1 -1
  124. package/dist/components/{p-BueaqfA2.js → p-Dw0Obsn5.js} +1 -1
  125. package/dist/components/{p-DxzDda_J.js → p-Gm5hSQ-e.js} +1 -1
  126. package/dist/components/{p-C4fKLlrd.js → p-HK-6khHo.js} +1 -1
  127. package/dist/components/{p-_QEHfsIk.js → p-V3VW2JKl.js} +1 -1
  128. package/dist/components/{p-Lhyh6KeB.js → p-VxgCvVox.js} +1 -1
  129. package/dist/components/{p-l_YGO7RB.js → p-cjeDomsc.js} +1 -1
  130. package/dist/components/{p-gtQlsorg.js → p-rNu5JVNH.js} +1 -1
  131. package/dist/components/p-xYCbKFih.js +1 -0
  132. package/dist/esm/{index-BbOHefEf.js → index-D9HaikfQ.js} +36 -9
  133. package/dist/esm/index.js +1 -1
  134. package/dist/esm/kritzel-active-users_42.entry.js +333 -177
  135. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  136. package/dist/esm/loader.js +3 -3
  137. package/dist/esm/stencil.js +4 -4
  138. package/dist/esm/{workspace.migrations-NhRgr2_H.js → workspace.migrations-OzSSw5kt.js} +244 -197
  139. package/dist/stencil/index.esm.js +1 -1
  140. package/dist/stencil/p-D9HaikfQ.js +2 -0
  141. package/dist/stencil/p-OzSSw5kt.js +1 -0
  142. package/dist/stencil/{p-98238bf9.entry.js → p-b0be4da1.entry.js} +1 -1
  143. package/dist/stencil/p-f7be06a8.entry.js +9 -0
  144. package/dist/stencil/stencil.esm.js +1 -1
  145. package/dist/types/classes/core/store.class.d.ts +23 -0
  146. package/dist/types/classes/objects/shape.class.d.ts +1 -0
  147. package/dist/types/classes/objects/text.class.d.ts +1 -0
  148. package/dist/types/classes/providers/hocuspocus-sync-provider.class.d.ts +1 -1
  149. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +7 -5
  150. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +10 -4
  151. package/dist/types/components.d.ts +35 -13
  152. package/dist/types/constants/version.d.ts +1 -1
  153. package/dist/types/helpers/tool-config.helper.d.ts +1 -1
  154. package/dist/types/interfaces/engine-state.interface.d.ts +10 -10
  155. package/package.json +1 -1
  156. package/dist/components/p-Ban3OlgZ.js +0 -9
  157. package/dist/components/p-CGGiwvWZ.js +0 -1
  158. package/dist/components/p-CHY71o5B.js +0 -1
  159. package/dist/components/p-DXpYcAnT.js +0 -1
  160. package/dist/components/p-pGzF7PUB.js +0 -1
  161. package/dist/stencil/p-4a4b38e4.entry.js +0 -9
  162. package/dist/stencil/p-BbOHefEf.js +0 -2
  163. package/dist/stencil/p-NhRgr2_H.js +0 -1
@@ -31,13 +31,13 @@ export class KritzelEngine {
31
31
  }
32
32
  // Let batched prop updates settle, then perform an idempotent re-check.
33
33
  await Promise.resolve();
34
- const currentWorkspaceId = this.core.store.state.activeWorkspace?.id;
34
+ const currentWorkspaceId = this.core.store.activeWorkspace?.id;
35
35
  if (currentWorkspaceId === newWorkspaceId) {
36
36
  return;
37
37
  }
38
38
  this.core.beforeWorkspaceChange();
39
39
  await this.initializeWorkspaceIfNeeded(newWorkspace);
40
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
40
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
41
41
  }
42
42
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
43
43
  editorId;
@@ -137,6 +137,11 @@ export class KritzelEngine {
137
137
  }
138
138
  /** When false, wheel events will not trigger viewport pan/zoom. The event still propagates to parent elements. */
139
139
  wheelEnabled = true;
140
+ /** External loading state. Combined with internal workspace-loading state to drive the overlay. */
141
+ isLoading = false;
142
+ onIsLoadingChange() {
143
+ this.syncLoadingState();
144
+ }
140
145
  /** Emitted when the engine has fully initialized and is ready for interaction. */
141
146
  isEngineReady;
142
147
  /** Emitted when the active drawing tool changes. */
@@ -245,7 +250,7 @@ export class KritzelEngine {
245
250
  this.core.store.state?.activeTool?.handlePointerUp(ev);
246
251
  }
247
252
  handlePointerLeave() {
248
- this.core.store.state.objects?.clearCursorPosition();
253
+ this.core.store.objects?.clearCursorPosition();
249
254
  }
250
255
  handleLongPress(ev) {
251
256
  this.contextMenuHandler.handleContextMenu(ev.detail);
@@ -428,9 +433,9 @@ export class KritzelEngine {
428
433
  async hideContextMenu() {
429
434
  this.core.store.state.pointers.clear();
430
435
  this.core.store.state.isContextMenuVisible = false;
431
- this.core.store.state.objects.remove(o => o instanceof KritzelSelectionBox);
436
+ this.core.store.objects?.remove(o => o instanceof KritzelSelectionBox);
432
437
  this.core.store.setSelectionBox(null);
433
- this.core.store.state.objects.clearLocalSelectionBox();
438
+ this.core.store.objects?.clearLocalSelectionBox();
434
439
  this.core.store.state.isSelecting = false;
435
440
  this.core.store.state.isEnabled = true;
436
441
  this.core.rerender();
@@ -484,7 +489,7 @@ export class KritzelEngine {
484
489
  object._core = this.core;
485
490
  object.scale = this.core.store.state.scale;
486
491
  object.zIndex = this.core.store.currentZIndex;
487
- object.workspaceId = this.core.store.state.activeWorkspace.id;
492
+ object.workspaceId = this.core.store.activeWorkspace.id;
488
493
  // Handle KritzelText: recreate the editor now that _core is available
489
494
  // The editor's dispatchTransaction callback needs _core for persisting changes
490
495
  if (KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
@@ -505,7 +510,7 @@ export class KritzelEngine {
505
510
  child._core = this.core;
506
511
  child.scale = this.core.store.state.scale;
507
512
  child.zIndex = this.core.store.currentZIndex;
508
- child.workspaceId = this.core.store.state.activeWorkspace.id;
513
+ child.workspaceId = this.core.store.activeWorkspace.id;
509
514
  idRemapping.set(oldId, child.id);
510
515
  object.childIds.push(child.id);
511
516
  });
@@ -559,8 +564,12 @@ export class KritzelEngine {
559
564
  * @returns The removed object.
560
565
  */
561
566
  async removeObject(object) {
567
+ const objectsMap = this.core.store.objects;
568
+ if (!objectsMap) {
569
+ return null;
570
+ }
562
571
  this.core.deselectAllObjects();
563
- this.core.store.state.objects.remove(o => o.id === object.id);
572
+ objectsMap.remove(o => o.id === object.id);
564
573
  this.core.rerender();
565
574
  this.emitObjectsRemoved([object]);
566
575
  return object;
@@ -579,15 +588,23 @@ export class KritzelEngine {
579
588
  * @param objects - The objects to select.
580
589
  */
581
590
  async selectObjects(objects) {
591
+ const selectionTool = KritzelToolRegistry.getTool('selection');
592
+ if (!selectionTool) {
593
+ return;
594
+ }
582
595
  this.core.store.state.activeTool?.onDeactivate();
583
- this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
596
+ this.core.store.setState('activeTool', selectionTool);
584
597
  this.core.deselectAllObjects();
585
598
  this.core.selectObjects(objects);
586
599
  }
587
600
  /** Selects all objects currently visible in the viewport. Switches to the selection tool automatically. */
588
601
  async selectAllObjectsInViewport() {
602
+ const selectionTool = KritzelToolRegistry.getTool('selection');
603
+ if (!selectionTool) {
604
+ return;
605
+ }
589
606
  this.core.store.state.activeTool?.onDeactivate();
590
- this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
607
+ this.core.store.setState('activeTool', selectionTool);
591
608
  this.core.deselectAllObjects();
592
609
  this.core.selectAllObjectsInViewport();
593
610
  }
@@ -693,8 +710,8 @@ export class KritzelEngine {
693
710
  return null;
694
711
  // Save critical state before screenshot to restore after
695
712
  const savedState = {
696
- objects: this.core.store.state.objects,
697
- activeWorkspace: this.core.store.state.activeWorkspace,
713
+ objects: this.core.store.objects,
714
+ activeWorkspace: this.core.store.activeWorkspace,
698
715
  workspaces: this.core.store.state.workspaces,
699
716
  activeTool: this.core.store.state.activeTool,
700
717
  isReady: this.core.store.state.isReady,
@@ -745,6 +762,10 @@ export class KritzelEngine {
745
762
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
746
763
  const filename = `${activeWorkspaceName}-${timestamp}.png`;
747
764
  const dataUrl = await this.getScreenshot('png');
765
+ if (!dataUrl) {
766
+ console.error('Failed to export viewport as PNG: screenshot could not be generated');
767
+ return;
768
+ }
748
769
  const link = document.createElement('a');
749
770
  link.download = filename;
750
771
  link.href = dataUrl;
@@ -762,6 +783,10 @@ export class KritzelEngine {
762
783
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
763
784
  const filename = `${activeWorkspaceName}-${timestamp}.svg`;
764
785
  const dataUrl = await this.getScreenshot('svg');
786
+ if (!dataUrl) {
787
+ console.error('Failed to export viewport as SVG: screenshot could not be generated');
788
+ return;
789
+ }
765
790
  const link = document.createElement('a');
766
791
  link.download = filename;
767
792
  link.href = dataUrl;
@@ -884,7 +909,10 @@ export class KritzelEngine {
884
909
  * @returns A JSON string representing the complete workspace state.
885
910
  */
886
911
  async exportAsJson() {
887
- const workspace = this.core.store.state.activeWorkspace;
912
+ const workspace = this.core.store.activeWorkspace;
913
+ if (!workspace) {
914
+ throw new Error('Cannot export workspace: no active workspace is loaded');
915
+ }
888
916
  const serialized = workspace.serialize({ includeObjects: true });
889
917
  return JSON.stringify(serialized, null, 2);
890
918
  }
@@ -957,7 +985,11 @@ export class KritzelEngine {
957
985
  if (data.version && data.version !== WORKSPACE_EXPORT_VERSION) {
958
986
  console.warn(`Workspace version mismatch: expected ${WORKSPACE_EXPORT_VERSION}, got ${data.version}`);
959
987
  }
960
- const currentWorkspaceId = this.core.store.state.activeWorkspace.id;
988
+ const activeWorkspace = this.core.store.activeWorkspace;
989
+ if (!activeWorkspace) {
990
+ throw new Error('Cannot load objects: no active workspace is loaded');
991
+ }
992
+ const currentWorkspaceId = activeWorkspace.id;
961
993
  let loadedCount = 0;
962
994
  // Revive and add objects to the current workspace
963
995
  if (data.objects && Array.isArray(data.objects)) {
@@ -1093,7 +1125,11 @@ export class KritzelEngine {
1093
1125
  }
1094
1126
  /** Returns the currently active workspace. */
1095
1127
  async getActiveWorkspace() {
1096
- return this.core.store.state.activeWorkspace;
1128
+ const activeWorkspace = this.core.store.activeWorkspace;
1129
+ if (!activeWorkspace) {
1130
+ throw new Error('No active workspace is loaded');
1131
+ }
1132
+ return activeWorkspace;
1097
1133
  }
1098
1134
  /**
1099
1135
  * Gets whether the active workspace is publicly accessible.
@@ -1122,7 +1158,7 @@ export class KritzelEngine {
1122
1158
  this.workspacesChange.emit(this.core.store.state.workspaces);
1123
1159
  this.core.beforeWorkspaceChange();
1124
1160
  await this.initializeWorkspaceIfNeeded(workspace);
1125
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
1161
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
1126
1162
  }
1127
1163
  /**
1128
1164
  * Reinitializes sync by performing a full teardown and re-initialization.
@@ -1132,8 +1168,8 @@ export class KritzelEngine {
1132
1168
  */
1133
1169
  async reinitSync() {
1134
1170
  this.core.setSyncConfig(this.syncConfig);
1135
- this.core.store.state.objects?.clearCursorPosition();
1136
- this.core.store.state.objects?.destroy();
1171
+ this.core.store.objects?.clearCursorPosition();
1172
+ this.core.store.objects?.destroy();
1137
1173
  this.core.appStateMap.destroy();
1138
1174
  this._isYjsInitialized = false;
1139
1175
  await this.initializeSyncAndWorkspace();
@@ -1151,6 +1187,16 @@ export class KritzelEngine {
1151
1187
  _workspaceInitializationTargetKey = null;
1152
1188
  _syncInitPromise = null;
1153
1189
  _syncConfigRevision = 0;
1190
+ _isWorkspaceLoading = false;
1191
+ _defaultUndoState = {
1192
+ canUndo: false,
1193
+ canRedo: false,
1194
+ undoStackSize: 0,
1195
+ redoStackSize: 0,
1196
+ };
1197
+ syncLoadingState() {
1198
+ this.core.store.state.isLoading = this._isWorkspaceLoading || this.isLoading;
1199
+ }
1154
1200
  get isSelecting() {
1155
1201
  return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.isSelecting;
1156
1202
  }
@@ -1163,10 +1209,10 @@ export class KritzelEngine {
1163
1209
  disconnectedCallback() {
1164
1210
  this.throttledPointerMoveMulti.cancel();
1165
1211
  // Clear cursor position in awareness before destroying
1166
- this.core.store.state.objects?.clearCursorPosition();
1212
+ this.core.store.objects?.clearCursorPosition();
1167
1213
  // Clean up current workspace's ObjectMap
1168
- if (this.core.store.state.objects) {
1169
- this.core.store.state.objects.destroy();
1214
+ if (this.core.store.objects) {
1215
+ this.core.store.objects.destroy();
1170
1216
  }
1171
1217
  // Clean up AppStateMap (workspaces Y.Doc)
1172
1218
  this.core.appStateMap.destroy();
@@ -1184,6 +1230,8 @@ export class KritzelEngine {
1184
1230
  this.core.store.state.viewportBoundaryRight = this.viewportBoundaryRight;
1185
1231
  this.core.store.state.viewportBoundaryTop = this.viewportBoundaryTop;
1186
1232
  this.core.store.state.viewportBoundaryBottom = this.viewportBoundaryBottom;
1233
+ this._isWorkspaceLoading = true;
1234
+ this.syncLoadingState();
1187
1235
  }
1188
1236
  async componentDidLoad() {
1189
1237
  setTimeout(async () => {
@@ -1192,7 +1240,9 @@ export class KritzelEngine {
1192
1240
  this.viewport = new KritzelViewport(this.core, this.host);
1193
1241
  // Initialize cursor manager with target element and shadow root
1194
1242
  this.core.cursorManager.setTargetElement(this.cursorTarget || document.body);
1195
- this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
1243
+ if (this.host.shadowRoot) {
1244
+ this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
1245
+ }
1196
1246
  // Initialize theme manager with kritzel-editor as target element
1197
1247
  const editorElement = this.host.closest('kritzel-editor');
1198
1248
  this.core.themeManager.setTargetElement(editorElement || this.host);
@@ -1253,7 +1303,7 @@ export class KritzelEngine {
1253
1303
  await this.initializeWorkspaceIfNeeded(startupWorkspace);
1254
1304
  }
1255
1305
  // Emit initial active workspace once startup initialization has completed
1256
- const initialActiveWorkspace = this.core.store.state.activeWorkspace;
1306
+ const initialActiveWorkspace = this.core.store.activeWorkspace;
1257
1307
  if (initialActiveWorkspace) {
1258
1308
  this.activeWorkspaceChange.emit(initialActiveWorkspace);
1259
1309
  }
@@ -1282,7 +1332,7 @@ export class KritzelEngine {
1282
1332
  if (!this.activeWorkspaceId || this._isResolvingActiveWorkspaceId) {
1283
1333
  return;
1284
1334
  }
1285
- if (this.core.store.state.activeWorkspace?.id === this.activeWorkspaceId) {
1335
+ if (this.core.store.activeWorkspace?.id === this.activeWorkspaceId) {
1286
1336
  return;
1287
1337
  }
1288
1338
  this._isResolvingActiveWorkspaceId = true;
@@ -1298,24 +1348,25 @@ export class KritzelEngine {
1298
1348
  }
1299
1349
  return;
1300
1350
  }
1301
- if (this.core.store.state.activeWorkspace?.id === workspace.id) {
1351
+ if (this.core.store.activeWorkspace?.id === workspace.id) {
1302
1352
  return;
1303
1353
  }
1304
1354
  this.core.beforeWorkspaceChange();
1305
1355
  await this.initializeWorkspaceIfNeeded(workspace);
1306
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
1356
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
1307
1357
  }
1308
1358
  async initializeWorkspaceIfNeeded(workspace, options) {
1309
1359
  const targetWorkspaceId = workspace?.id ?? null;
1310
1360
  const targetKey = targetWorkspaceId ?? (options?.skipFallbackCreation ? '__NO_FALLBACK__' : '__AUTO__');
1311
- if (targetWorkspaceId && this.core.store.state.activeWorkspace?.id === targetWorkspaceId) {
1361
+ if (targetWorkspaceId && this.core.store.activeWorkspace?.id === targetWorkspaceId) {
1312
1362
  return;
1313
1363
  }
1314
1364
  if (this._workspaceInitializationPromise && this._workspaceInitializationTargetKey === targetKey) {
1315
1365
  await this._workspaceInitializationPromise;
1316
1366
  return;
1317
1367
  }
1318
- this.core.store.state.isWorkspaceLoading = true;
1368
+ this._isWorkspaceLoading = true;
1369
+ this.syncLoadingState();
1319
1370
  const initializationPromise = this.core.initializeWorkspace(workspace, options);
1320
1371
  this._workspaceInitializationPromise = initializationPromise;
1321
1372
  this._workspaceInitializationTargetKey = targetKey;
@@ -1327,12 +1378,23 @@ export class KritzelEngine {
1327
1378
  this._workspaceInitializationPromise = null;
1328
1379
  this._workspaceInitializationTargetKey = null;
1329
1380
  }
1330
- this.core.store.state.isWorkspaceLoading = false;
1381
+ this._isWorkspaceLoading = false;
1382
+ this.syncLoadingState();
1331
1383
  }
1332
1384
  }
1333
1385
  emitObjectsChange() {
1386
+ const objectsMap = this.core.store.objects;
1387
+ if (!objectsMap) {
1388
+ this.objectsChange.emit([]);
1389
+ this.undoStateChange.emit(this._defaultUndoState);
1390
+ if (this._lastHadSelectionGroup) {
1391
+ this._lastHadSelectionGroup = false;
1392
+ this.objectsSelectionChange.emit();
1393
+ }
1394
+ return;
1395
+ }
1334
1396
  const objects = this.core.store.allObjects;
1335
- const undoState = this.core.store.state.objects.undoState;
1397
+ const undoState = objectsMap.undoState;
1336
1398
  const hasSelectionGroup = this.core.store.selectionGroup !== null;
1337
1399
  this.objectsChange.emit(objects);
1338
1400
  this.undoStateChange.emit(undoState);
@@ -1363,22 +1425,24 @@ export class KritzelEngine {
1363
1425
  _handleActiveToolChange(activeTool) {
1364
1426
  if (!(activeTool instanceof KritzelSelectionTool)) {
1365
1427
  this.core.clearSelection();
1366
- this.core.store.state.objects.remove(o => o instanceof KritzelSelectionBox);
1428
+ this.core.store.objects?.remove(o => o instanceof KritzelSelectionBox);
1367
1429
  this.core.store.setSelectionBox(null);
1368
- this.core.store.state.objects.clearLocalSelectionBox();
1430
+ this.core.store.objects?.clearLocalSelectionBox();
1369
1431
  this.core.store.state.isSelecting = false;
1370
1432
  this.core.store.state.isResizeHandleSelected = false;
1371
1433
  this.core.store.state.isRotationHandleSelected = false;
1372
1434
  }
1373
1435
  this.core.store.state.skipContextMenu = false;
1374
- this.core.store.state.copiedObjects = null;
1375
- this.activeToolChange.emit(activeTool);
1436
+ this.core.store.state.copiedObjects = undefined;
1437
+ if (activeTool) {
1438
+ this.activeToolChange.emit(activeTool);
1439
+ }
1376
1440
  KritzelKeyboardHelper.forceHideKeyboard();
1377
1441
  this.core.rerender();
1378
1442
  }
1379
1443
  render() {
1380
1444
  if (!this.viewport) {
1381
- return null;
1445
+ return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading..."))));
1382
1446
  }
1383
1447
  const currentTheme = this.core.themeManager.getStoredTheme();
1384
1448
  const computedStyle = window.getComputedStyle(this.host);
@@ -1395,7 +1459,7 @@ export class KritzelEngine {
1395
1459
  this.emitObjectsInViewportChange();
1396
1460
  }
1397
1461
  }
1398
- return (h(Host, null, this.core.store.state.isWorkspaceLoading && (h("div", { class: "workspace-loading-overlay" }, "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
1462
+ return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
1399
1463
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
1400
1464
  } }, visibleObjects?.map(object => {
1401
1465
  return (h("div", { key: object.id, id: object.id, class: "object", style: {
@@ -1404,7 +1468,7 @@ export class KritzelEngine {
1404
1468
  position: 'absolute',
1405
1469
  zIndex: object.zIndex.toString(),
1406
1470
  pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
1407
- } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1471
+ } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1408
1472
  height: object?.totalHeight + 'px',
1409
1473
  width: object?.totalWidth + 'px',
1410
1474
  left: '0',
@@ -1415,7 +1479,7 @@ export class KritzelEngine {
1415
1479
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1416
1480
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1417
1481
  overflow: 'visible',
1418
- }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1482
+ }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1419
1483
  height: object?.totalHeight + 'px',
1420
1484
  width: object?.totalWidth + 'px',
1421
1485
  left: '0',
@@ -1426,7 +1490,7 @@ export class KritzelEngine {
1426
1490
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1427
1491
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1428
1492
  overflow: 'visible',
1429
- }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => object.mount(el), src: object.src, style: {
1493
+ }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => el && object.mount(el), src: object.src, style: {
1430
1494
  position: 'absolute',
1431
1495
  left: '0',
1432
1496
  top: '0',
@@ -1444,7 +1508,7 @@ export class KritzelEngine {
1444
1508
  overflow: 'visible',
1445
1509
  userSelect: 'none',
1446
1510
  imageRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'pixelated' : 'auto',
1447
- }, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", { ref: el => object.mount(el), style: {
1511
+ }, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", { ref: el => el && object.mount(el), style: {
1448
1512
  position: 'absolute',
1449
1513
  left: '0',
1450
1514
  top: '0',
@@ -1461,7 +1525,7 @@ export class KritzelEngine {
1461
1525
  padding: object.padding + 'px',
1462
1526
  overflow: 'hidden',
1463
1527
  display: 'block',
1464
- } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => object.mount(el), style: {
1528
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => el && object.mount(el), style: {
1465
1529
  position: 'absolute',
1466
1530
  left: '0',
1467
1531
  top: '0',
@@ -1471,7 +1535,7 @@ export class KritzelEngine {
1471
1535
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1472
1536
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1473
1537
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1474
- } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => object.mount(el), style: {
1538
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => el && object.mount(el), style: {
1475
1539
  position: 'absolute',
1476
1540
  left: '0',
1477
1541
  top: '0',
@@ -1495,7 +1559,7 @@ export class KritzelEngine {
1495
1559
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1496
1560
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1497
1561
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1498
- } }, h("div", { id: "text-object", ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
1562
+ } }, h("div", { id: "text-object", ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
1499
1563
  minWidth: object.initialWidth + 'px',
1500
1564
  minHeight: object.initialHeight + 'px',
1501
1565
  maxWidth: '500px',
@@ -1505,7 +1569,7 @@ export class KritzelEngine {
1505
1569
  transform: `scale(${object.scaleFactor})`,
1506
1570
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
1507
1571
  overflow: 'visible',
1508
- } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
1572
+ } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
1509
1573
  position: 'absolute',
1510
1574
  left: '0',
1511
1575
  top: '0',
@@ -1524,7 +1588,7 @@ export class KritzelEngine {
1524
1588
  height: '100%',
1525
1589
  overflow: 'visible',
1526
1590
  pointerEvents: 'none',
1527
- }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), h("div", { ref: el => object.mountTextEditor(el), style: {
1591
+ }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), h("div", { ref: el => el && object.mountTextEditor(el), style: {
1528
1592
  position: 'absolute',
1529
1593
  top: '0',
1530
1594
  left: '0',
@@ -1545,8 +1609,8 @@ export class KritzelEngine {
1545
1609
  } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
1546
1610
  (() => {
1547
1611
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
1548
- const localClientId = this.core.store.state.objects?.localClientId;
1549
- const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
1612
+ const localClientId = this.core.store.objects?.localClientId;
1613
+ const awarenessStates = this.core.store.objects?.awareness?.getStates();
1550
1614
  const isRemoteSelection = isSelectionGroup && (
1551
1615
  // Different user
1552
1616
  (object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
@@ -1774,18 +1838,20 @@ export class KritzelEngine {
1774
1838
  stroke: 'var(--kritzel-snap-indicator-stroke, #007bff)',
1775
1839
  strokeWidth: data.indicatorStrokeWidth,
1776
1840
  } }))));
1777
- })()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
1841
+ })()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { class: "context-menu", ref: el => (this.contextMenuElement = el ?? null), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
1778
1842
  position: 'fixed',
1779
1843
  left: `${this.core.store.state.contextMenuX}px`,
1780
1844
  top: `${this.core.store.state.contextMenuY}px`,
1781
1845
  zIndex: '10002',
1782
1846
  }, onActionSelected: event => {
1783
- event.detail.action({
1784
- x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
1785
- y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
1786
- }, this.core.store.selectionGroup?.objects);
1847
+ if (event.detail.action) {
1848
+ event.detail.action({
1849
+ x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
1850
+ y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
1851
+ }, this.core.store.selectionGroup?.objects || []);
1852
+ }
1787
1853
  this.hideContextMenu();
1788
- }, onClose: () => this.hideContextMenu() })), this.core.store.state.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core })));
1854
+ }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core })));
1789
1855
  }
1790
1856
  static get is() { return "kritzel-engine"; }
1791
1857
  static get encapsulation() { return "shadow"; }
@@ -1926,7 +1992,7 @@ export class KritzelEngine {
1926
1992
  }
1927
1993
  }
1928
1994
  },
1929
- "required": false,
1995
+ "required": true,
1930
1996
  "optional": false,
1931
1997
  "docs": {
1932
1998
  "tags": [],
@@ -1950,7 +2016,7 @@ export class KritzelEngine {
1950
2016
  }
1951
2017
  }
1952
2018
  },
1953
- "required": false,
2019
+ "required": true,
1954
2020
  "optional": false,
1955
2021
  "docs": {
1956
2022
  "tags": [],
@@ -2163,7 +2229,7 @@ export class KritzelEngine {
2163
2229
  }
2164
2230
  }
2165
2231
  },
2166
- "required": false,
2232
+ "required": true,
2167
2233
  "optional": false,
2168
2234
  "docs": {
2169
2235
  "tags": [],
@@ -2191,6 +2257,26 @@ export class KritzelEngine {
2191
2257
  "reflect": false,
2192
2258
  "attribute": "wheel-enabled",
2193
2259
  "defaultValue": "true"
2260
+ },
2261
+ "isLoading": {
2262
+ "type": "boolean",
2263
+ "mutable": false,
2264
+ "complexType": {
2265
+ "original": "boolean",
2266
+ "resolved": "boolean",
2267
+ "references": {}
2268
+ },
2269
+ "required": false,
2270
+ "optional": false,
2271
+ "docs": {
2272
+ "tags": [],
2273
+ "text": "External loading state. Combined with internal workspace-loading state to drive the overlay."
2274
+ },
2275
+ "getter": false,
2276
+ "setter": false,
2277
+ "reflect": false,
2278
+ "attribute": "is-loading",
2279
+ "defaultValue": "false"
2194
2280
  }
2195
2281
  };
2196
2282
  }
@@ -2530,7 +2616,7 @@ export class KritzelEngine {
2530
2616
  },
2531
2617
  "registerTool": {
2532
2618
  "complexType": {
2533
- "signature": "(toolName: string, toolClass: any, toolConfig?: KritzelTextToolConfig | KritzelBrushToolConfig | KritzelLineToolConfig | KritzelShapeToolConfig) => Promise<KritzelBaseTool>",
2619
+ "signature": "(toolName: string, toolClass: any, toolConfig?: KritzelTextToolConfig | KritzelBrushToolConfig | KritzelLineToolConfig | KritzelShapeToolConfig) => Promise<KritzelBaseTool | null>",
2534
2620
  "parameters": [{
2535
2621
  "name": "toolName",
2536
2622
  "type": "string",
@@ -2578,6 +2664,10 @@ export class KritzelEngine {
2578
2664
  "path": "../../../interfaces/toolbar-control.interface",
2579
2665
  "id": "src/interfaces/toolbar-control.interface.ts::KritzelShapeToolConfig",
2580
2666
  "referenceLocation": "KritzelShapeToolConfig"
2667
+ },
2668
+ "Record": {
2669
+ "location": "global",
2670
+ "id": "global::Record"
2581
2671
  }
2582
2672
  },
2583
2673
  "return": "Promise<KritzelBaseTool>"
@@ -3029,10 +3119,10 @@ export class KritzelEngine {
3029
3119
  },
3030
3120
  "findObjects": {
3031
3121
  "complexType": {
3032
- "signature": "<T extends KritzelBaseObject>(predicate: (obj: KritzelBaseObject) => boolean) => Promise<T[]>",
3122
+ "signature": "<T extends KritzelBaseObject>(predicate: (obj: KritzelBaseObject<Element>) => boolean) => Promise<T[]>",
3033
3123
  "parameters": [{
3034
3124
  "name": "predicate",
3035
- "type": "(obj: KritzelBaseObject<HTMLElement | SVGElement>) => boolean",
3125
+ "type": "(obj: KritzelBaseObject<Element>) => boolean",
3036
3126
  "docs": "- A filter function called for each object. Return `true` to include."
3037
3127
  }],
3038
3128
  "references": {
@@ -3049,6 +3139,12 @@ export class KritzelEngine {
3049
3139
  "path": "../../../classes/objects/base-object.class",
3050
3140
  "id": "src/classes/objects/base-object.class.ts::KritzelBaseObject",
3051
3141
  "referenceLocation": "KritzelBaseObject"
3142
+ },
3143
+ "Element": {
3144
+ "location": "import",
3145
+ "path": "@stencil/core",
3146
+ "id": "../../node_modules/@stencil/core/internal/stencil-core/index.d.ts::Element",
3147
+ "referenceLocation": "Element"
3052
3148
  }
3053
3149
  },
3054
3150
  "return": "Promise<T[]>"
@@ -3691,7 +3787,7 @@ export class KritzelEngine {
3691
3787
  },
3692
3788
  "getScreenshot": {
3693
3789
  "complexType": {
3694
- "signature": "(format?: \"png\" | \"svg\") => Promise<string>",
3790
+ "signature": "(format?: \"png\" | \"svg\") => Promise<string | null>",
3695
3791
  "parameters": [{
3696
3792
  "name": "format",
3697
3793
  "type": "\"svg\" | \"png\"",
@@ -4245,6 +4341,9 @@ export class KritzelEngine {
4245
4341
  }, {
4246
4342
  "propName": "debugInfo",
4247
4343
  "methodName": "onDebugInfoChange"
4344
+ }, {
4345
+ "propName": "isLoading",
4346
+ "methodName": "onIsLoadingChange"
4248
4347
  }];
4249
4348
  }
4250
4349
  static get listeners() {
@@ -1,5 +1,5 @@
1
1
  export const DEFAULT_ENGINE_CONFIG = {
2
- activeWorkspace: null,
2
+ activeWorkspace: undefined,
3
3
  activeTool: null,
4
4
  copiedObjects: null,
5
5
  objects: null,
@@ -25,7 +25,7 @@ export const DEFAULT_ENGINE_CONFIG = {
25
25
  isDrawing: false,
26
26
  isErasing: false,
27
27
  isWriting: false,
28
- isWorkspaceLoading: false,
28
+ isLoading: false,
29
29
  isCtrlKeyPressed: false,
30
30
  isContextMenuVisible: false,
31
31
  contextMenuItems: [],
@@ -3,4 +3,4 @@
3
3
  * This file is auto-generated by the version bump scripts.
4
4
  * Do not modify manually.
5
5
  */
6
- export const KRITZEL_VERSION = '0.1.78';
6
+ export const KRITZEL_VERSION = '0.1.80';