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
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-BRZ6e6oa.js');
4
- var workspace_migrations = require('./workspace.migrations-sUPrO23c.js');
3
+ var index = require('./index-CFnj_FXt.js');
4
+ var workspace_migrations = require('./workspace.migrations-DUXtSb7C.js');
5
5
  var Y = require('yjs');
6
6
  require('y-websocket');
7
7
  require('y-indexeddb');
@@ -193,10 +193,10 @@ const KritzelAwarenessCursors = class {
193
193
  cleanupIntervalId;
194
194
  objectChangeRafId = null;
195
195
  componentDidLoad() {
196
- this.core.store.state.objects?.onAwarenessChange(states => {
196
+ this.core.store.objects?.onAwarenessChange(states => {
197
197
  this.handleAwarenessChange(states);
198
198
  });
199
- this.core.store.state.objects?.onObjectsChange(() => {
199
+ this.core.store.objects?.onObjectsChange(() => {
200
200
  this.handleRemoteObjectChange();
201
201
  });
202
202
  this.cleanupIntervalId = setInterval(() => {
@@ -212,7 +212,7 @@ const KritzelAwarenessCursors = class {
212
212
  }
213
213
  }
214
214
  handleAwarenessChange(states) {
215
- const localClientId = this.core.store.state.objects?.localClientId;
215
+ const localClientId = this.core.store.objects?.localClientId;
216
216
  const now = Date.now();
217
217
  const updated = new Map(this.remoteCursors);
218
218
  // Track which clientIds are still present
@@ -288,7 +288,7 @@ const KritzelAwarenessCursors = class {
288
288
  });
289
289
  }
290
290
  getActiveObjectTip(objectId) {
291
- const obj = this.core.store.state.objects?.findById(objectId);
291
+ const obj = this.core.store.objects?.findById(objectId);
292
292
  if (!obj)
293
293
  return null;
294
294
  if (obj instanceof workspace_migrations.KritzelPath && !obj.isCompleted) {
@@ -356,7 +356,7 @@ const KritzelAwarenessCursors = class {
356
356
  }
357
357
  render() {
358
358
  const cursors = Array.from(this.remoteCursors.values());
359
- return (index.h(index.Host, { key: '5a28def6e024249c4309c087502cde9f219f5421' }, cursors.map(remoteCursor => {
359
+ return (index.h(index.Host, { key: '1743084eadda932b5aaf89552f500b90e194a79f' }, cursors.map(remoteCursor => {
360
360
  if (!remoteCursor.cursor)
361
361
  return null;
362
362
  // When a remote user is actively drawing, derive cursor position from
@@ -1270,7 +1270,7 @@ const KritzelCursorTrail = class {
1270
1270
  }
1271
1271
  }
1272
1272
  render() {
1273
- return (index.h(index.Host, { key: 'b6a9e84ce49dd72f353e0b87ae0bc02b0e5aeb1e' }, this.cursorTrailPoints.length > 1 && (index.h("svg", { key: '238ea314a937d556c75ae080495c2e6559340c6f', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1273
+ return (index.h(index.Host, { key: 'b0f5c795c4803e27a49d7f76f3fedea818967049' }, this.cursorTrailPoints.length > 1 && (index.h("svg", { key: '6ff883be1aecfb302bc9ecb3b7562617d753d5ba', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1274
1274
  position: 'absolute',
1275
1275
  left: '0',
1276
1276
  top: '0',
@@ -2049,6 +2049,8 @@ const KritzelEditor = class {
2049
2049
  }
2050
2050
  ]
2051
2051
  };
2052
+ /** Whether the editor is in a loading state. When true, a loading overlay is displayed. */
2053
+ isLoading = false;
2052
2054
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
2053
2055
  editorId;
2054
2056
  /** Optional workspace ID to set as active. If provided, the editor will automatically activate the workspace with this ID. */
@@ -2088,9 +2090,10 @@ const KritzelEditor = class {
2088
2090
  }
2089
2091
  }
2090
2092
  onWorkspacesChange(newWorkspaces) {
2091
- if (this.activeWorkspace) {
2092
- const updatedActiveWorkspace = newWorkspaces.find(ws => ws.id === this.activeWorkspace.id);
2093
- if (updatedActiveWorkspace && updatedActiveWorkspace !== this.activeWorkspace) {
2093
+ const activeWorkspace = this.activeWorkspace;
2094
+ if (activeWorkspace) {
2095
+ const updatedActiveWorkspace = newWorkspaces.find(ws => ws.id === activeWorkspace.id);
2096
+ if (updatedActiveWorkspace && updatedActiveWorkspace !== activeWorkspace) {
2094
2097
  this.activeWorkspace = updatedActiveWorkspace;
2095
2098
  }
2096
2099
  }
@@ -2317,7 +2320,7 @@ const KritzelEditor = class {
2317
2320
  await customElements.whenDefined('kritzel-workspace-manager');
2318
2321
  await customElements.whenDefined('kritzel-controls');
2319
2322
  await customElements.whenDefined('kritzel-engine');
2320
- if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady) {
2323
+ if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady || !this.activeWorkspace) {
2321
2324
  return;
2322
2325
  }
2323
2326
  const { id, name, isPublic, createdAt, updatedAt } = this.activeWorkspace;
@@ -2336,6 +2339,9 @@ const KritzelEditor = class {
2336
2339
  }
2337
2340
  async onEngineReady(event) {
2338
2341
  this.isEngineReady = true;
2342
+ if (!event.detail.activeWorkspace) {
2343
+ return;
2344
+ }
2339
2345
  this.activeWorkspace = event.detail.activeWorkspace;
2340
2346
  this.workspaces = event.detail.workspaces;
2341
2347
  this.currentIsPublic = await this.engineRef.getIsPublic();
@@ -2418,7 +2424,7 @@ const KritzelEditor = class {
2418
2424
  icon: 'upload',
2419
2425
  action: async () => {
2420
2426
  const preview = await this.engineRef.getScreenshot('png');
2421
- this.exportRef.open(preview);
2427
+ this.exportRef.open(preview ?? undefined);
2422
2428
  },
2423
2429
  },
2424
2430
  {
@@ -2449,7 +2455,7 @@ const KritzelEditor = class {
2449
2455
  activeWorkspace.isPublic = isPublic;
2450
2456
  await this.engineRef.updateWorkspace(activeWorkspace);
2451
2457
  this.activeWorkspace = activeWorkspace.clone();
2452
- this.isPublicChange.emit({ isPublic, workspaceId: this.activeWorkspace?.id });
2458
+ this.isPublicChange.emit({ isPublic, workspaceId: activeWorkspace.id });
2453
2459
  };
2454
2460
  /**
2455
2461
  * Updates the currentIsPublic state from the active workspace and emits the isPublicChange event.
@@ -2458,6 +2464,9 @@ const KritzelEditor = class {
2458
2464
  const isPublic = this.activeWorkspace?.isPublic ?? false;
2459
2465
  const workspaceId = this.activeWorkspace?.id;
2460
2466
  this.currentIsPublic = isPublic;
2467
+ if (!workspaceId) {
2468
+ return;
2469
+ }
2461
2470
  this.isPublicChange.emit({ isPublic, workspaceId });
2462
2471
  }
2463
2472
  handleProviderLogin = (event) => {
@@ -2562,7 +2571,31 @@ const KritzelEditor = class {
2562
2571
  const isLoggedIn = this.isLoggedIn;
2563
2572
  const shouldShowCurrentUser = isLoggedIn;
2564
2573
  const shouldShowLoginButton = !!this.loginConfig && !isLoggedIn;
2565
- return (index.h(index.Host, { key: '6dbc3a8c64dd097ba82e46341b3fb97cbd0194db' }, index.h("div", { key: '26ceb62f59ad830fd651a1712f57e5d711e7c6f4', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: 'afb4f5b87c5dc0a673444fb27930e43994df4e02', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'f3c0f31841cb819917c3277852bc9b5ce291c09a', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '8a9e57132e6b74ec812ee516dc7f0d5fc6c8a2e1', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: '6caadf512a0208fecdb18b6d68b17daa522161a3', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'e27e5f3965be2fd15c83b91470ef87c4031dd7a2', class: "top-right-buttons" }, index.h("kritzel-settings", { key: '57f8e75287402aecbb7740d46dfa15839de2169f', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: '5ccf176d4fe1221c5d7597bd1c8537cf3324d3ee', ref: el => (this.exportRef = el), workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '44a334b808706e11163e89b91074ca4ea8ab4b18', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: 'bcb3c966e630b1a8fc4ccd438fc8fbb11cd2b167', user: this.user }), shouldShowLoginButton && index.h("kritzel-button", { key: 'f1957e56257b7c565311e41b770579f7e2bb910d', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), index.h("kritzel-more-menu", { key: 'd8c1d1b51cf87725d68aaf4457b88828986a40dc', items: this.moreMenuItems }), index.h("kritzel-share-dialog", { key: 'f5840e7f56cf6897ec28b0f28d9b204037bf3348', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'cfdcc3d5e7a5e29b0a352f0d4423ae79195dbf69', ref: el => (this.loginDialogRef = el), providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2574
+ return (index.h(index.Host, { key: '1e3c220506d14f276ca246365c2bda79110c6c35' }, index.h("div", { key: '154b45141b995f749adb52a11dc3363ab2989475', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: '22519269ea7227a1a7a05d2f282bbcd2466edf5d', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'e89f0609dfd031cb040fd80a1f60ecb56d56734c', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '0b3acdf827d48c9589fb8170b49a602beb273684', ref: el => {
2575
+ if (el) {
2576
+ this.engineRef = el;
2577
+ }
2578
+ }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, scaleMin: this.scaleMin, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.currentTheme, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: '324ba00f982938abc7a3f4dc47368f3b9bad665e', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => {
2579
+ if (el) {
2580
+ this.controlsRef = el;
2581
+ }
2582
+ }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: '0c4662e92cbe90a958f8704e6db0375915d9c634', class: "top-right-buttons" }, index.h("kritzel-settings", { key: 'e0422c1a02bc895bafd4b777d4d593afcfdf335b', ref: el => {
2583
+ if (el) {
2584
+ this.settingsRef = el;
2585
+ }
2586
+ }, shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: '72f59ec2eab76d753bb64475f199f0fa33e935d4', ref: el => {
2587
+ if (el) {
2588
+ this.exportRef = el;
2589
+ }
2590
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: 'c60411370947fc408b5e9d7adade3e28210b8d47', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: '4783940d3d4f9c2a7e8156c0713f29cb8b043125', user: this.user }), shouldShowLoginButton && index.h("kritzel-button", { key: 'bdb727d5641f8cda3711856086e1b9aa8533a5a6', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), index.h("kritzel-more-menu", { key: '3afa57ea46636c92cc7232dfe22a27cace85766e', items: this.moreMenuItems }), index.h("kritzel-share-dialog", { key: '852f9980fa3b89ceb5b6d8bde1bdd5598d3dc6e4', ref: el => {
2591
+ if (el) {
2592
+ this.shareDialogRef = el;
2593
+ }
2594
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'cdccbb7ef0b9932c0747545a18071f22e5683d8c', ref: el => {
2595
+ if (el) {
2596
+ this.loginDialogRef = el;
2597
+ }
2598
+ }, providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2566
2599
  }
2567
2600
  static get watchers() { return {
2568
2601
  "isEngineReady": [{
@@ -19977,8 +20010,8 @@ class KritzelViewport {
19977
20010
  * Updates the stored viewport dimensions and triggers a rerender.
19978
20011
  */
19979
20012
  handleResize() {
19980
- this._core.store.state.viewportWidth = this._core.store.state.host.clientWidth;
19981
- this._core.store.state.viewportHeight = this._core.store.state.host.clientHeight;
20013
+ this._core.store.state.viewportWidth = this._core.store.host.clientWidth;
20014
+ this._core.store.state.viewportHeight = this._core.store.host.clientHeight;
19982
20015
  this._core.store.state.hasViewportChanged = true;
19983
20016
  this._core.rerender();
19984
20017
  }
@@ -20009,15 +20042,15 @@ class KritzelViewport {
20009
20042
  this._touchCursorBroadcastActive = false;
20010
20043
  }
20011
20044
  if (activePointers.length === 2) {
20012
- this._core.store.state.objects?.clearCursorPosition();
20045
+ this._core.store.objects?.clearCursorPosition();
20013
20046
  const currentPath = this._core.store.currentPath;
20014
20047
  if (currentPath) {
20015
- this._core.store.state.objects.remove(obj => obj.id === currentPath.id);
20048
+ this._core.store.objects.remove(obj => obj.id === currentPath.id);
20016
20049
  }
20017
20050
  // Clear selection box when scaling starts to prevent it from remaining on screen
20018
20051
  if (this._core.store.state.isSelecting) {
20019
20052
  this._core.store.state.isSelecting = false;
20020
- this._core.store.state.objects.remove(obj => obj instanceof workspace_migrations.KritzelSelectionBox);
20053
+ this._core.store.objects.remove(obj => obj instanceof workspace_migrations.KritzelSelectionBox);
20021
20054
  this._core.store.setSelectionBox(null);
20022
20055
  // Clear selection preview state from objects - use selectedObjects for efficiency
20023
20056
  this._core.store.selectedObjects.forEach(object => {
@@ -20044,12 +20077,12 @@ class KritzelViewport {
20044
20077
  */
20045
20078
  handlePointerMove(event) {
20046
20079
  if (event.pointerType === 'mouse') {
20047
- const hostRect = this._core.store.state.host.getBoundingClientRect();
20080
+ const hostRect = this._core.store.host.getBoundingClientRect();
20048
20081
  const xRelativeToHost = event.clientX - hostRect.left;
20049
20082
  const yRelativeToHost = event.clientY - hostRect.top;
20050
20083
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
20051
20084
  this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
20052
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20085
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20053
20086
  if (this._core.store.state.isPanning) {
20054
20087
  const dx = xRelativeToHost - this._core.store.state.startX;
20055
20088
  const dy = yRelativeToHost - this._core.store.state.startY;
@@ -20067,12 +20100,12 @@ class KritzelViewport {
20067
20100
  }
20068
20101
  }
20069
20102
  if (event.pointerType === 'touch' || event.pointerType === 'pen') {
20070
- const hostRect = this._core.store.state.host.getBoundingClientRect();
20103
+ const hostRect = this._core.store.host.getBoundingClientRect();
20071
20104
  const xRelativeToHost = event.clientX - hostRect.left;
20072
20105
  const yRelativeToHost = event.clientY - hostRect.top;
20073
20106
  const activePointers = Array.from(this._core.store.state.pointers.values());
20074
20107
  if (this._core.store.state.isScaling || activePointers.length > 1) {
20075
- this._core.store.state.objects?.clearCursorPosition();
20108
+ this._core.store.objects?.clearCursorPosition();
20076
20109
  }
20077
20110
  else {
20078
20111
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
@@ -20085,7 +20118,7 @@ class KritzelViewport {
20085
20118
  }
20086
20119
  }
20087
20120
  if (this._touchCursorBroadcastActive) {
20088
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20121
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20089
20122
  }
20090
20123
  }
20091
20124
  if (activePointers.length === 2) {
@@ -20284,12 +20317,12 @@ class KritzelViewport {
20284
20317
  */
20285
20318
  handleZoom(event) {
20286
20319
  this._core.store.state.isScaling = true;
20287
- const rect = this._core.store.state.host.getBoundingClientRect();
20320
+ const rect = this._core.store.host.getBoundingClientRect();
20288
20321
  const xRelativeToHost = event.clientX - rect.left;
20289
20322
  const yRelativeToHost = event.clientY - rect.top;
20290
20323
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
20291
20324
  this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
20292
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20325
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20293
20326
  const rawScaleFactor = 1 + (event.deltaY * -0.012);
20294
20327
  const scaleFactor = Math.max(0.8, Math.min(1.2, rawScaleFactor));
20295
20328
  const effectiveMinScale = this.getEffectiveMinScale();
@@ -20637,7 +20670,7 @@ class KritzelContextMenuHandler extends workspace_migrations.KritzelBaseHandler
20637
20670
  const selectionTool = this._core.store.state.activeTool;
20638
20671
  selectionTool?.moveHandler?.cancelPendingDrag();
20639
20672
  if (this._core.store.selectionBox) {
20640
- this._core.store.state.objects.remove(object => object instanceof workspace_migrations.KritzelSelectionBox);
20673
+ this._core.store.objects.remove(object => object instanceof workspace_migrations.KritzelSelectionBox);
20641
20674
  this._core.store.setSelectionBox(null);
20642
20675
  this._core.store.state.isSelecting = false;
20643
20676
  }
@@ -20726,7 +20759,7 @@ class KritzelCustomElement extends workspace_migrations.KritzelBaseObject {
20726
20759
  const object = new KritzelCustomElement(config);
20727
20760
  object._core = core;
20728
20761
  object.id = object.generateId();
20729
- object.workspaceId = core.store.state.activeWorkspace.id;
20762
+ object.workspaceId = core.store.activeWorkspace.id;
20730
20763
  object.userId = core.user?.id;
20731
20764
  return object;
20732
20765
  }
@@ -20772,7 +20805,7 @@ class KritzelCustomElement extends workspace_migrations.KritzelBaseObject {
20772
20805
  this.element.style.height = `${height}px`;
20773
20806
  }
20774
20807
  // Update to sync changes to y.js and propagate to other tabs
20775
- this._core.store.state.objects.update(this);
20808
+ this._core.store.objects.update(this);
20776
20809
  }
20777
20810
  /**
20778
20811
  * Creates a deep copy of this custom element.
@@ -20900,7 +20933,7 @@ class KritzelReviver {
20900
20933
  }
20901
20934
 
20902
20935
  const DEFAULT_ENGINE_CONFIG = {
20903
- activeWorkspace: null,
20936
+ activeWorkspace: undefined,
20904
20937
  activeTool: null,
20905
20938
  copiedObjects: null,
20906
20939
  objects: null,
@@ -20926,7 +20959,7 @@ const DEFAULT_ENGINE_CONFIG = {
20926
20959
  isDrawing: false,
20927
20960
  isErasing: false,
20928
20961
  isWriting: false,
20929
- isWorkspaceLoading: false,
20962
+ isLoading: false,
20930
20963
  isCtrlKeyPressed: false,
20931
20964
  isContextMenuVisible: false,
20932
20965
  contextMenuItems: [],
@@ -21690,9 +21723,9 @@ class KritzelObjectMap {
21690
21723
  objectsToDelete.push(key);
21691
21724
  }
21692
21725
  else {
21693
- const serialized = this._objectsMap.get(key);
21726
+ const serialized = this._objectsMap?.get(key);
21694
21727
  if (serialized) {
21695
- const object = this._reviver.revive(serialized);
21728
+ const object = this._reviver?.revive(serialized);
21696
21729
  // Separate SelectionGroups to process them after regular objects
21697
21730
  if (object instanceof workspace_migrations.KritzelSelectionGroup) {
21698
21731
  selectionGroupsToUpdate.push(object);
@@ -21799,17 +21832,17 @@ class KritzelObjectMap {
21799
21832
  return;
21800
21833
  }
21801
21834
  this._ydoc.transact(() => {
21802
- if (!this._metadataMap.get('type')) {
21803
- this._metadataMap.set('type', type);
21835
+ if (!this._metadataMap?.get('type')) {
21836
+ this._metadataMap?.set('type', type);
21804
21837
  }
21805
- if (this._metadataMap.get('isPublic') === undefined) {
21806
- this._metadataMap.set('isPublic', false);
21838
+ if (this._metadataMap?.get('isPublic') === undefined) {
21839
+ this._metadataMap?.set('isPublic', false);
21807
21840
  }
21808
- if (this._metadataMap.get('schemaVersion') === undefined) {
21809
- this._metadataMap.set('schemaVersion', workspace_migrations.CURRENT_WORKSPACE_SCHEMA_VERSION);
21841
+ if (this._metadataMap?.get('schemaVersion') === undefined) {
21842
+ this._metadataMap?.set('schemaVersion', workspace_migrations.CURRENT_WORKSPACE_SCHEMA_VERSION);
21810
21843
  }
21811
- this._metadataMap.set('workspaceId', workspaceId);
21812
- this._metadataMap.set('workspaceName', workspaceName);
21844
+ this._metadataMap?.set('workspaceId', workspaceId);
21845
+ this._metadataMap?.set('workspaceName', workspaceName);
21813
21846
  }, 'metadata');
21814
21847
  }
21815
21848
  /**
@@ -21827,8 +21860,8 @@ class KritzelObjectMap {
21827
21860
  if (!this._metadataMap || !this._ydoc) {
21828
21861
  return;
21829
21862
  }
21830
- this._ydoc.transact(() => {
21831
- this._metadataMap.set('isPublic', isPublic);
21863
+ this._ydoc?.transact(() => {
21864
+ this._metadataMap?.set('isPublic', isPublic);
21832
21865
  }, 'metadata');
21833
21866
  }
21834
21867
  /**
@@ -21852,8 +21885,8 @@ class KritzelObjectMap {
21852
21885
  if (!this._metadataMap || !this._ydoc) {
21853
21886
  return;
21854
21887
  }
21855
- this._ydoc.transact(() => {
21856
- this._metadataMap.set('workspaceName', name);
21888
+ this._ydoc?.transact(() => {
21889
+ this._metadataMap?.set('workspaceName', name);
21857
21890
  }, 'metadata');
21858
21891
  }
21859
21892
  /**
@@ -21888,13 +21921,16 @@ class KritzelObjectMap {
21888
21921
  const localUserId = this._core?.user?.id;
21889
21922
  const staleSelectionGroupIds = [];
21890
21923
  this._objectsMap.forEach((serialized, key) => {
21891
- const object = this._reviver.revive(serialized);
21924
+ const object = this._reviver?.revive(serialized);
21892
21925
  // Remove remote selection groups on startup — they are transient UI state
21893
21926
  // that should not survive an app restart. The owning user's session is gone.
21894
21927
  if (object instanceof workspace_migrations.KritzelSelectionGroup && object.userId != null && object.userId !== localUserId) {
21895
21928
  staleSelectionGroupIds.push(key);
21896
21929
  return;
21897
21930
  }
21931
+ if (!object) {
21932
+ return;
21933
+ }
21898
21934
  this.quadtree.insert(object);
21899
21935
  this._idMap.set(object.id, object);
21900
21936
  });
@@ -21915,8 +21951,8 @@ class KritzelObjectMap {
21915
21951
  reset() {
21916
21952
  this.quadtree.reset();
21917
21953
  this._idMap.clear();
21918
- this._ydoc.transact(() => {
21919
- this._objectsMap.clear();
21954
+ this._ydoc?.transact(() => {
21955
+ this._objectsMap?.clear();
21920
21956
  }, 'local');
21921
21957
  }
21922
21958
  /**
@@ -21935,8 +21971,8 @@ class KritzelObjectMap {
21935
21971
  this._idMap.set(object.id, object);
21936
21972
  if (this._objectsMap && this.isPersistable(object)) {
21937
21973
  const serialized = object.serialize();
21938
- this._ydoc.transact(() => {
21939
- this._objectsMap.set(object.id, serialized);
21974
+ this._ydoc?.transact(() => {
21975
+ this._objectsMap?.set(object.id, serialized);
21940
21976
  }, 'local');
21941
21977
  }
21942
21978
  return true;
@@ -21965,8 +22001,8 @@ class KritzelObjectMap {
21965
22001
  if (this._objectsMap && this.isPersistable(object)) {
21966
22002
  const serialized = object.serialize();
21967
22003
  const origin = options.temporary ? 'temporary' : 'local';
21968
- this._ydoc.transact(() => {
21969
- this._objectsMap.set(object.id, serialized);
22004
+ this._ydoc?.transact(() => {
22005
+ this._objectsMap?.set(object.id, serialized);
21970
22006
  }, origin);
21971
22007
  }
21972
22008
  return true;
@@ -21983,8 +22019,8 @@ class KritzelObjectMap {
21983
22019
  this.quadtree.remove(o => o.id === object.id);
21984
22020
  this._idMap.delete(object.id);
21985
22021
  if (this._objectsMap && this.isPersistable(object)) {
21986
- this._ydoc.transact(() => {
21987
- this._objectsMap.delete(object.id);
22022
+ this._ydoc?.transact(() => {
22023
+ this._objectsMap?.delete(object.id);
21988
22024
  }, 'local');
21989
22025
  }
21990
22026
  }
@@ -22042,7 +22078,7 @@ class KritzelObjectMap {
22042
22078
  undo() {
22043
22079
  if (this._undoManager && this._undoManager.canUndo()) {
22044
22080
  this._undoManager.undo();
22045
- this._core.engine.emitObjectsChange();
22081
+ this._core?.engine.emitObjectsChange();
22046
22082
  }
22047
22083
  }
22048
22084
  /**
@@ -22052,7 +22088,7 @@ class KritzelObjectMap {
22052
22088
  redo() {
22053
22089
  if (this._undoManager && this._undoManager.canRedo()) {
22054
22090
  this._undoManager.redo();
22055
- this._core.engine.emitObjectsChange();
22091
+ this._core?.engine.emitObjectsChange();
22056
22092
  }
22057
22093
  }
22058
22094
  /**
@@ -22121,9 +22157,9 @@ class KritzelObjectMap {
22121
22157
  }
22122
22158
  // Now redo them all as a single 'local' transaction
22123
22159
  // This will consolidate them into one undo item
22124
- this._ydoc.transact(() => {
22160
+ this._ydoc?.transact(() => {
22125
22161
  for (let i = itemsToConsolidate - 1; i >= 0; i--) {
22126
- if (this._undoManager.canRedo()) {
22162
+ if (this._undoManager?.canRedo()) {
22127
22163
  this._undoManager.redo();
22128
22164
  }
22129
22165
  }
@@ -22239,13 +22275,49 @@ class KritzelStore {
22239
22275
  get state() {
22240
22276
  return this._state;
22241
22277
  }
22278
+ /**
22279
+ * Gets the map of all objects in the workspace.
22280
+ * Throws an error if the objects map is not initialized, as it is required for all object management.
22281
+ * @returns The KritzelObjectMap containing all objects
22282
+ * @throws Error if the objects map is not initialized in the state
22283
+ */
22284
+ get objects() {
22285
+ if (!this._state.objects) {
22286
+ throw new Error('Objects map is not initialized.');
22287
+ }
22288
+ return this._state.objects;
22289
+ }
22290
+ /**
22291
+ * Gets the currently active workspace.
22292
+ * Throws an error if no active workspace is set, as it is required for workspace-bound operations.
22293
+ * @returns The current active KritzelWorkspace
22294
+ * @throws Error if no active workspace is set in the state
22295
+ */
22296
+ get activeWorkspace() {
22297
+ if (!this._state.activeWorkspace) {
22298
+ throw new Error('Active workspace is not set.');
22299
+ }
22300
+ return this._state.activeWorkspace;
22301
+ }
22302
+ /**
22303
+ * Gets the host element for the Kritzel editor.
22304
+ * Throws an error if the host is not set, as it is required for many operations.
22305
+ * @returns The host HTMLElement
22306
+ * @throws Error if the host element is not set in the state
22307
+ */
22308
+ get host() {
22309
+ if (!this._state.host) {
22310
+ throw new Error('Host element is not set.');
22311
+ }
22312
+ return this._state.host;
22313
+ }
22242
22314
  /**
22243
22315
  * Gets the next available z-index for new objects.
22244
22316
  * Calculates the maximum z-index among all non-selection objects and adds 1.
22245
22317
  * @returns The next z-index value to use for new objects
22246
22318
  */
22247
22319
  get currentZIndex() {
22248
- return Math.max(0, ...this._state.objects.filter(o => !(o instanceof workspace_migrations.KritzelSelectionGroup) && !(o instanceof workspace_migrations.KritzelSelectionBox)).map(o => o.zIndex)) + 1;
22320
+ return Math.max(0, ...this.objects.filter(o => !(o instanceof workspace_migrations.KritzelSelectionGroup) && !(o instanceof workspace_migrations.KritzelSelectionBox)).map(o => o.zIndex)) + 1;
22249
22321
  }
22250
22322
  /**
22251
22323
  * Returns true if viewport boundaries are set to finite values (not Infinity).
@@ -22282,7 +22354,7 @@ class KritzelStore {
22282
22354
  if (this.hasViewportBoundaries) {
22283
22355
  return this.allObjects.length;
22284
22356
  }
22285
- return this._state.objects.totalCount;
22357
+ return this.objects.totalCount;
22286
22358
  }
22287
22359
  /**
22288
22360
  * Gets all objects in the workspace.
@@ -22291,9 +22363,9 @@ class KritzelStore {
22291
22363
  */
22292
22364
  get allObjects() {
22293
22365
  if (this.hasViewportBoundaries) {
22294
- return this._state.objects.query(this.viewportBoundaryBounds);
22366
+ return this.objects.query(this.viewportBoundaryBounds);
22295
22367
  }
22296
- return this._state.objects.allObjects();
22368
+ return this.objects.allObjects();
22297
22369
  }
22298
22370
  /**
22299
22371
  * Gets all objects currently visible in the viewport.
@@ -22309,7 +22381,7 @@ class KritzelStore {
22309
22381
  height: this._state.viewportHeight / this._state.scale,
22310
22382
  depth: 100,
22311
22383
  };
22312
- return this._state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
22384
+ return this.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
22313
22385
  }
22314
22386
  /**
22315
22387
  * Gets all objects excluding selection-related objects (selection group and selection box).
@@ -22334,7 +22406,7 @@ class KritzelStore {
22334
22406
  if (this._selectionBoxCacheValid) {
22335
22407
  return this._cachedSelectionBox;
22336
22408
  }
22337
- const selectionBoxes = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelSelectionBox);
22409
+ const selectionBoxes = this.objects.filter(o => o instanceof workspace_migrations.KritzelSelectionBox);
22338
22410
  this._cachedSelectionBox = selectionBoxes.length > 0 ? selectionBoxes[0] : null;
22339
22411
  this._selectionBoxCacheValid = true;
22340
22412
  return this._cachedSelectionBox;
@@ -22349,7 +22421,7 @@ class KritzelStore {
22349
22421
  if (this._selectionGroupCacheValid) {
22350
22422
  return this._cachedSelectionGroup;
22351
22423
  }
22352
- const selectionGroups = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelSelectionGroup);
22424
+ const selectionGroups = this.objects.filter(o => o instanceof workspace_migrations.KritzelSelectionGroup);
22353
22425
  if (this._localUserId) {
22354
22426
  this._cachedSelectionGroup = selectionGroups.find(sg => sg.userId === this._localUserId) ?? null;
22355
22427
  }
@@ -22398,7 +22470,7 @@ class KritzelStore {
22398
22470
  * @returns The text object in editing mode, or null if none
22399
22471
  */
22400
22472
  get activeText() {
22401
- const activeTexts = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelText && o.isEditing);
22473
+ const activeTexts = this.objects.filter(o => o instanceof workspace_migrations.KritzelText && o.isEditing);
22402
22474
  return activeTexts.length > 0 ? activeTexts[0] : null;
22403
22475
  }
22404
22476
  /**
@@ -22406,7 +22478,7 @@ class KritzelStore {
22406
22478
  * @returns The shape object in editing mode, or null if none
22407
22479
  */
22408
22480
  get activeShape() {
22409
- const activeShapes = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelShape && o.isEditing);
22481
+ const activeShapes = this.objects.filter(o => o instanceof workspace_migrations.KritzelShape && o.isEditing);
22410
22482
  return activeShapes.length > 0 ? activeShapes[0] : null;
22411
22483
  }
22412
22484
  /**
@@ -22414,7 +22486,7 @@ class KritzelStore {
22414
22486
  * @returns The incomplete path object, or null if no path is being drawn
22415
22487
  */
22416
22488
  get currentPath() {
22417
- const drawingPaths = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelPath && o.isCompleted === false);
22489
+ const drawingPaths = this.objects.filter(o => o instanceof workspace_migrations.KritzelPath && o.isCompleted === false);
22418
22490
  return drawingPaths.length > 0 ? drawingPaths[0] : null;
22419
22491
  }
22420
22492
  /**
@@ -22422,7 +22494,7 @@ class KritzelStore {
22422
22494
  * @returns The incomplete line object, or null if no line is being drawn
22423
22495
  */
22424
22496
  get currentLine() {
22425
- const drawingLines = this._state.objects.filter(o => o instanceof workspace_migrations.KritzelLine && o.isCompleted === false);
22497
+ const drawingLines = this.objects.filter(o => o instanceof workspace_migrations.KritzelLine && o.isCompleted === false);
22426
22498
  return drawingLines.length > 0 ? drawingLines[0] : null;
22427
22499
  }
22428
22500
  /**
@@ -22430,14 +22502,14 @@ class KritzelStore {
22430
22502
  * @returns The left position of the host element in client coordinates
22431
22503
  */
22432
22504
  get offsetX() {
22433
- return this._state.host.getBoundingClientRect().left;
22505
+ return this.host.getBoundingClientRect().left;
22434
22506
  }
22435
22507
  /**
22436
22508
  * Gets the vertical offset of the host element from the viewport.
22437
22509
  * @returns The top position of the host element in client coordinates
22438
22510
  */
22439
22511
  get offsetY() {
22440
- return this._state.host.getBoundingClientRect().top;
22512
+ return this.host.getBoundingClientRect().top;
22441
22513
  }
22442
22514
  /**
22443
22515
  * Checks if the engine is currently disabled.
@@ -22473,7 +22545,11 @@ class KritzelStore {
22473
22545
  if (!this._listeners.has(property)) {
22474
22546
  this._listeners.set(property, new Set());
22475
22547
  }
22476
- this._listeners.get(property).add(listener);
22548
+ const listenersForProperty = this._listeners.get(property);
22549
+ if (!listenersForProperty) {
22550
+ throw new Error(`Listeners set for property ${String(property)} was not initialized.`);
22551
+ }
22552
+ listenersForProperty.add(listener);
22477
22553
  }
22478
22554
  /**
22479
22555
  * Gets the current value of a state property as readonly.
@@ -22495,8 +22571,9 @@ class KritzelStore {
22495
22571
  const oldValue = this._state[property];
22496
22572
  if (oldValue !== value) {
22497
22573
  this._state[property] = value;
22498
- if (this._listeners.has(property)) {
22499
- this._listeners.get(property).forEach(listener => listener(value, oldValue, String(property)));
22574
+ const listenersForProperty = this._listeners.get(property);
22575
+ if (listenersForProperty) {
22576
+ listenersForProperty.forEach(listener => listener(value, oldValue, String(property)));
22500
22577
  }
22501
22578
  }
22502
22579
  }
@@ -22705,7 +22782,9 @@ class KritzelAppStateMap {
22705
22782
  };
22706
22783
  }
22707
22784
  const workspace = new workspace_migrations.KritzelWorkspace(serialized.id, serialized.name, viewport);
22708
- workspace._core = this._core;
22785
+ if (this._core) {
22786
+ workspace._core = this._core;
22787
+ }
22709
22788
  workspace.createdAt = new Date(serialized.createdAt);
22710
22789
  workspace.updatedAt = new Date(serialized.updatedAt);
22711
22790
  workspace.isPublic = serialized.isPublic ?? false;
@@ -22720,14 +22799,14 @@ class KritzelAppStateMap {
22720
22799
  return;
22721
22800
  }
22722
22801
  this._ydoc.transact(() => {
22723
- if (!this._metadataMap.get('type')) {
22724
- this._metadataMap.set('type', type);
22802
+ if (!this._metadataMap?.get('type')) {
22803
+ this._metadataMap?.set('type', type);
22725
22804
  }
22726
- if (this._metadataMap.get('isPublic') === undefined) {
22727
- this._metadataMap.set('isPublic', false);
22805
+ if (this._metadataMap?.get('isPublic') === undefined) {
22806
+ this._metadataMap?.set('isPublic', false);
22728
22807
  }
22729
- if (this._metadataMap.get('schemaVersion') === undefined) {
22730
- this._metadataMap.set('schemaVersion', workspace_migrations.CURRENT_APP_STATE_SCHEMA_VERSION);
22808
+ if (this._metadataMap?.get('schemaVersion') === undefined) {
22809
+ this._metadataMap?.set('schemaVersion', workspace_migrations.CURRENT_APP_STATE_SCHEMA_VERSION);
22731
22810
  }
22732
22811
  }, 'metadata');
22733
22812
  }
@@ -22746,7 +22825,7 @@ class KritzelAppStateMap {
22746
22825
  return;
22747
22826
  }
22748
22827
  this._ydoc.transact(() => {
22749
- this._metadataMap.set('isPublic', isPublic);
22828
+ this._metadataMap?.set('isPublic', isPublic);
22750
22829
  }, 'metadata');
22751
22830
  }
22752
22831
  /**
@@ -22786,8 +22865,8 @@ class KritzelAppStateMap {
22786
22865
  */
22787
22866
  reset() {
22788
22867
  this.map.clear();
22789
- this._ydoc.transact(() => {
22790
- this._workspacesMap.clear();
22868
+ this._ydoc?.transact(() => {
22869
+ this._workspacesMap?.clear();
22791
22870
  }, 'local');
22792
22871
  }
22793
22872
  /**
@@ -22803,8 +22882,8 @@ class KritzelAppStateMap {
22803
22882
  this.map.set(workspace.id, workspace);
22804
22883
  if (this._workspacesMap) {
22805
22884
  const serialized = workspace.serialize();
22806
- this._ydoc.transact(() => {
22807
- this._workspacesMap.set(workspace.id, serialized);
22885
+ this._ydoc?.transact(() => {
22886
+ this._workspacesMap?.set(workspace.id, serialized);
22808
22887
  }, 'local');
22809
22888
  }
22810
22889
  return true;
@@ -22822,8 +22901,8 @@ class KritzelAppStateMap {
22822
22901
  this.map.set(workspace.id, workspace);
22823
22902
  if (this._workspacesMap) {
22824
22903
  const serialized = workspace.serialize();
22825
- this._ydoc.transact(() => {
22826
- this._workspacesMap.set(workspace.id, serialized);
22904
+ this._ydoc?.transact(() => {
22905
+ this._workspacesMap?.set(workspace.id, serialized);
22827
22906
  }, 'local');
22828
22907
  }
22829
22908
  return true;
@@ -22841,8 +22920,8 @@ class KritzelAppStateMap {
22841
22920
  }
22842
22921
  this.map.delete(workspaceToRemove.id);
22843
22922
  if (this._workspacesMap) {
22844
- this._ydoc.transact(() => {
22845
- this._workspacesMap.delete(workspaceToRemove.id);
22923
+ this._ydoc?.transact(() => {
22924
+ this._workspacesMap?.delete(workspaceToRemove.id);
22846
22925
  }, 'local');
22847
22926
  }
22848
22927
  return true;
@@ -23154,7 +23233,7 @@ class KritzelCore {
23154
23233
  setUser(user) {
23155
23234
  this._user = user;
23156
23235
  this._store.setLocalUserId(user?.id ?? null);
23157
- this._store.state.objects?.setLocalUser(user);
23236
+ this._store.objects?.setLocalUser(user);
23158
23237
  }
23159
23238
  /**
23160
23239
  * Creates a new KritzelCore instance.
@@ -23273,8 +23352,8 @@ class KritzelCore {
23273
23352
  // Save active workspace ID to localStorage
23274
23353
  localStorage.setItem(this.getStorageKey('kritzel-active-workspace-id'), activeWorkspace.id);
23275
23354
  // Destroy old ObjectMap if switching workspaces
23276
- if (this._store.state.objects && this._store.state.objects.isReady) {
23277
- this._store.state.objects.destroy();
23355
+ if (this._store.objects && this._store.objects.isReady) {
23356
+ this._store.objects.destroy();
23278
23357
  }
23279
23358
  // Create new ObjectMap with its own Y.Doc for this workspace
23280
23359
  const objectsMap = new KritzelObjectMap();
@@ -23344,7 +23423,10 @@ class KritzelCore {
23344
23423
  height: this._store.state.viewportHeight / this._store.state.scale,
23345
23424
  depth: 100,
23346
23425
  };
23347
- return this._store.state.objects
23426
+ if (!this._store.objects) {
23427
+ return [];
23428
+ }
23429
+ return this._store.objects
23348
23430
  .query(viewportBounds)
23349
23431
  .filter(obj => !(obj instanceof workspace_migrations.KritzelSelectionGroup) && !(obj instanceof workspace_migrations.KritzelSelectionBox))
23350
23432
  .sort((a, b) => a.zIndex - b.zIndex);
@@ -23399,8 +23481,8 @@ class KritzelCore {
23399
23481
  workspace.updatedAt = new Date();
23400
23482
  this.saveWorkspaceToAppState(workspace);
23401
23483
  // Keep metadata map in sync when the active workspace's name changes
23402
- if (this._store.state.activeWorkspace?.id === workspace.id) {
23403
- this._store.state.objects?.setWorkspaceName(workspace.name);
23484
+ if (this._store.activeWorkspace?.id === workspace.id) {
23485
+ this._store.objects?.setWorkspaceName(workspace.name);
23404
23486
  }
23405
23487
  const workspaces = this._store.state.workspaces;
23406
23488
  const index = workspaces.findIndex(w => w.id === workspace.id);
@@ -23417,9 +23499,9 @@ class KritzelCore {
23417
23499
  */
23418
23500
  deleteWorkspace(workspace) {
23419
23501
  // If deleting the active workspace, need to handle ObjectMap cleanup
23420
- if (this._store.state.activeWorkspace?.id === workspace.id) {
23502
+ if (this._store.activeWorkspace?.id === workspace.id) {
23421
23503
  this.engine.viewport?.cancelPendingUpdates();
23422
- this._store.state.objects?.destroy();
23504
+ this._store.objects?.destroy();
23423
23505
  }
23424
23506
  this.deleteWorkspaceFromAppState(workspace.id);
23425
23507
  this._store.state.workspaces = this.loadWorkspacesFromAppState();
@@ -23438,7 +23520,7 @@ class KritzelCore {
23438
23520
  * @param scale - The zoom scale of the viewport
23439
23521
  */
23440
23522
  updateWorkspaceViewport(translateX, translateY, scale) {
23441
- const activeWorkspace = this._store.state.activeWorkspace;
23523
+ const activeWorkspace = this._store.activeWorkspace;
23442
23524
  if (!activeWorkspace) {
23443
23525
  return;
23444
23526
  }
@@ -23461,7 +23543,7 @@ class KritzelCore {
23461
23543
  * @returns True if the workspace is public, false otherwise
23462
23544
  */
23463
23545
  getIsPublic() {
23464
- return this._store.state.activeWorkspace?.isPublic ?? false;
23546
+ return this._store.activeWorkspace?.isPublic ?? false;
23465
23547
  }
23466
23548
  // ═══════════════════════════════════════════════════════════════════════════
23467
23549
  // Object Management Methods
@@ -23471,7 +23553,7 @@ class KritzelCore {
23471
23553
  * @param object - The object to add to the canvas
23472
23554
  */
23473
23555
  addObject(object) {
23474
- this._store.state.objects.insert(object);
23556
+ this._store.objects.insert(object);
23475
23557
  }
23476
23558
  /**
23477
23559
  * Removes an object from the workspace.
@@ -23499,7 +23581,7 @@ class KritzelCore {
23499
23581
  this._anchorManager.handleObjectDeleted(object.id);
23500
23582
  }
23501
23583
  object.isMounted = false;
23502
- this._store.state.objects.remove(o => o.id === object.id);
23584
+ this._store.objects.remove(o => o.id === object.id);
23503
23585
  }
23504
23586
  /**
23505
23587
  * Updates properties on an object and persists the changes.
@@ -23512,12 +23594,15 @@ class KritzelCore {
23512
23594
  const changedKeys = [];
23513
23595
  for (const key in updatedProperties) {
23514
23596
  if (updatedProperties.hasOwnProperty(key)) {
23515
- object[key] = updatedProperties[key];
23516
- changedKeys.push(key);
23597
+ const value = updatedProperties[key];
23598
+ if (value !== undefined) {
23599
+ object[key] = value;
23600
+ changedKeys.push(key);
23601
+ }
23517
23602
  }
23518
23603
  }
23519
23604
  object.onAfterUpdate(changedKeys);
23520
- this._store.state.objects.update(object);
23605
+ this._store.objects.update(object);
23521
23606
  }
23522
23607
  /**
23523
23608
  * Adds a selection group to the canvas.
@@ -23528,7 +23613,7 @@ class KritzelCore {
23528
23613
  addSelectionGroup(selectionGroup) {
23529
23614
  this.removeSelectionGroup();
23530
23615
  this.removeSelectionBox();
23531
- this._store.state.objects.insert(selectionGroup);
23616
+ this._store.objects.insert(selectionGroup);
23532
23617
  this._store.setSelectionGroup(selectionGroup);
23533
23618
  this._kritzelEngine.triggerSelectionChange();
23534
23619
  }
@@ -23539,7 +23624,7 @@ class KritzelCore {
23539
23624
  removeSelectionGroup() {
23540
23625
  const selectionGroup = this._store.selectionGroup;
23541
23626
  if (selectionGroup) {
23542
- this._store.state.objects.remove(object => object.id === selectionGroup.id);
23627
+ this._store.objects.remove(object => object.id === selectionGroup.id);
23543
23628
  this._store.setSelectionGroup(null);
23544
23629
  this._kritzelEngine.triggerSelectionChange();
23545
23630
  }
@@ -23551,9 +23636,9 @@ class KritzelCore {
23551
23636
  removeSelectionBox() {
23552
23637
  const selectionBox = this._store.selectionBox;
23553
23638
  if (selectionBox) {
23554
- this._store.state.objects.remove(object => object.id === selectionBox.id);
23639
+ this._store.objects.remove(object => object.id === selectionBox.id);
23555
23640
  this._store.setSelectionBox(null);
23556
- this._store.state.objects.clearLocalSelectionBox();
23641
+ this._store.objects.clearLocalSelectionBox();
23557
23642
  }
23558
23643
  }
23559
23644
  /**
@@ -23582,13 +23667,13 @@ class KritzelCore {
23582
23667
  * Undoes the last action in the history stack.
23583
23668
  */
23584
23669
  undo() {
23585
- this._store.state.objects?.undo();
23670
+ this._store.objects?.undo();
23586
23671
  }
23587
23672
  /**
23588
23673
  * Redoes the last undone action from the history stack.
23589
23674
  */
23590
23675
  redo() {
23591
- this._store.state.objects?.redo();
23676
+ this._store.objects?.redo();
23592
23677
  }
23593
23678
  /**
23594
23679
  * Deletes a specific object by its ID.
@@ -23650,7 +23735,7 @@ class KritzelCore {
23650
23735
  if (!copiedObjects || copiedObjects.length === 0) {
23651
23736
  return;
23652
23737
  }
23653
- const activeWorkspace = this._store.state.activeWorkspace;
23738
+ const activeWorkspace = this._store.activeWorkspace;
23654
23739
  const originalIdMapping = this._store.state.copiedObjectIdMapping;
23655
23740
  // Check if we're pasting from a different workspace
23656
23741
  const isDifferentWorkspace = copiedObjects.some(obj => obj.workspaceId !== activeWorkspace.id);
@@ -23695,7 +23780,7 @@ class KritzelCore {
23695
23780
  const baseZIndex = this._store.currentZIndex;
23696
23781
  // Batch all inserts and updates in a single Y.js transaction to avoid
23697
23782
  // N separate observer callbacks and N rerenders (fires only once at commit)
23698
- this._store.state.objects.transaction(() => {
23783
+ this._store.objects.transaction(() => {
23699
23784
  // First add all copied objects to the objectsMap with updated positions
23700
23785
  copiedObjects.forEach((obj, i) => {
23701
23786
  // Update workspace if pasting to a different workspace
@@ -23747,7 +23832,7 @@ class KritzelCore {
23747
23832
  }
23748
23833
  // If anchors were updated, rebuild the anchor index and persist the change
23749
23834
  if (updated) {
23750
- this._store.state.objects.update(obj);
23835
+ this._store.objects.update(obj);
23751
23836
  }
23752
23837
  }
23753
23838
  });
@@ -23869,7 +23954,7 @@ class KritzelCore {
23869
23954
  }
23870
23955
  const objects = selectionGroup.objects;
23871
23956
  const alignedPositions = AlignmentHelper.calculateAlignedPositions(objects, alignment);
23872
- this._store.state.objects.transaction(() => {
23957
+ this._store.objects.transaction(() => {
23873
23958
  for (const obj of objects) {
23874
23959
  const newPosition = alignedPositions.get(obj.id);
23875
23960
  if (newPosition) {
@@ -23967,7 +24052,7 @@ class KritzelCore {
23967
24052
  * Switches to selection tool.
23968
24053
  */
23969
24054
  selectAllObjects() {
23970
- const allObjects = this._store.state.objects
24055
+ const allObjects = this._store.objects
23971
24056
  .allObjects()
23972
24057
  .filter(o => !(o instanceof workspace_migrations.KritzelSelectionGroup) && !(o instanceof workspace_migrations.KritzelSelectionBox) && !(o instanceof KritzelContextMenu));
23973
24058
  if (allObjects.length > 0) {
@@ -24000,7 +24085,7 @@ class KritzelCore {
24000
24085
  height: this._store.state.viewportHeight / this._store.state.scale,
24001
24086
  depth: 100,
24002
24087
  };
24003
- const objectsInViewport = this._store.state.objects
24088
+ const objectsInViewport = this._store.objects
24004
24089
  .query(viewportBounds)
24005
24090
  .filter(o => o.isInViewport())
24006
24091
  .filter(o => !(o instanceof workspace_migrations.KritzelSelectionGroup) && !(o instanceof workspace_migrations.KritzelSelectionBox) && !(o instanceof KritzelContextMenu));
@@ -24027,7 +24112,7 @@ class KritzelCore {
24027
24112
  clearSelection() {
24028
24113
  this.removeSelectionGroup();
24029
24114
  const localUserId = this._user?.id;
24030
- this._store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox ||
24115
+ this._store.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox ||
24031
24116
  (o instanceof workspace_migrations.KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
24032
24117
  this._store.setSelectionBox(null);
24033
24118
  this._store.setSelectionGroup(null);
@@ -24036,7 +24121,7 @@ class KritzelCore {
24036
24121
  this._store.state.isRotationHandleSelected = false;
24037
24122
  this._store.state.isLineHandleSelected = false;
24038
24123
  this._store.state.isLineHandleDragging = false;
24039
- this._store.state.lineHandleType = null;
24124
+ this._store.state.lineHandleType = undefined;
24040
24125
  this.rerender();
24041
24126
  }
24042
24127
  /**
@@ -24082,7 +24167,9 @@ class KritzelCore {
24082
24167
  const selectedObject = elementAtPoint.closest(selector);
24083
24168
  if (selectedObject) {
24084
24169
  const foundObject = this._store.allObjects.find(object => selectedObject.id === object.id);
24085
- const isHit = foundObject?.hitTest(clientX, clientY);
24170
+ if (!foundObject)
24171
+ return null;
24172
+ const isHit = foundObject.hitTest(clientX, clientY);
24086
24173
  return isHit ? foundObject : null;
24087
24174
  }
24088
24175
  return null;
@@ -24164,7 +24251,7 @@ class KritzelCore {
24164
24251
  // saving the old workspace's viewport to the new workspace
24165
24252
  this._kritzelEngine.viewport?.cancelPendingUpdates();
24166
24253
  // Immediately save the current workspace's viewport before switching
24167
- const currentWorkspace = this._store.state.activeWorkspace;
24254
+ const currentWorkspace = this._store.activeWorkspace;
24168
24255
  if (currentWorkspace) {
24169
24256
  this.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
24170
24257
  }
@@ -25506,7 +25593,7 @@ async function toPng(node, options = {}) {
25506
25593
  return canvas.toDataURL();
25507
25594
  }
25508
25595
 
25509
- const kritzelEngineCss = () => `:host{display:block;position:relative;height:100%;width:100%;overflow:hidden;background-color:var(--kritzel-engine-background-color, #ffffff)}:host,:host *{touch-action:none;user-select:none}.ProseMirror{outline:none}p,h1,h2,h3,h4,h5,h6,blockquote,pre{margin:0;padding:0}.workspace-loading-overlay{position:absolute;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;background-color:var(--kritzel-loading-overlay-background, rgba(255, 255, 255, 0.6));color:var(--kritzel-loading-overlay-color, #333);font-size:1.25rem;pointer-events:all;animation:workspace-loading-fade-in var(--kritzel-loading-overlay-delay, 300ms) ease-out forwards;opacity:0}@keyframes workspace-loading-fade-in{to{opacity:1}}.debug-panel{position:absolute;pointer-events:none;top:0;right:0}.origin{position:relative;top:0;left:0;height:0;width:0;pointer-events:none;-webkit-transform-origin:top left;-moz-transform-origin:top left;transform-origin:top left;overflow:visible}.object{overflow:visible}.PlaygroundEditorTheme__quote{margin:0;margin-left:20px;margin-bottom:10px;font-size:15px;color:rgb(101, 103, 107);border-left-color:rgb(206, 208, 212);border-left-width:4px;border-left-style:solid;padding-left:16px}`;
25596
+ const kritzelEngineCss = () => `:host{display:block;position:relative;height:100%;width:100%;overflow:hidden;background-color:var(--kritzel-engine-background-color, #ffffff)}:host,:host *{touch-action:none;user-select:none}.ProseMirror{outline:none}p,h1,h2,h3,h4,h5,h6,blockquote,pre{margin:0;padding:0}.workspace-loading-overlay{position:absolute;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;gap:10px;background-color:var(--kritzel-loading-overlay-background, rgba(255, 255, 255, 0.6));color:var(--kritzel-loading-overlay-color, #333);font-family:var(--kritzel-font-family, sans-serif);font-size:1.25rem;pointer-events:all;animation:workspace-loading-fade-in 200ms ease-out var(--kritzel-loading-overlay-delay, 300ms) forwards;opacity:0}.workspace-loading-spinner{width:20px;height:20px;box-sizing:border-box;display:block;flex-shrink:0;border:2px solid var(--kritzel-loading-overlay-spinner-color, #cccccc);border-top-color:var(--kritzel-loading-overlay-spinner-active-color, #333333);border-radius:50%;animation:workspace-loading-spin 0.6s linear infinite}@keyframes workspace-loading-spin{to{transform:rotate(360deg)}}@keyframes workspace-loading-fade-in{to{opacity:1}}.debug-panel{position:absolute;pointer-events:none;top:0;right:0}.origin{position:relative;top:0;left:0;height:0;width:0;pointer-events:none;-webkit-transform-origin:top left;-moz-transform-origin:top left;transform-origin:top left;overflow:visible}.object{overflow:visible}.PlaygroundEditorTheme__quote{margin:0;margin-left:20px;margin-bottom:10px;font-size:15px;color:rgb(101, 103, 107);border-left-color:rgb(206, 208, 212);border-left-width:4px;border-left-style:solid;padding-left:16px}`;
25510
25597
 
25511
25598
  const KritzelEngine = class {
25512
25599
  get host() { return index.getElement(this); }
@@ -25519,13 +25606,13 @@ const KritzelEngine = class {
25519
25606
  }
25520
25607
  // Let batched prop updates settle, then perform an idempotent re-check.
25521
25608
  await Promise.resolve();
25522
- const currentWorkspaceId = this.core.store.state.activeWorkspace?.id;
25609
+ const currentWorkspaceId = this.core.store.activeWorkspace?.id;
25523
25610
  if (currentWorkspaceId === newWorkspaceId) {
25524
25611
  return;
25525
25612
  }
25526
25613
  this.core.beforeWorkspaceChange();
25527
25614
  await this.initializeWorkspaceIfNeeded(newWorkspace);
25528
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
25615
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
25529
25616
  }
25530
25617
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
25531
25618
  editorId;
@@ -25625,6 +25712,11 @@ const KritzelEngine = class {
25625
25712
  }
25626
25713
  /** When false, wheel events will not trigger viewport pan/zoom. The event still propagates to parent elements. */
25627
25714
  wheelEnabled = true;
25715
+ /** External loading state. Combined with internal workspace-loading state to drive the overlay. */
25716
+ isLoading = false;
25717
+ onIsLoadingChange() {
25718
+ this.syncLoadingState();
25719
+ }
25628
25720
  /** Emitted when the engine has fully initialized and is ready for interaction. */
25629
25721
  isEngineReady;
25630
25722
  /** Emitted when the active drawing tool changes. */
@@ -25733,7 +25825,7 @@ const KritzelEngine = class {
25733
25825
  this.core.store.state?.activeTool?.handlePointerUp(ev);
25734
25826
  }
25735
25827
  handlePointerLeave() {
25736
- this.core.store.state.objects?.clearCursorPosition();
25828
+ this.core.store.objects?.clearCursorPosition();
25737
25829
  }
25738
25830
  handleLongPress(ev) {
25739
25831
  this.contextMenuHandler.handleContextMenu(ev.detail);
@@ -25916,9 +26008,9 @@ const KritzelEngine = class {
25916
26008
  async hideContextMenu() {
25917
26009
  this.core.store.state.pointers.clear();
25918
26010
  this.core.store.state.isContextMenuVisible = false;
25919
- this.core.store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
26011
+ this.core.store.objects?.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
25920
26012
  this.core.store.setSelectionBox(null);
25921
- this.core.store.state.objects.clearLocalSelectionBox();
26013
+ this.core.store.objects?.clearLocalSelectionBox();
25922
26014
  this.core.store.state.isSelecting = false;
25923
26015
  this.core.store.state.isEnabled = true;
25924
26016
  this.core.rerender();
@@ -25972,7 +26064,7 @@ const KritzelEngine = class {
25972
26064
  object._core = this.core;
25973
26065
  object.scale = this.core.store.state.scale;
25974
26066
  object.zIndex = this.core.store.currentZIndex;
25975
- object.workspaceId = this.core.store.state.activeWorkspace.id;
26067
+ object.workspaceId = this.core.store.activeWorkspace.id;
25976
26068
  // Handle KritzelText: recreate the editor now that _core is available
25977
26069
  // The editor's dispatchTransaction callback needs _core for persisting changes
25978
26070
  if (workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
@@ -25993,7 +26085,7 @@ const KritzelEngine = class {
25993
26085
  child._core = this.core;
25994
26086
  child.scale = this.core.store.state.scale;
25995
26087
  child.zIndex = this.core.store.currentZIndex;
25996
- child.workspaceId = this.core.store.state.activeWorkspace.id;
26088
+ child.workspaceId = this.core.store.activeWorkspace.id;
25997
26089
  idRemapping.set(oldId, child.id);
25998
26090
  object.childIds.push(child.id);
25999
26091
  });
@@ -26047,8 +26139,12 @@ const KritzelEngine = class {
26047
26139
  * @returns The removed object.
26048
26140
  */
26049
26141
  async removeObject(object) {
26142
+ const objectsMap = this.core.store.objects;
26143
+ if (!objectsMap) {
26144
+ return null;
26145
+ }
26050
26146
  this.core.deselectAllObjects();
26051
- this.core.store.state.objects.remove(o => o.id === object.id);
26147
+ objectsMap.remove(o => o.id === object.id);
26052
26148
  this.core.rerender();
26053
26149
  this.emitObjectsRemoved([object]);
26054
26150
  return object;
@@ -26067,15 +26163,23 @@ const KritzelEngine = class {
26067
26163
  * @param objects - The objects to select.
26068
26164
  */
26069
26165
  async selectObjects(objects) {
26166
+ const selectionTool = workspace_migrations.KritzelToolRegistry.getTool('selection');
26167
+ if (!selectionTool) {
26168
+ return;
26169
+ }
26070
26170
  this.core.store.state.activeTool?.onDeactivate();
26071
- this.core.store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
26171
+ this.core.store.setState('activeTool', selectionTool);
26072
26172
  this.core.deselectAllObjects();
26073
26173
  this.core.selectObjects(objects);
26074
26174
  }
26075
26175
  /** Selects all objects currently visible in the viewport. Switches to the selection tool automatically. */
26076
26176
  async selectAllObjectsInViewport() {
26177
+ const selectionTool = workspace_migrations.KritzelToolRegistry.getTool('selection');
26178
+ if (!selectionTool) {
26179
+ return;
26180
+ }
26077
26181
  this.core.store.state.activeTool?.onDeactivate();
26078
- this.core.store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
26182
+ this.core.store.setState('activeTool', selectionTool);
26079
26183
  this.core.deselectAllObjects();
26080
26184
  this.core.selectAllObjectsInViewport();
26081
26185
  }
@@ -26181,8 +26285,8 @@ const KritzelEngine = class {
26181
26285
  return null;
26182
26286
  // Save critical state before screenshot to restore after
26183
26287
  const savedState = {
26184
- objects: this.core.store.state.objects,
26185
- activeWorkspace: this.core.store.state.activeWorkspace,
26288
+ objects: this.core.store.objects,
26289
+ activeWorkspace: this.core.store.activeWorkspace,
26186
26290
  workspaces: this.core.store.state.workspaces,
26187
26291
  activeTool: this.core.store.state.activeTool,
26188
26292
  isReady: this.core.store.state.isReady,
@@ -26233,6 +26337,10 @@ const KritzelEngine = class {
26233
26337
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26234
26338
  const filename = `${activeWorkspaceName}-${timestamp}.png`;
26235
26339
  const dataUrl = await this.getScreenshot('png');
26340
+ if (!dataUrl) {
26341
+ console.error('Failed to export viewport as PNG: screenshot could not be generated');
26342
+ return;
26343
+ }
26236
26344
  const link = document.createElement('a');
26237
26345
  link.download = filename;
26238
26346
  link.href = dataUrl;
@@ -26250,6 +26358,10 @@ const KritzelEngine = class {
26250
26358
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26251
26359
  const filename = `${activeWorkspaceName}-${timestamp}.svg`;
26252
26360
  const dataUrl = await this.getScreenshot('svg');
26361
+ if (!dataUrl) {
26362
+ console.error('Failed to export viewport as SVG: screenshot could not be generated');
26363
+ return;
26364
+ }
26253
26365
  const link = document.createElement('a');
26254
26366
  link.download = filename;
26255
26367
  link.href = dataUrl;
@@ -26372,7 +26484,10 @@ const KritzelEngine = class {
26372
26484
  * @returns A JSON string representing the complete workspace state.
26373
26485
  */
26374
26486
  async exportAsJson() {
26375
- const workspace = this.core.store.state.activeWorkspace;
26487
+ const workspace = this.core.store.activeWorkspace;
26488
+ if (!workspace) {
26489
+ throw new Error('Cannot export workspace: no active workspace is loaded');
26490
+ }
26376
26491
  const serialized = workspace.serialize({ includeObjects: true });
26377
26492
  return JSON.stringify(serialized, null, 2);
26378
26493
  }
@@ -26445,7 +26560,11 @@ const KritzelEngine = class {
26445
26560
  if (data.version && data.version !== workspace_migrations.WORKSPACE_EXPORT_VERSION) {
26446
26561
  console.warn(`Workspace version mismatch: expected ${workspace_migrations.WORKSPACE_EXPORT_VERSION}, got ${data.version}`);
26447
26562
  }
26448
- const currentWorkspaceId = this.core.store.state.activeWorkspace.id;
26563
+ const activeWorkspace = this.core.store.activeWorkspace;
26564
+ if (!activeWorkspace) {
26565
+ throw new Error('Cannot load objects: no active workspace is loaded');
26566
+ }
26567
+ const currentWorkspaceId = activeWorkspace.id;
26449
26568
  let loadedCount = 0;
26450
26569
  // Revive and add objects to the current workspace
26451
26570
  if (data.objects && Array.isArray(data.objects)) {
@@ -26581,7 +26700,11 @@ const KritzelEngine = class {
26581
26700
  }
26582
26701
  /** Returns the currently active workspace. */
26583
26702
  async getActiveWorkspace() {
26584
- return this.core.store.state.activeWorkspace;
26703
+ const activeWorkspace = this.core.store.activeWorkspace;
26704
+ if (!activeWorkspace) {
26705
+ throw new Error('No active workspace is loaded');
26706
+ }
26707
+ return activeWorkspace;
26585
26708
  }
26586
26709
  /**
26587
26710
  * Gets whether the active workspace is publicly accessible.
@@ -26610,7 +26733,7 @@ const KritzelEngine = class {
26610
26733
  this.workspacesChange.emit(this.core.store.state.workspaces);
26611
26734
  this.core.beforeWorkspaceChange();
26612
26735
  await this.initializeWorkspaceIfNeeded(workspace);
26613
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
26736
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
26614
26737
  }
26615
26738
  /**
26616
26739
  * Reinitializes sync by performing a full teardown and re-initialization.
@@ -26620,8 +26743,8 @@ const KritzelEngine = class {
26620
26743
  */
26621
26744
  async reinitSync() {
26622
26745
  this.core.setSyncConfig(this.syncConfig);
26623
- this.core.store.state.objects?.clearCursorPosition();
26624
- this.core.store.state.objects?.destroy();
26746
+ this.core.store.objects?.clearCursorPosition();
26747
+ this.core.store.objects?.destroy();
26625
26748
  this.core.appStateMap.destroy();
26626
26749
  this._isYjsInitialized = false;
26627
26750
  await this.initializeSyncAndWorkspace();
@@ -26639,6 +26762,16 @@ const KritzelEngine = class {
26639
26762
  _workspaceInitializationTargetKey = null;
26640
26763
  _syncInitPromise = null;
26641
26764
  _syncConfigRevision = 0;
26765
+ _isWorkspaceLoading = false;
26766
+ _defaultUndoState = {
26767
+ canUndo: false,
26768
+ canRedo: false,
26769
+ undoStackSize: 0,
26770
+ redoStackSize: 0,
26771
+ };
26772
+ syncLoadingState() {
26773
+ this.core.store.state.isLoading = this._isWorkspaceLoading || this.isLoading;
26774
+ }
26642
26775
  get isSelecting() {
26643
26776
  return this.core.store.state.activeTool instanceof workspace_migrations.KritzelSelectionTool && this.core.store.state.isSelecting;
26644
26777
  }
@@ -26666,10 +26799,10 @@ const KritzelEngine = class {
26666
26799
  disconnectedCallback() {
26667
26800
  this.throttledPointerMoveMulti.cancel();
26668
26801
  // Clear cursor position in awareness before destroying
26669
- this.core.store.state.objects?.clearCursorPosition();
26802
+ this.core.store.objects?.clearCursorPosition();
26670
26803
  // Clean up current workspace's ObjectMap
26671
- if (this.core.store.state.objects) {
26672
- this.core.store.state.objects.destroy();
26804
+ if (this.core.store.objects) {
26805
+ this.core.store.objects.destroy();
26673
26806
  }
26674
26807
  // Clean up AppStateMap (workspaces Y.Doc)
26675
26808
  this.core.appStateMap.destroy();
@@ -26687,6 +26820,8 @@ const KritzelEngine = class {
26687
26820
  this.core.store.state.viewportBoundaryRight = this.viewportBoundaryRight;
26688
26821
  this.core.store.state.viewportBoundaryTop = this.viewportBoundaryTop;
26689
26822
  this.core.store.state.viewportBoundaryBottom = this.viewportBoundaryBottom;
26823
+ this._isWorkspaceLoading = true;
26824
+ this.syncLoadingState();
26690
26825
  }
26691
26826
  async componentDidLoad() {
26692
26827
  setTimeout(async () => {
@@ -26695,7 +26830,9 @@ const KritzelEngine = class {
26695
26830
  this.viewport = new KritzelViewport(this.core, this.host);
26696
26831
  // Initialize cursor manager with target element and shadow root
26697
26832
  this.core.cursorManager.setTargetElement(this.cursorTarget || document.body);
26698
- this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
26833
+ if (this.host.shadowRoot) {
26834
+ this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
26835
+ }
26699
26836
  // Initialize theme manager with kritzel-editor as target element
26700
26837
  const editorElement = this.host.closest('kritzel-editor');
26701
26838
  this.core.themeManager.setTargetElement(editorElement || this.host);
@@ -26756,7 +26893,7 @@ const KritzelEngine = class {
26756
26893
  await this.initializeWorkspaceIfNeeded(startupWorkspace);
26757
26894
  }
26758
26895
  // Emit initial active workspace once startup initialization has completed
26759
- const initialActiveWorkspace = this.core.store.state.activeWorkspace;
26896
+ const initialActiveWorkspace = this.core.store.activeWorkspace;
26760
26897
  if (initialActiveWorkspace) {
26761
26898
  this.activeWorkspaceChange.emit(initialActiveWorkspace);
26762
26899
  }
@@ -26785,7 +26922,7 @@ const KritzelEngine = class {
26785
26922
  if (!this.activeWorkspaceId || this._isResolvingActiveWorkspaceId) {
26786
26923
  return;
26787
26924
  }
26788
- if (this.core.store.state.activeWorkspace?.id === this.activeWorkspaceId) {
26925
+ if (this.core.store.activeWorkspace?.id === this.activeWorkspaceId) {
26789
26926
  return;
26790
26927
  }
26791
26928
  this._isResolvingActiveWorkspaceId = true;
@@ -26801,24 +26938,25 @@ const KritzelEngine = class {
26801
26938
  }
26802
26939
  return;
26803
26940
  }
26804
- if (this.core.store.state.activeWorkspace?.id === workspace.id) {
26941
+ if (this.core.store.activeWorkspace?.id === workspace.id) {
26805
26942
  return;
26806
26943
  }
26807
26944
  this.core.beforeWorkspaceChange();
26808
26945
  await this.initializeWorkspaceIfNeeded(workspace);
26809
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
26946
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
26810
26947
  }
26811
26948
  async initializeWorkspaceIfNeeded(workspace, options) {
26812
26949
  const targetWorkspaceId = workspace?.id ?? null;
26813
26950
  const targetKey = targetWorkspaceId ?? (options?.skipFallbackCreation ? '__NO_FALLBACK__' : '__AUTO__');
26814
- if (targetWorkspaceId && this.core.store.state.activeWorkspace?.id === targetWorkspaceId) {
26951
+ if (targetWorkspaceId && this.core.store.activeWorkspace?.id === targetWorkspaceId) {
26815
26952
  return;
26816
26953
  }
26817
26954
  if (this._workspaceInitializationPromise && this._workspaceInitializationTargetKey === targetKey) {
26818
26955
  await this._workspaceInitializationPromise;
26819
26956
  return;
26820
26957
  }
26821
- this.core.store.state.isWorkspaceLoading = true;
26958
+ this._isWorkspaceLoading = true;
26959
+ this.syncLoadingState();
26822
26960
  const initializationPromise = this.core.initializeWorkspace(workspace, options);
26823
26961
  this._workspaceInitializationPromise = initializationPromise;
26824
26962
  this._workspaceInitializationTargetKey = targetKey;
@@ -26830,12 +26968,23 @@ const KritzelEngine = class {
26830
26968
  this._workspaceInitializationPromise = null;
26831
26969
  this._workspaceInitializationTargetKey = null;
26832
26970
  }
26833
- this.core.store.state.isWorkspaceLoading = false;
26971
+ this._isWorkspaceLoading = false;
26972
+ this.syncLoadingState();
26834
26973
  }
26835
26974
  }
26836
26975
  emitObjectsChange() {
26976
+ const objectsMap = this.core.store.objects;
26977
+ if (!objectsMap) {
26978
+ this.objectsChange.emit([]);
26979
+ this.undoStateChange.emit(this._defaultUndoState);
26980
+ if (this._lastHadSelectionGroup) {
26981
+ this._lastHadSelectionGroup = false;
26982
+ this.objectsSelectionChange.emit();
26983
+ }
26984
+ return;
26985
+ }
26837
26986
  const objects = this.core.store.allObjects;
26838
- const undoState = this.core.store.state.objects.undoState;
26987
+ const undoState = objectsMap.undoState;
26839
26988
  const hasSelectionGroup = this.core.store.selectionGroup !== null;
26840
26989
  this.objectsChange.emit(objects);
26841
26990
  this.undoStateChange.emit(undoState);
@@ -26866,22 +27015,24 @@ const KritzelEngine = class {
26866
27015
  _handleActiveToolChange(activeTool) {
26867
27016
  if (!(activeTool instanceof workspace_migrations.KritzelSelectionTool)) {
26868
27017
  this.core.clearSelection();
26869
- this.core.store.state.objects.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
27018
+ this.core.store.objects?.remove(o => o instanceof workspace_migrations.KritzelSelectionBox);
26870
27019
  this.core.store.setSelectionBox(null);
26871
- this.core.store.state.objects.clearLocalSelectionBox();
27020
+ this.core.store.objects?.clearLocalSelectionBox();
26872
27021
  this.core.store.state.isSelecting = false;
26873
27022
  this.core.store.state.isResizeHandleSelected = false;
26874
27023
  this.core.store.state.isRotationHandleSelected = false;
26875
27024
  }
26876
27025
  this.core.store.state.skipContextMenu = false;
26877
- this.core.store.state.copiedObjects = null;
26878
- this.activeToolChange.emit(activeTool);
27026
+ this.core.store.state.copiedObjects = undefined;
27027
+ if (activeTool) {
27028
+ this.activeToolChange.emit(activeTool);
27029
+ }
26879
27030
  workspace_migrations.KritzelKeyboardHelper.forceHideKeyboard();
26880
27031
  this.core.rerender();
26881
27032
  }
26882
27033
  render() {
26883
27034
  if (!this.viewport) {
26884
- return null;
27035
+ return (index.h(index.Host, null, this.core.store.state.isLoading && (index.h("div", { class: "workspace-loading-overlay" }, index.h("span", { class: "workspace-loading-spinner" }), "Loading..."))));
26885
27036
  }
26886
27037
  const currentTheme = this.core.themeManager.getStoredTheme();
26887
27038
  const computedStyle = window.getComputedStyle(this.host);
@@ -26898,7 +27049,7 @@ const KritzelEngine = class {
26898
27049
  this.emitObjectsInViewportChange();
26899
27050
  }
26900
27051
  }
26901
- return (index.h(index.Host, null, this.core.store.state.isWorkspaceLoading && (index.h("div", { class: "workspace-loading-overlay" }, "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (index.h("div", { class: "debug-panel" }, index.h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), index.h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), index.h("div", null, "TranslateX: ", this.core.store.state?.translateX), index.h("div", null, "TranslateY: ", this.core.store.state?.translateY), index.h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), index.h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), index.h("div", null, "PointerCount: ", this.core.store.state.pointers.size), index.h("div", null, "Scale: ", this.core.store.state?.scale), index.h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), index.h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), index.h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), index.h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), index.h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), index.h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), index.h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), index.h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), index.h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), index.h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), index.h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), index.h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), index.h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), index.h("div", null, "PointerX: ", this.core.store.state?.pointerX), index.h("div", null, "PointerY: ", this.core.store.state?.pointerY), index.h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), index.h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), index.h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), index.h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), index.h("div", { id: "origin", class: "origin", style: {
27052
+ return (index.h(index.Host, null, this.core.store.state.isLoading && (index.h("div", { class: "workspace-loading-overlay" }, index.h("span", { class: "workspace-loading-spinner" }), "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (index.h("div", { class: "debug-panel" }, index.h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), index.h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), index.h("div", null, "TranslateX: ", this.core.store.state?.translateX), index.h("div", null, "TranslateY: ", this.core.store.state?.translateY), index.h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), index.h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), index.h("div", null, "PointerCount: ", this.core.store.state.pointers.size), index.h("div", null, "Scale: ", this.core.store.state?.scale), index.h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), index.h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), index.h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), index.h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), index.h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), index.h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), index.h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), index.h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), index.h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), index.h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), index.h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), index.h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), index.h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), index.h("div", null, "PointerX: ", this.core.store.state?.pointerX), index.h("div", null, "PointerY: ", this.core.store.state?.pointerY), index.h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), index.h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), index.h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), index.h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), index.h("div", { id: "origin", class: "origin", style: {
26902
27053
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
26903
27054
  } }, visibleObjects?.map(object => {
26904
27055
  return (index.h("div", { key: object.id, id: object.id, class: "object", style: {
@@ -26907,7 +27058,7 @@ const KritzelEngine = class {
26907
27058
  position: 'absolute',
26908
27059
  zIndex: object.zIndex.toString(),
26909
27060
  pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
26910
- } }, workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (index.h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
27061
+ } }, workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (index.h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
26911
27062
  height: object?.totalHeight + 'px',
26912
27063
  width: object?.totalWidth + 'px',
26913
27064
  left: '0',
@@ -26918,7 +27069,7 @@ const KritzelEngine = class {
26918
27069
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26919
27070
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26920
27071
  overflow: 'visible',
26921
- }, viewBox: object?.viewBox }, index.h("path", { d: object?.d, fill: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: workspace_migrations.KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
27072
+ }, viewBox: object?.viewBox }, index.h("path", { d: object?.d, fill: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: workspace_migrations.KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (index.h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
26922
27073
  height: object?.totalHeight + 'px',
26923
27074
  width: object?.totalWidth + 'px',
26924
27075
  left: '0',
@@ -26929,7 +27080,7 @@ const KritzelEngine = class {
26929
27080
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26930
27081
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26931
27082
  overflow: 'visible',
26932
- }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (index.h("defs", null, object.hasStartArrow && (index.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" }, index.h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (index.h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, index.h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), index.h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), index.h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: workspace_migrations.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 }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (index.h("img", { ref: el => object.mount(el), src: object.src, style: {
27083
+ }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (index.h("defs", null, object.hasStartArrow && (index.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" }, index.h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (index.h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, index.h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), index.h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), index.h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: workspace_migrations.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 }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (index.h("img", { ref: el => el && object.mount(el), src: object.src, style: {
26933
27084
  position: 'absolute',
26934
27085
  left: '0',
26935
27086
  top: '0',
@@ -26947,7 +27098,7 @@ const KritzelEngine = class {
26947
27098
  overflow: 'visible',
26948
27099
  userSelect: 'none',
26949
27100
  imageRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'pixelated' : 'auto',
26950
- }, draggable: false, onDragStart: e => e.preventDefault() })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (index.h("div", { ref: el => object.mount(el), style: {
27101
+ }, draggable: false, onDragStart: e => e.preventDefault() })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (index.h("div", { ref: el => el && object.mount(el), style: {
26951
27102
  position: 'absolute',
26952
27103
  left: '0',
26953
27104
  top: '0',
@@ -26964,7 +27115,7 @@ const KritzelEngine = class {
26964
27115
  padding: object.padding + 'px',
26965
27116
  overflow: 'hidden',
26966
27117
  display: 'block',
26967
- } })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (index.h("div", { ref: el => object.mount(el), style: {
27118
+ } })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (index.h("div", { ref: el => el && object.mount(el), style: {
26968
27119
  position: 'absolute',
26969
27120
  left: '0',
26970
27121
  top: '0',
@@ -26974,7 +27125,7 @@ const KritzelEngine = class {
26974
27125
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
26975
27126
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26976
27127
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26977
- } })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (index.h("div", { ref: el => object.mount(el), style: {
27128
+ } })), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (index.h("div", { ref: el => el && object.mount(el), style: {
26978
27129
  position: 'absolute',
26979
27130
  left: '0',
26980
27131
  top: '0',
@@ -26998,7 +27149,7 @@ const KritzelEngine = class {
26998
27149
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
26999
27150
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
27000
27151
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
27001
- } }, index.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: {
27152
+ } }, index.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: {
27002
27153
  minWidth: object.initialWidth + 'px',
27003
27154
  minHeight: object.initialHeight + 'px',
27004
27155
  maxWidth: '500px',
@@ -27008,7 +27159,7 @@ const KritzelEngine = class {
27008
27159
  transform: `scale(${object.scaleFactor})`,
27009
27160
  backgroundColor: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
27010
27161
  overflow: 'visible',
27011
- } }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (index.h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
27162
+ } }))), workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (index.h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
27012
27163
  position: 'absolute',
27013
27164
  left: '0',
27014
27165
  top: '0',
@@ -27027,7 +27178,7 @@ const KritzelEngine = class {
27027
27178
  height: '100%',
27028
27179
  overflow: 'visible',
27029
27180
  pointerEvents: 'none',
27030
- }, viewBox: object.viewBox, preserveAspectRatio: "none" }, index.h("path", { d: object.getSvgPath(), fill: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), index.h("div", { ref: el => object.mountTextEditor(el), style: {
27181
+ }, viewBox: object.viewBox, preserveAspectRatio: "none" }, index.h("path", { d: object.getSvgPath(), fill: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: workspace_migrations.KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), index.h("div", { ref: el => el && object.mountTextEditor(el), style: {
27031
27182
  position: 'absolute',
27032
27183
  top: '0',
27033
27184
  left: '0',
@@ -27048,8 +27199,8 @@ const KritzelEngine = class {
27048
27199
  } }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
27049
27200
  (() => {
27050
27201
  const isSelectionGroup = workspace_migrations.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
27051
- const localClientId = this.core.store.state.objects?.localClientId;
27052
- const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
27202
+ const localClientId = this.core.store.objects?.localClientId;
27203
+ const awarenessStates = this.core.store.objects?.awareness?.getStates();
27053
27204
  const isRemoteSelection = isSelectionGroup && (
27054
27205
  // Different user
27055
27206
  (object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
@@ -27277,18 +27428,20 @@ const KritzelEngine = class {
27277
27428
  stroke: 'var(--kritzel-snap-indicator-stroke, #007bff)',
27278
27429
  strokeWidth: data.indicatorStrokeWidth,
27279
27430
  } }))));
27280
- })()), this.core.store.state.isContextMenuVisible && (index.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: {
27431
+ })()), this.core.store.state.isContextMenuVisible && (index.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: {
27281
27432
  position: 'fixed',
27282
27433
  left: `${this.core.store.state.contextMenuX}px`,
27283
27434
  top: `${this.core.store.state.contextMenuY}px`,
27284
27435
  zIndex: '10002',
27285
27436
  }, onActionSelected: event => {
27286
- event.detail.action({
27287
- x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
27288
- y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
27289
- }, this.core.store.selectionGroup?.objects);
27437
+ if (event.detail.action) {
27438
+ event.detail.action({
27439
+ x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
27440
+ y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
27441
+ }, this.core.store.selectionGroup?.objects || []);
27442
+ }
27290
27443
  this.hideContextMenu();
27291
- }, onClose: () => this.hideContextMenu() })), this.core.store.state.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof workspace_migrations.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core })));
27444
+ }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof workspace_migrations.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core })));
27292
27445
  }
27293
27446
  static get watchers() { return {
27294
27447
  "workspace": [{
@@ -27332,6 +27485,9 @@ const KritzelEngine = class {
27332
27485
  }],
27333
27486
  "debugInfo": [{
27334
27487
  "onDebugInfoChange": 0
27488
+ }],
27489
+ "isLoading": [{
27490
+ "onIsLoadingChange": 0
27335
27491
  }]
27336
27492
  }; }
27337
27493
  };
@@ -28559,7 +28715,7 @@ const KritzelPortal = class {
28559
28715
  * This file is auto-generated by the version bump scripts.
28560
28716
  * Do not modify manually.
28561
28717
  */
28562
- const KRITZEL_VERSION = '0.1.78';
28718
+ const KRITZEL_VERSION = '0.1.80';
28563
28719
 
28564
28720
  const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
28565
28721