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,5 +1,5 @@
1
- import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-BbOHefEf.js';
2
- import { a as KritzelPath, c as KritzelLine, y as KritzelColorHelper, m as KritzelSelectionTool, f as KritzelBrushTool, g as KritzelLineTool, k as KritzelShapeTool, j as KritzelTextTool, z as KritzelDevicesHelper, B as KritzelMouseButton, E as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, h as KritzelEraserTool, r as DEFAULT_LINE_TOOL_CONFIG, q as DEFAULT_TEXT_CONFIG, i as KritzelImageTool, u as KritzelAlignment, H as HocuspocusSyncProvider, I as IndexedDBSyncProvider, F as KritzelSelectionGroup, G as KritzelSelectionBox, J as KritzelIconRegistry, L as KritzelKeyboardHelper, M as KritzelBaseHandler, N as KritzelToolRegistry, O as KritzelBaseObject, n as KritzelWorkspace, d as KritzelGroup, b as KritzelImage, e as KritzelShape, K as KritzelText, w as runMigrations, v as CURRENT_WORKSPACE_SCHEMA_VERSION, x as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, A as APP_STATE_MIGRATIONS, P as ObjectHelper, l as KritzelCursorHelper, o as KritzelAnchorManager, p as KritzelThemeManager, Q as KritzelClassHelper, R as KritzelEventHelper, T as KritzelBaseTool, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-NhRgr2_H.js';
1
+ import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-D9HaikfQ.js';
2
+ import { a as KritzelPath, c as KritzelLine, y as KritzelColorHelper, m as KritzelSelectionTool, f as KritzelBrushTool, g as KritzelLineTool, k as KritzelShapeTool, j as KritzelTextTool, z as KritzelDevicesHelper, B as KritzelMouseButton, E as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, h as KritzelEraserTool, r as DEFAULT_LINE_TOOL_CONFIG, q as DEFAULT_TEXT_CONFIG, i as KritzelImageTool, u as KritzelAlignment, H as HocuspocusSyncProvider, I as IndexedDBSyncProvider, F as KritzelSelectionGroup, G as KritzelSelectionBox, J as KritzelIconRegistry, L as KritzelKeyboardHelper, M as KritzelBaseHandler, N as KritzelToolRegistry, O as KritzelBaseObject, n as KritzelWorkspace, d as KritzelGroup, b as KritzelImage, e as KritzelShape, K as KritzelText, w as runMigrations, v as CURRENT_WORKSPACE_SCHEMA_VERSION, x as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, A as APP_STATE_MIGRATIONS, P as ObjectHelper, l as KritzelCursorHelper, o as KritzelAnchorManager, p as KritzelThemeManager, Q as KritzelClassHelper, R as KritzelEventHelper, T as KritzelBaseTool, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-OzSSw5kt.js';
3
3
  import * as Y from 'yjs';
4
4
  import 'y-websocket';
5
5
  import 'y-indexeddb';
@@ -171,10 +171,10 @@ const KritzelAwarenessCursors = class {
171
171
  cleanupIntervalId;
172
172
  objectChangeRafId = null;
173
173
  componentDidLoad() {
174
- this.core.store.state.objects?.onAwarenessChange(states => {
174
+ this.core.store.objects?.onAwarenessChange(states => {
175
175
  this.handleAwarenessChange(states);
176
176
  });
177
- this.core.store.state.objects?.onObjectsChange(() => {
177
+ this.core.store.objects?.onObjectsChange(() => {
178
178
  this.handleRemoteObjectChange();
179
179
  });
180
180
  this.cleanupIntervalId = setInterval(() => {
@@ -190,7 +190,7 @@ const KritzelAwarenessCursors = class {
190
190
  }
191
191
  }
192
192
  handleAwarenessChange(states) {
193
- const localClientId = this.core.store.state.objects?.localClientId;
193
+ const localClientId = this.core.store.objects?.localClientId;
194
194
  const now = Date.now();
195
195
  const updated = new Map(this.remoteCursors);
196
196
  // Track which clientIds are still present
@@ -266,7 +266,7 @@ const KritzelAwarenessCursors = class {
266
266
  });
267
267
  }
268
268
  getActiveObjectTip(objectId) {
269
- const obj = this.core.store.state.objects?.findById(objectId);
269
+ const obj = this.core.store.objects?.findById(objectId);
270
270
  if (!obj)
271
271
  return null;
272
272
  if (obj instanceof KritzelPath && !obj.isCompleted) {
@@ -334,7 +334,7 @@ const KritzelAwarenessCursors = class {
334
334
  }
335
335
  render() {
336
336
  const cursors = Array.from(this.remoteCursors.values());
337
- return (h(Host, { key: '5a28def6e024249c4309c087502cde9f219f5421' }, cursors.map(remoteCursor => {
337
+ return (h(Host, { key: '1743084eadda932b5aaf89552f500b90e194a79f' }, cursors.map(remoteCursor => {
338
338
  if (!remoteCursor.cursor)
339
339
  return null;
340
340
  // When a remote user is actively drawing, derive cursor position from
@@ -1248,7 +1248,7 @@ const KritzelCursorTrail = class {
1248
1248
  }
1249
1249
  }
1250
1250
  render() {
1251
- return (h(Host, { key: 'b6a9e84ce49dd72f353e0b87ae0bc02b0e5aeb1e' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: '238ea314a937d556c75ae080495c2e6559340c6f', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1251
+ return (h(Host, { key: 'b0f5c795c4803e27a49d7f76f3fedea818967049' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: '6ff883be1aecfb302bc9ecb3b7562617d753d5ba', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
1252
1252
  position: 'absolute',
1253
1253
  left: '0',
1254
1254
  top: '0',
@@ -2027,6 +2027,8 @@ const KritzelEditor = class {
2027
2027
  }
2028
2028
  ]
2029
2029
  };
2030
+ /** Whether the editor is in a loading state. When true, a loading overlay is displayed. */
2031
+ isLoading = false;
2030
2032
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
2031
2033
  editorId;
2032
2034
  /** Optional workspace ID to set as active. If provided, the editor will automatically activate the workspace with this ID. */
@@ -2066,9 +2068,10 @@ const KritzelEditor = class {
2066
2068
  }
2067
2069
  }
2068
2070
  onWorkspacesChange(newWorkspaces) {
2069
- if (this.activeWorkspace) {
2070
- const updatedActiveWorkspace = newWorkspaces.find(ws => ws.id === this.activeWorkspace.id);
2071
- if (updatedActiveWorkspace && updatedActiveWorkspace !== this.activeWorkspace) {
2071
+ const activeWorkspace = this.activeWorkspace;
2072
+ if (activeWorkspace) {
2073
+ const updatedActiveWorkspace = newWorkspaces.find(ws => ws.id === activeWorkspace.id);
2074
+ if (updatedActiveWorkspace && updatedActiveWorkspace !== activeWorkspace) {
2072
2075
  this.activeWorkspace = updatedActiveWorkspace;
2073
2076
  }
2074
2077
  }
@@ -2295,7 +2298,7 @@ const KritzelEditor = class {
2295
2298
  await customElements.whenDefined('kritzel-workspace-manager');
2296
2299
  await customElements.whenDefined('kritzel-controls');
2297
2300
  await customElements.whenDefined('kritzel-engine');
2298
- if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady) {
2301
+ if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady || !this.activeWorkspace) {
2299
2302
  return;
2300
2303
  }
2301
2304
  const { id, name, isPublic, createdAt, updatedAt } = this.activeWorkspace;
@@ -2314,6 +2317,9 @@ const KritzelEditor = class {
2314
2317
  }
2315
2318
  async onEngineReady(event) {
2316
2319
  this.isEngineReady = true;
2320
+ if (!event.detail.activeWorkspace) {
2321
+ return;
2322
+ }
2317
2323
  this.activeWorkspace = event.detail.activeWorkspace;
2318
2324
  this.workspaces = event.detail.workspaces;
2319
2325
  this.currentIsPublic = await this.engineRef.getIsPublic();
@@ -2396,7 +2402,7 @@ const KritzelEditor = class {
2396
2402
  icon: 'upload',
2397
2403
  action: async () => {
2398
2404
  const preview = await this.engineRef.getScreenshot('png');
2399
- this.exportRef.open(preview);
2405
+ this.exportRef.open(preview ?? undefined);
2400
2406
  },
2401
2407
  },
2402
2408
  {
@@ -2427,7 +2433,7 @@ const KritzelEditor = class {
2427
2433
  activeWorkspace.isPublic = isPublic;
2428
2434
  await this.engineRef.updateWorkspace(activeWorkspace);
2429
2435
  this.activeWorkspace = activeWorkspace.clone();
2430
- this.isPublicChange.emit({ isPublic, workspaceId: this.activeWorkspace?.id });
2436
+ this.isPublicChange.emit({ isPublic, workspaceId: activeWorkspace.id });
2431
2437
  };
2432
2438
  /**
2433
2439
  * Updates the currentIsPublic state from the active workspace and emits the isPublicChange event.
@@ -2436,6 +2442,9 @@ const KritzelEditor = class {
2436
2442
  const isPublic = this.activeWorkspace?.isPublic ?? false;
2437
2443
  const workspaceId = this.activeWorkspace?.id;
2438
2444
  this.currentIsPublic = isPublic;
2445
+ if (!workspaceId) {
2446
+ return;
2447
+ }
2439
2448
  this.isPublicChange.emit({ isPublic, workspaceId });
2440
2449
  }
2441
2450
  handleProviderLogin = (event) => {
@@ -2540,7 +2549,31 @@ const KritzelEditor = class {
2540
2549
  const isLoggedIn = this.isLoggedIn;
2541
2550
  const shouldShowCurrentUser = isLoggedIn;
2542
2551
  const shouldShowLoginButton = !!this.loginConfig && !isLoggedIn;
2543
- return (h(Host, { key: '6dbc3a8c64dd097ba82e46341b3fb97cbd0194db' }, h("div", { key: '26ceb62f59ad830fd651a1712f57e5d711e7c6f4', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: 'afb4f5b87c5dc0a673444fb27930e43994df4e02', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'f3c0f31841cb819917c3277852bc9b5ce291c09a', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), 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) }), 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) }), h("div", { key: 'e27e5f3965be2fd15c83b91470ef87c4031dd7a2', class: "top-right-buttons" }, h("kritzel-settings", { key: '57f8e75287402aecbb7740d46dfa15839de2169f', ref: el => (this.settingsRef = el), shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), 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) }), h("kritzel-active-users", { key: '44a334b808706e11163e89b91074ca4ea8ab4b18', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: 'bcb3c966e630b1a8fc4ccd438fc8fbb11cd2b167', user: this.user }), shouldShowLoginButton && h("kritzel-button", { key: 'f1957e56257b7c565311e41b770579f7e2bb910d', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), h("kritzel-more-menu", { key: 'd8c1d1b51cf87725d68aaf4457b88828986a40dc', items: this.moreMenuItems }), h("kritzel-share-dialog", { key: 'f5840e7f56cf6897ec28b0f28d9b204037bf3348', ref: el => (this.shareDialogRef = el), isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (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 })))));
2552
+ return (h(Host, { key: '1e3c220506d14f276ca246365c2bda79110c6c35' }, h("div", { key: '154b45141b995f749adb52a11dc3363ab2989475', class: "top-left-buttons" }, h("kritzel-workspace-manager", { key: '22519269ea7227a1a7a05d2f282bbcd2466edf5d', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-back-to-content", { key: 'e89f0609dfd031cb040fd80a1f60ecb56d56734c', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), h("kritzel-engine", { key: '0b3acdf827d48c9589fb8170b49a602beb273684', ref: el => {
2553
+ if (el) {
2554
+ this.engineRef = el;
2555
+ }
2556
+ }, 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) }), h("kritzel-controls", { key: '324ba00f982938abc7a3f4dc47368f3b9bad665e', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => {
2557
+ if (el) {
2558
+ this.controlsRef = el;
2559
+ }
2560
+ }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.currentTheme, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: '0c4662e92cbe90a958f8704e6db0375915d9c634', class: "top-right-buttons" }, h("kritzel-settings", { key: 'e0422c1a02bc895bafd4b777d4d593afcfdf335b', ref: el => {
2561
+ if (el) {
2562
+ this.settingsRef = el;
2563
+ }
2564
+ }, shortcuts: this.shortcuts, editorId: this.editorId, onSettingsChange: event => this.handleSettingsChange(event) }), h("kritzel-export", { key: '72f59ec2eab76d753bb64475f199f0fa33e935d4', ref: el => {
2565
+ if (el) {
2566
+ this.exportRef = el;
2567
+ }
2568
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: 'c60411370947fc408b5e9d7adade3e28210b8d47', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: '4783940d3d4f9c2a7e8156c0713f29cb8b043125', user: this.user }), shouldShowLoginButton && h("kritzel-button", { key: 'bdb727d5641f8cda3711856086e1b9aa8533a5a6', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in"), h("kritzel-more-menu", { key: '3afa57ea46636c92cc7232dfe22a27cace85766e', items: this.moreMenuItems }), h("kritzel-share-dialog", { key: '852f9980fa3b89ceb5b6d8bde1bdd5598d3dc6e4', ref: el => {
2569
+ if (el) {
2570
+ this.shareDialogRef = el;
2571
+ }
2572
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'cdccbb7ef0b9932c0747545a18071f22e5683d8c', ref: el => {
2573
+ if (el) {
2574
+ this.loginDialogRef = el;
2575
+ }
2576
+ }, providers: this.loginConfig.providers, dialogTitle: this.loginConfig.title, subtitle: this.loginConfig.subtitle, onProviderLogin: this.handleProviderLogin })))));
2544
2577
  }
2545
2578
  static get watchers() { return {
2546
2579
  "isEngineReady": [{
@@ -19955,8 +19988,8 @@ class KritzelViewport {
19955
19988
  * Updates the stored viewport dimensions and triggers a rerender.
19956
19989
  */
19957
19990
  handleResize() {
19958
- this._core.store.state.viewportWidth = this._core.store.state.host.clientWidth;
19959
- this._core.store.state.viewportHeight = this._core.store.state.host.clientHeight;
19991
+ this._core.store.state.viewportWidth = this._core.store.host.clientWidth;
19992
+ this._core.store.state.viewportHeight = this._core.store.host.clientHeight;
19960
19993
  this._core.store.state.hasViewportChanged = true;
19961
19994
  this._core.rerender();
19962
19995
  }
@@ -19987,15 +20020,15 @@ class KritzelViewport {
19987
20020
  this._touchCursorBroadcastActive = false;
19988
20021
  }
19989
20022
  if (activePointers.length === 2) {
19990
- this._core.store.state.objects?.clearCursorPosition();
20023
+ this._core.store.objects?.clearCursorPosition();
19991
20024
  const currentPath = this._core.store.currentPath;
19992
20025
  if (currentPath) {
19993
- this._core.store.state.objects.remove(obj => obj.id === currentPath.id);
20026
+ this._core.store.objects.remove(obj => obj.id === currentPath.id);
19994
20027
  }
19995
20028
  // Clear selection box when scaling starts to prevent it from remaining on screen
19996
20029
  if (this._core.store.state.isSelecting) {
19997
20030
  this._core.store.state.isSelecting = false;
19998
- this._core.store.state.objects.remove(obj => obj instanceof KritzelSelectionBox);
20031
+ this._core.store.objects.remove(obj => obj instanceof KritzelSelectionBox);
19999
20032
  this._core.store.setSelectionBox(null);
20000
20033
  // Clear selection preview state from objects - use selectedObjects for efficiency
20001
20034
  this._core.store.selectedObjects.forEach(object => {
@@ -20022,12 +20055,12 @@ class KritzelViewport {
20022
20055
  */
20023
20056
  handlePointerMove(event) {
20024
20057
  if (event.pointerType === 'mouse') {
20025
- const hostRect = this._core.store.state.host.getBoundingClientRect();
20058
+ const hostRect = this._core.store.host.getBoundingClientRect();
20026
20059
  const xRelativeToHost = event.clientX - hostRect.left;
20027
20060
  const yRelativeToHost = event.clientY - hostRect.top;
20028
20061
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
20029
20062
  this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
20030
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20063
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20031
20064
  if (this._core.store.state.isPanning) {
20032
20065
  const dx = xRelativeToHost - this._core.store.state.startX;
20033
20066
  const dy = yRelativeToHost - this._core.store.state.startY;
@@ -20045,12 +20078,12 @@ class KritzelViewport {
20045
20078
  }
20046
20079
  }
20047
20080
  if (event.pointerType === 'touch' || event.pointerType === 'pen') {
20048
- const hostRect = this._core.store.state.host.getBoundingClientRect();
20081
+ const hostRect = this._core.store.host.getBoundingClientRect();
20049
20082
  const xRelativeToHost = event.clientX - hostRect.left;
20050
20083
  const yRelativeToHost = event.clientY - hostRect.top;
20051
20084
  const activePointers = Array.from(this._core.store.state.pointers.values());
20052
20085
  if (this._core.store.state.isScaling || activePointers.length > 1) {
20053
- this._core.store.state.objects?.clearCursorPosition();
20086
+ this._core.store.objects?.clearCursorPosition();
20054
20087
  }
20055
20088
  else {
20056
20089
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
@@ -20063,7 +20096,7 @@ class KritzelViewport {
20063
20096
  }
20064
20097
  }
20065
20098
  if (this._touchCursorBroadcastActive) {
20066
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20099
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20067
20100
  }
20068
20101
  }
20069
20102
  if (activePointers.length === 2) {
@@ -20262,12 +20295,12 @@ class KritzelViewport {
20262
20295
  */
20263
20296
  handleZoom(event) {
20264
20297
  this._core.store.state.isScaling = true;
20265
- const rect = this._core.store.state.host.getBoundingClientRect();
20298
+ const rect = this._core.store.host.getBoundingClientRect();
20266
20299
  const xRelativeToHost = event.clientX - rect.left;
20267
20300
  const yRelativeToHost = event.clientY - rect.top;
20268
20301
  this._core.store.state.pointerX = (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale;
20269
20302
  this._core.store.state.pointerY = (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale;
20270
- this._core.store.state.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20303
+ this._core.store.objects?.updateCursorPosition(this._core.store.state.pointerX, this._core.store.state.pointerY);
20271
20304
  const rawScaleFactor = 1 + (event.deltaY * -0.012);
20272
20305
  const scaleFactor = Math.max(0.8, Math.min(1.2, rawScaleFactor));
20273
20306
  const effectiveMinScale = this.getEffectiveMinScale();
@@ -20615,7 +20648,7 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
20615
20648
  const selectionTool = this._core.store.state.activeTool;
20616
20649
  selectionTool?.moveHandler?.cancelPendingDrag();
20617
20650
  if (this._core.store.selectionBox) {
20618
- this._core.store.state.objects.remove(object => object instanceof KritzelSelectionBox);
20651
+ this._core.store.objects.remove(object => object instanceof KritzelSelectionBox);
20619
20652
  this._core.store.setSelectionBox(null);
20620
20653
  this._core.store.state.isSelecting = false;
20621
20654
  }
@@ -20704,7 +20737,7 @@ class KritzelCustomElement extends KritzelBaseObject {
20704
20737
  const object = new KritzelCustomElement(config);
20705
20738
  object._core = core;
20706
20739
  object.id = object.generateId();
20707
- object.workspaceId = core.store.state.activeWorkspace.id;
20740
+ object.workspaceId = core.store.activeWorkspace.id;
20708
20741
  object.userId = core.user?.id;
20709
20742
  return object;
20710
20743
  }
@@ -20750,7 +20783,7 @@ class KritzelCustomElement extends KritzelBaseObject {
20750
20783
  this.element.style.height = `${height}px`;
20751
20784
  }
20752
20785
  // Update to sync changes to y.js and propagate to other tabs
20753
- this._core.store.state.objects.update(this);
20786
+ this._core.store.objects.update(this);
20754
20787
  }
20755
20788
  /**
20756
20789
  * Creates a deep copy of this custom element.
@@ -20878,7 +20911,7 @@ class KritzelReviver {
20878
20911
  }
20879
20912
 
20880
20913
  const DEFAULT_ENGINE_CONFIG = {
20881
- activeWorkspace: null,
20914
+ activeWorkspace: undefined,
20882
20915
  activeTool: null,
20883
20916
  copiedObjects: null,
20884
20917
  objects: null,
@@ -20904,7 +20937,7 @@ const DEFAULT_ENGINE_CONFIG = {
20904
20937
  isDrawing: false,
20905
20938
  isErasing: false,
20906
20939
  isWriting: false,
20907
- isWorkspaceLoading: false,
20940
+ isLoading: false,
20908
20941
  isCtrlKeyPressed: false,
20909
20942
  isContextMenuVisible: false,
20910
20943
  contextMenuItems: [],
@@ -21668,9 +21701,9 @@ class KritzelObjectMap {
21668
21701
  objectsToDelete.push(key);
21669
21702
  }
21670
21703
  else {
21671
- const serialized = this._objectsMap.get(key);
21704
+ const serialized = this._objectsMap?.get(key);
21672
21705
  if (serialized) {
21673
- const object = this._reviver.revive(serialized);
21706
+ const object = this._reviver?.revive(serialized);
21674
21707
  // Separate SelectionGroups to process them after regular objects
21675
21708
  if (object instanceof KritzelSelectionGroup) {
21676
21709
  selectionGroupsToUpdate.push(object);
@@ -21777,17 +21810,17 @@ class KritzelObjectMap {
21777
21810
  return;
21778
21811
  }
21779
21812
  this._ydoc.transact(() => {
21780
- if (!this._metadataMap.get('type')) {
21781
- this._metadataMap.set('type', type);
21813
+ if (!this._metadataMap?.get('type')) {
21814
+ this._metadataMap?.set('type', type);
21782
21815
  }
21783
- if (this._metadataMap.get('isPublic') === undefined) {
21784
- this._metadataMap.set('isPublic', false);
21816
+ if (this._metadataMap?.get('isPublic') === undefined) {
21817
+ this._metadataMap?.set('isPublic', false);
21785
21818
  }
21786
- if (this._metadataMap.get('schemaVersion') === undefined) {
21787
- this._metadataMap.set('schemaVersion', CURRENT_WORKSPACE_SCHEMA_VERSION);
21819
+ if (this._metadataMap?.get('schemaVersion') === undefined) {
21820
+ this._metadataMap?.set('schemaVersion', CURRENT_WORKSPACE_SCHEMA_VERSION);
21788
21821
  }
21789
- this._metadataMap.set('workspaceId', workspaceId);
21790
- this._metadataMap.set('workspaceName', workspaceName);
21822
+ this._metadataMap?.set('workspaceId', workspaceId);
21823
+ this._metadataMap?.set('workspaceName', workspaceName);
21791
21824
  }, 'metadata');
21792
21825
  }
21793
21826
  /**
@@ -21805,8 +21838,8 @@ class KritzelObjectMap {
21805
21838
  if (!this._metadataMap || !this._ydoc) {
21806
21839
  return;
21807
21840
  }
21808
- this._ydoc.transact(() => {
21809
- this._metadataMap.set('isPublic', isPublic);
21841
+ this._ydoc?.transact(() => {
21842
+ this._metadataMap?.set('isPublic', isPublic);
21810
21843
  }, 'metadata');
21811
21844
  }
21812
21845
  /**
@@ -21830,8 +21863,8 @@ class KritzelObjectMap {
21830
21863
  if (!this._metadataMap || !this._ydoc) {
21831
21864
  return;
21832
21865
  }
21833
- this._ydoc.transact(() => {
21834
- this._metadataMap.set('workspaceName', name);
21866
+ this._ydoc?.transact(() => {
21867
+ this._metadataMap?.set('workspaceName', name);
21835
21868
  }, 'metadata');
21836
21869
  }
21837
21870
  /**
@@ -21866,13 +21899,16 @@ class KritzelObjectMap {
21866
21899
  const localUserId = this._core?.user?.id;
21867
21900
  const staleSelectionGroupIds = [];
21868
21901
  this._objectsMap.forEach((serialized, key) => {
21869
- const object = this._reviver.revive(serialized);
21902
+ const object = this._reviver?.revive(serialized);
21870
21903
  // Remove remote selection groups on startup — they are transient UI state
21871
21904
  // that should not survive an app restart. The owning user's session is gone.
21872
21905
  if (object instanceof KritzelSelectionGroup && object.userId != null && object.userId !== localUserId) {
21873
21906
  staleSelectionGroupIds.push(key);
21874
21907
  return;
21875
21908
  }
21909
+ if (!object) {
21910
+ return;
21911
+ }
21876
21912
  this.quadtree.insert(object);
21877
21913
  this._idMap.set(object.id, object);
21878
21914
  });
@@ -21893,8 +21929,8 @@ class KritzelObjectMap {
21893
21929
  reset() {
21894
21930
  this.quadtree.reset();
21895
21931
  this._idMap.clear();
21896
- this._ydoc.transact(() => {
21897
- this._objectsMap.clear();
21932
+ this._ydoc?.transact(() => {
21933
+ this._objectsMap?.clear();
21898
21934
  }, 'local');
21899
21935
  }
21900
21936
  /**
@@ -21913,8 +21949,8 @@ class KritzelObjectMap {
21913
21949
  this._idMap.set(object.id, object);
21914
21950
  if (this._objectsMap && this.isPersistable(object)) {
21915
21951
  const serialized = object.serialize();
21916
- this._ydoc.transact(() => {
21917
- this._objectsMap.set(object.id, serialized);
21952
+ this._ydoc?.transact(() => {
21953
+ this._objectsMap?.set(object.id, serialized);
21918
21954
  }, 'local');
21919
21955
  }
21920
21956
  return true;
@@ -21943,8 +21979,8 @@ class KritzelObjectMap {
21943
21979
  if (this._objectsMap && this.isPersistable(object)) {
21944
21980
  const serialized = object.serialize();
21945
21981
  const origin = options.temporary ? 'temporary' : 'local';
21946
- this._ydoc.transact(() => {
21947
- this._objectsMap.set(object.id, serialized);
21982
+ this._ydoc?.transact(() => {
21983
+ this._objectsMap?.set(object.id, serialized);
21948
21984
  }, origin);
21949
21985
  }
21950
21986
  return true;
@@ -21961,8 +21997,8 @@ class KritzelObjectMap {
21961
21997
  this.quadtree.remove(o => o.id === object.id);
21962
21998
  this._idMap.delete(object.id);
21963
21999
  if (this._objectsMap && this.isPersistable(object)) {
21964
- this._ydoc.transact(() => {
21965
- this._objectsMap.delete(object.id);
22000
+ this._ydoc?.transact(() => {
22001
+ this._objectsMap?.delete(object.id);
21966
22002
  }, 'local');
21967
22003
  }
21968
22004
  }
@@ -22020,7 +22056,7 @@ class KritzelObjectMap {
22020
22056
  undo() {
22021
22057
  if (this._undoManager && this._undoManager.canUndo()) {
22022
22058
  this._undoManager.undo();
22023
- this._core.engine.emitObjectsChange();
22059
+ this._core?.engine.emitObjectsChange();
22024
22060
  }
22025
22061
  }
22026
22062
  /**
@@ -22030,7 +22066,7 @@ class KritzelObjectMap {
22030
22066
  redo() {
22031
22067
  if (this._undoManager && this._undoManager.canRedo()) {
22032
22068
  this._undoManager.redo();
22033
- this._core.engine.emitObjectsChange();
22069
+ this._core?.engine.emitObjectsChange();
22034
22070
  }
22035
22071
  }
22036
22072
  /**
@@ -22099,9 +22135,9 @@ class KritzelObjectMap {
22099
22135
  }
22100
22136
  // Now redo them all as a single 'local' transaction
22101
22137
  // This will consolidate them into one undo item
22102
- this._ydoc.transact(() => {
22138
+ this._ydoc?.transact(() => {
22103
22139
  for (let i = itemsToConsolidate - 1; i >= 0; i--) {
22104
- if (this._undoManager.canRedo()) {
22140
+ if (this._undoManager?.canRedo()) {
22105
22141
  this._undoManager.redo();
22106
22142
  }
22107
22143
  }
@@ -22217,13 +22253,49 @@ class KritzelStore {
22217
22253
  get state() {
22218
22254
  return this._state;
22219
22255
  }
22256
+ /**
22257
+ * Gets the map of all objects in the workspace.
22258
+ * Throws an error if the objects map is not initialized, as it is required for all object management.
22259
+ * @returns The KritzelObjectMap containing all objects
22260
+ * @throws Error if the objects map is not initialized in the state
22261
+ */
22262
+ get objects() {
22263
+ if (!this._state.objects) {
22264
+ throw new Error('Objects map is not initialized.');
22265
+ }
22266
+ return this._state.objects;
22267
+ }
22268
+ /**
22269
+ * Gets the currently active workspace.
22270
+ * Throws an error if no active workspace is set, as it is required for workspace-bound operations.
22271
+ * @returns The current active KritzelWorkspace
22272
+ * @throws Error if no active workspace is set in the state
22273
+ */
22274
+ get activeWorkspace() {
22275
+ if (!this._state.activeWorkspace) {
22276
+ throw new Error('Active workspace is not set.');
22277
+ }
22278
+ return this._state.activeWorkspace;
22279
+ }
22280
+ /**
22281
+ * Gets the host element for the Kritzel editor.
22282
+ * Throws an error if the host is not set, as it is required for many operations.
22283
+ * @returns The host HTMLElement
22284
+ * @throws Error if the host element is not set in the state
22285
+ */
22286
+ get host() {
22287
+ if (!this._state.host) {
22288
+ throw new Error('Host element is not set.');
22289
+ }
22290
+ return this._state.host;
22291
+ }
22220
22292
  /**
22221
22293
  * Gets the next available z-index for new objects.
22222
22294
  * Calculates the maximum z-index among all non-selection objects and adds 1.
22223
22295
  * @returns The next z-index value to use for new objects
22224
22296
  */
22225
22297
  get currentZIndex() {
22226
- return Math.max(0, ...this._state.objects.filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox)).map(o => o.zIndex)) + 1;
22298
+ return Math.max(0, ...this.objects.filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox)).map(o => o.zIndex)) + 1;
22227
22299
  }
22228
22300
  /**
22229
22301
  * Returns true if viewport boundaries are set to finite values (not Infinity).
@@ -22260,7 +22332,7 @@ class KritzelStore {
22260
22332
  if (this.hasViewportBoundaries) {
22261
22333
  return this.allObjects.length;
22262
22334
  }
22263
- return this._state.objects.totalCount;
22335
+ return this.objects.totalCount;
22264
22336
  }
22265
22337
  /**
22266
22338
  * Gets all objects in the workspace.
@@ -22269,9 +22341,9 @@ class KritzelStore {
22269
22341
  */
22270
22342
  get allObjects() {
22271
22343
  if (this.hasViewportBoundaries) {
22272
- return this._state.objects.query(this.viewportBoundaryBounds);
22344
+ return this.objects.query(this.viewportBoundaryBounds);
22273
22345
  }
22274
- return this._state.objects.allObjects();
22346
+ return this.objects.allObjects();
22275
22347
  }
22276
22348
  /**
22277
22349
  * Gets all objects currently visible in the viewport.
@@ -22287,7 +22359,7 @@ class KritzelStore {
22287
22359
  height: this._state.viewportHeight / this._state.scale,
22288
22360
  depth: 100,
22289
22361
  };
22290
- return this._state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
22362
+ return this.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
22291
22363
  }
22292
22364
  /**
22293
22365
  * Gets all objects excluding selection-related objects (selection group and selection box).
@@ -22312,7 +22384,7 @@ class KritzelStore {
22312
22384
  if (this._selectionBoxCacheValid) {
22313
22385
  return this._cachedSelectionBox;
22314
22386
  }
22315
- const selectionBoxes = this._state.objects.filter(o => o instanceof KritzelSelectionBox);
22387
+ const selectionBoxes = this.objects.filter(o => o instanceof KritzelSelectionBox);
22316
22388
  this._cachedSelectionBox = selectionBoxes.length > 0 ? selectionBoxes[0] : null;
22317
22389
  this._selectionBoxCacheValid = true;
22318
22390
  return this._cachedSelectionBox;
@@ -22327,7 +22399,7 @@ class KritzelStore {
22327
22399
  if (this._selectionGroupCacheValid) {
22328
22400
  return this._cachedSelectionGroup;
22329
22401
  }
22330
- const selectionGroups = this._state.objects.filter(o => o instanceof KritzelSelectionGroup);
22402
+ const selectionGroups = this.objects.filter(o => o instanceof KritzelSelectionGroup);
22331
22403
  if (this._localUserId) {
22332
22404
  this._cachedSelectionGroup = selectionGroups.find(sg => sg.userId === this._localUserId) ?? null;
22333
22405
  }
@@ -22376,7 +22448,7 @@ class KritzelStore {
22376
22448
  * @returns The text object in editing mode, or null if none
22377
22449
  */
22378
22450
  get activeText() {
22379
- const activeTexts = this._state.objects.filter(o => o instanceof KritzelText && o.isEditing);
22451
+ const activeTexts = this.objects.filter(o => o instanceof KritzelText && o.isEditing);
22380
22452
  return activeTexts.length > 0 ? activeTexts[0] : null;
22381
22453
  }
22382
22454
  /**
@@ -22384,7 +22456,7 @@ class KritzelStore {
22384
22456
  * @returns The shape object in editing mode, or null if none
22385
22457
  */
22386
22458
  get activeShape() {
22387
- const activeShapes = this._state.objects.filter(o => o instanceof KritzelShape && o.isEditing);
22459
+ const activeShapes = this.objects.filter(o => o instanceof KritzelShape && o.isEditing);
22388
22460
  return activeShapes.length > 0 ? activeShapes[0] : null;
22389
22461
  }
22390
22462
  /**
@@ -22392,7 +22464,7 @@ class KritzelStore {
22392
22464
  * @returns The incomplete path object, or null if no path is being drawn
22393
22465
  */
22394
22466
  get currentPath() {
22395
- const drawingPaths = this._state.objects.filter(o => o instanceof KritzelPath && o.isCompleted === false);
22467
+ const drawingPaths = this.objects.filter(o => o instanceof KritzelPath && o.isCompleted === false);
22396
22468
  return drawingPaths.length > 0 ? drawingPaths[0] : null;
22397
22469
  }
22398
22470
  /**
@@ -22400,7 +22472,7 @@ class KritzelStore {
22400
22472
  * @returns The incomplete line object, or null if no line is being drawn
22401
22473
  */
22402
22474
  get currentLine() {
22403
- const drawingLines = this._state.objects.filter(o => o instanceof KritzelLine && o.isCompleted === false);
22475
+ const drawingLines = this.objects.filter(o => o instanceof KritzelLine && o.isCompleted === false);
22404
22476
  return drawingLines.length > 0 ? drawingLines[0] : null;
22405
22477
  }
22406
22478
  /**
@@ -22408,14 +22480,14 @@ class KritzelStore {
22408
22480
  * @returns The left position of the host element in client coordinates
22409
22481
  */
22410
22482
  get offsetX() {
22411
- return this._state.host.getBoundingClientRect().left;
22483
+ return this.host.getBoundingClientRect().left;
22412
22484
  }
22413
22485
  /**
22414
22486
  * Gets the vertical offset of the host element from the viewport.
22415
22487
  * @returns The top position of the host element in client coordinates
22416
22488
  */
22417
22489
  get offsetY() {
22418
- return this._state.host.getBoundingClientRect().top;
22490
+ return this.host.getBoundingClientRect().top;
22419
22491
  }
22420
22492
  /**
22421
22493
  * Checks if the engine is currently disabled.
@@ -22451,7 +22523,11 @@ class KritzelStore {
22451
22523
  if (!this._listeners.has(property)) {
22452
22524
  this._listeners.set(property, new Set());
22453
22525
  }
22454
- this._listeners.get(property).add(listener);
22526
+ const listenersForProperty = this._listeners.get(property);
22527
+ if (!listenersForProperty) {
22528
+ throw new Error(`Listeners set for property ${String(property)} was not initialized.`);
22529
+ }
22530
+ listenersForProperty.add(listener);
22455
22531
  }
22456
22532
  /**
22457
22533
  * Gets the current value of a state property as readonly.
@@ -22473,8 +22549,9 @@ class KritzelStore {
22473
22549
  const oldValue = this._state[property];
22474
22550
  if (oldValue !== value) {
22475
22551
  this._state[property] = value;
22476
- if (this._listeners.has(property)) {
22477
- this._listeners.get(property).forEach(listener => listener(value, oldValue, String(property)));
22552
+ const listenersForProperty = this._listeners.get(property);
22553
+ if (listenersForProperty) {
22554
+ listenersForProperty.forEach(listener => listener(value, oldValue, String(property)));
22478
22555
  }
22479
22556
  }
22480
22557
  }
@@ -22683,7 +22760,9 @@ class KritzelAppStateMap {
22683
22760
  };
22684
22761
  }
22685
22762
  const workspace = new KritzelWorkspace(serialized.id, serialized.name, viewport);
22686
- workspace._core = this._core;
22763
+ if (this._core) {
22764
+ workspace._core = this._core;
22765
+ }
22687
22766
  workspace.createdAt = new Date(serialized.createdAt);
22688
22767
  workspace.updatedAt = new Date(serialized.updatedAt);
22689
22768
  workspace.isPublic = serialized.isPublic ?? false;
@@ -22698,14 +22777,14 @@ class KritzelAppStateMap {
22698
22777
  return;
22699
22778
  }
22700
22779
  this._ydoc.transact(() => {
22701
- if (!this._metadataMap.get('type')) {
22702
- this._metadataMap.set('type', type);
22780
+ if (!this._metadataMap?.get('type')) {
22781
+ this._metadataMap?.set('type', type);
22703
22782
  }
22704
- if (this._metadataMap.get('isPublic') === undefined) {
22705
- this._metadataMap.set('isPublic', false);
22783
+ if (this._metadataMap?.get('isPublic') === undefined) {
22784
+ this._metadataMap?.set('isPublic', false);
22706
22785
  }
22707
- if (this._metadataMap.get('schemaVersion') === undefined) {
22708
- this._metadataMap.set('schemaVersion', CURRENT_APP_STATE_SCHEMA_VERSION);
22786
+ if (this._metadataMap?.get('schemaVersion') === undefined) {
22787
+ this._metadataMap?.set('schemaVersion', CURRENT_APP_STATE_SCHEMA_VERSION);
22709
22788
  }
22710
22789
  }, 'metadata');
22711
22790
  }
@@ -22724,7 +22803,7 @@ class KritzelAppStateMap {
22724
22803
  return;
22725
22804
  }
22726
22805
  this._ydoc.transact(() => {
22727
- this._metadataMap.set('isPublic', isPublic);
22806
+ this._metadataMap?.set('isPublic', isPublic);
22728
22807
  }, 'metadata');
22729
22808
  }
22730
22809
  /**
@@ -22764,8 +22843,8 @@ class KritzelAppStateMap {
22764
22843
  */
22765
22844
  reset() {
22766
22845
  this.map.clear();
22767
- this._ydoc.transact(() => {
22768
- this._workspacesMap.clear();
22846
+ this._ydoc?.transact(() => {
22847
+ this._workspacesMap?.clear();
22769
22848
  }, 'local');
22770
22849
  }
22771
22850
  /**
@@ -22781,8 +22860,8 @@ class KritzelAppStateMap {
22781
22860
  this.map.set(workspace.id, workspace);
22782
22861
  if (this._workspacesMap) {
22783
22862
  const serialized = workspace.serialize();
22784
- this._ydoc.transact(() => {
22785
- this._workspacesMap.set(workspace.id, serialized);
22863
+ this._ydoc?.transact(() => {
22864
+ this._workspacesMap?.set(workspace.id, serialized);
22786
22865
  }, 'local');
22787
22866
  }
22788
22867
  return true;
@@ -22800,8 +22879,8 @@ class KritzelAppStateMap {
22800
22879
  this.map.set(workspace.id, workspace);
22801
22880
  if (this._workspacesMap) {
22802
22881
  const serialized = workspace.serialize();
22803
- this._ydoc.transact(() => {
22804
- this._workspacesMap.set(workspace.id, serialized);
22882
+ this._ydoc?.transact(() => {
22883
+ this._workspacesMap?.set(workspace.id, serialized);
22805
22884
  }, 'local');
22806
22885
  }
22807
22886
  return true;
@@ -22819,8 +22898,8 @@ class KritzelAppStateMap {
22819
22898
  }
22820
22899
  this.map.delete(workspaceToRemove.id);
22821
22900
  if (this._workspacesMap) {
22822
- this._ydoc.transact(() => {
22823
- this._workspacesMap.delete(workspaceToRemove.id);
22901
+ this._ydoc?.transact(() => {
22902
+ this._workspacesMap?.delete(workspaceToRemove.id);
22824
22903
  }, 'local');
22825
22904
  }
22826
22905
  return true;
@@ -23132,7 +23211,7 @@ class KritzelCore {
23132
23211
  setUser(user) {
23133
23212
  this._user = user;
23134
23213
  this._store.setLocalUserId(user?.id ?? null);
23135
- this._store.state.objects?.setLocalUser(user);
23214
+ this._store.objects?.setLocalUser(user);
23136
23215
  }
23137
23216
  /**
23138
23217
  * Creates a new KritzelCore instance.
@@ -23251,8 +23330,8 @@ class KritzelCore {
23251
23330
  // Save active workspace ID to localStorage
23252
23331
  localStorage.setItem(this.getStorageKey('kritzel-active-workspace-id'), activeWorkspace.id);
23253
23332
  // Destroy old ObjectMap if switching workspaces
23254
- if (this._store.state.objects && this._store.state.objects.isReady) {
23255
- this._store.state.objects.destroy();
23333
+ if (this._store.objects && this._store.objects.isReady) {
23334
+ this._store.objects.destroy();
23256
23335
  }
23257
23336
  // Create new ObjectMap with its own Y.Doc for this workspace
23258
23337
  const objectsMap = new KritzelObjectMap();
@@ -23322,7 +23401,10 @@ class KritzelCore {
23322
23401
  height: this._store.state.viewportHeight / this._store.state.scale,
23323
23402
  depth: 100,
23324
23403
  };
23325
- return this._store.state.objects
23404
+ if (!this._store.objects) {
23405
+ return [];
23406
+ }
23407
+ return this._store.objects
23326
23408
  .query(viewportBounds)
23327
23409
  .filter(obj => !(obj instanceof KritzelSelectionGroup) && !(obj instanceof KritzelSelectionBox))
23328
23410
  .sort((a, b) => a.zIndex - b.zIndex);
@@ -23377,8 +23459,8 @@ class KritzelCore {
23377
23459
  workspace.updatedAt = new Date();
23378
23460
  this.saveWorkspaceToAppState(workspace);
23379
23461
  // Keep metadata map in sync when the active workspace's name changes
23380
- if (this._store.state.activeWorkspace?.id === workspace.id) {
23381
- this._store.state.objects?.setWorkspaceName(workspace.name);
23462
+ if (this._store.activeWorkspace?.id === workspace.id) {
23463
+ this._store.objects?.setWorkspaceName(workspace.name);
23382
23464
  }
23383
23465
  const workspaces = this._store.state.workspaces;
23384
23466
  const index = workspaces.findIndex(w => w.id === workspace.id);
@@ -23395,9 +23477,9 @@ class KritzelCore {
23395
23477
  */
23396
23478
  deleteWorkspace(workspace) {
23397
23479
  // If deleting the active workspace, need to handle ObjectMap cleanup
23398
- if (this._store.state.activeWorkspace?.id === workspace.id) {
23480
+ if (this._store.activeWorkspace?.id === workspace.id) {
23399
23481
  this.engine.viewport?.cancelPendingUpdates();
23400
- this._store.state.objects?.destroy();
23482
+ this._store.objects?.destroy();
23401
23483
  }
23402
23484
  this.deleteWorkspaceFromAppState(workspace.id);
23403
23485
  this._store.state.workspaces = this.loadWorkspacesFromAppState();
@@ -23416,7 +23498,7 @@ class KritzelCore {
23416
23498
  * @param scale - The zoom scale of the viewport
23417
23499
  */
23418
23500
  updateWorkspaceViewport(translateX, translateY, scale) {
23419
- const activeWorkspace = this._store.state.activeWorkspace;
23501
+ const activeWorkspace = this._store.activeWorkspace;
23420
23502
  if (!activeWorkspace) {
23421
23503
  return;
23422
23504
  }
@@ -23439,7 +23521,7 @@ class KritzelCore {
23439
23521
  * @returns True if the workspace is public, false otherwise
23440
23522
  */
23441
23523
  getIsPublic() {
23442
- return this._store.state.activeWorkspace?.isPublic ?? false;
23524
+ return this._store.activeWorkspace?.isPublic ?? false;
23443
23525
  }
23444
23526
  // ═══════════════════════════════════════════════════════════════════════════
23445
23527
  // Object Management Methods
@@ -23449,7 +23531,7 @@ class KritzelCore {
23449
23531
  * @param object - The object to add to the canvas
23450
23532
  */
23451
23533
  addObject(object) {
23452
- this._store.state.objects.insert(object);
23534
+ this._store.objects.insert(object);
23453
23535
  }
23454
23536
  /**
23455
23537
  * Removes an object from the workspace.
@@ -23477,7 +23559,7 @@ class KritzelCore {
23477
23559
  this._anchorManager.handleObjectDeleted(object.id);
23478
23560
  }
23479
23561
  object.isMounted = false;
23480
- this._store.state.objects.remove(o => o.id === object.id);
23562
+ this._store.objects.remove(o => o.id === object.id);
23481
23563
  }
23482
23564
  /**
23483
23565
  * Updates properties on an object and persists the changes.
@@ -23490,12 +23572,15 @@ class KritzelCore {
23490
23572
  const changedKeys = [];
23491
23573
  for (const key in updatedProperties) {
23492
23574
  if (updatedProperties.hasOwnProperty(key)) {
23493
- object[key] = updatedProperties[key];
23494
- changedKeys.push(key);
23575
+ const value = updatedProperties[key];
23576
+ if (value !== undefined) {
23577
+ object[key] = value;
23578
+ changedKeys.push(key);
23579
+ }
23495
23580
  }
23496
23581
  }
23497
23582
  object.onAfterUpdate(changedKeys);
23498
- this._store.state.objects.update(object);
23583
+ this._store.objects.update(object);
23499
23584
  }
23500
23585
  /**
23501
23586
  * Adds a selection group to the canvas.
@@ -23506,7 +23591,7 @@ class KritzelCore {
23506
23591
  addSelectionGroup(selectionGroup) {
23507
23592
  this.removeSelectionGroup();
23508
23593
  this.removeSelectionBox();
23509
- this._store.state.objects.insert(selectionGroup);
23594
+ this._store.objects.insert(selectionGroup);
23510
23595
  this._store.setSelectionGroup(selectionGroup);
23511
23596
  this._kritzelEngine.triggerSelectionChange();
23512
23597
  }
@@ -23517,7 +23602,7 @@ class KritzelCore {
23517
23602
  removeSelectionGroup() {
23518
23603
  const selectionGroup = this._store.selectionGroup;
23519
23604
  if (selectionGroup) {
23520
- this._store.state.objects.remove(object => object.id === selectionGroup.id);
23605
+ this._store.objects.remove(object => object.id === selectionGroup.id);
23521
23606
  this._store.setSelectionGroup(null);
23522
23607
  this._kritzelEngine.triggerSelectionChange();
23523
23608
  }
@@ -23529,9 +23614,9 @@ class KritzelCore {
23529
23614
  removeSelectionBox() {
23530
23615
  const selectionBox = this._store.selectionBox;
23531
23616
  if (selectionBox) {
23532
- this._store.state.objects.remove(object => object.id === selectionBox.id);
23617
+ this._store.objects.remove(object => object.id === selectionBox.id);
23533
23618
  this._store.setSelectionBox(null);
23534
- this._store.state.objects.clearLocalSelectionBox();
23619
+ this._store.objects.clearLocalSelectionBox();
23535
23620
  }
23536
23621
  }
23537
23622
  /**
@@ -23560,13 +23645,13 @@ class KritzelCore {
23560
23645
  * Undoes the last action in the history stack.
23561
23646
  */
23562
23647
  undo() {
23563
- this._store.state.objects?.undo();
23648
+ this._store.objects?.undo();
23564
23649
  }
23565
23650
  /**
23566
23651
  * Redoes the last undone action from the history stack.
23567
23652
  */
23568
23653
  redo() {
23569
- this._store.state.objects?.redo();
23654
+ this._store.objects?.redo();
23570
23655
  }
23571
23656
  /**
23572
23657
  * Deletes a specific object by its ID.
@@ -23628,7 +23713,7 @@ class KritzelCore {
23628
23713
  if (!copiedObjects || copiedObjects.length === 0) {
23629
23714
  return;
23630
23715
  }
23631
- const activeWorkspace = this._store.state.activeWorkspace;
23716
+ const activeWorkspace = this._store.activeWorkspace;
23632
23717
  const originalIdMapping = this._store.state.copiedObjectIdMapping;
23633
23718
  // Check if we're pasting from a different workspace
23634
23719
  const isDifferentWorkspace = copiedObjects.some(obj => obj.workspaceId !== activeWorkspace.id);
@@ -23673,7 +23758,7 @@ class KritzelCore {
23673
23758
  const baseZIndex = this._store.currentZIndex;
23674
23759
  // Batch all inserts and updates in a single Y.js transaction to avoid
23675
23760
  // N separate observer callbacks and N rerenders (fires only once at commit)
23676
- this._store.state.objects.transaction(() => {
23761
+ this._store.objects.transaction(() => {
23677
23762
  // First add all copied objects to the objectsMap with updated positions
23678
23763
  copiedObjects.forEach((obj, i) => {
23679
23764
  // Update workspace if pasting to a different workspace
@@ -23725,7 +23810,7 @@ class KritzelCore {
23725
23810
  }
23726
23811
  // If anchors were updated, rebuild the anchor index and persist the change
23727
23812
  if (updated) {
23728
- this._store.state.objects.update(obj);
23813
+ this._store.objects.update(obj);
23729
23814
  }
23730
23815
  }
23731
23816
  });
@@ -23847,7 +23932,7 @@ class KritzelCore {
23847
23932
  }
23848
23933
  const objects = selectionGroup.objects;
23849
23934
  const alignedPositions = AlignmentHelper.calculateAlignedPositions(objects, alignment);
23850
- this._store.state.objects.transaction(() => {
23935
+ this._store.objects.transaction(() => {
23851
23936
  for (const obj of objects) {
23852
23937
  const newPosition = alignedPositions.get(obj.id);
23853
23938
  if (newPosition) {
@@ -23945,7 +24030,7 @@ class KritzelCore {
23945
24030
  * Switches to selection tool.
23946
24031
  */
23947
24032
  selectAllObjects() {
23948
- const allObjects = this._store.state.objects
24033
+ const allObjects = this._store.objects
23949
24034
  .allObjects()
23950
24035
  .filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox) && !(o instanceof KritzelContextMenu));
23951
24036
  if (allObjects.length > 0) {
@@ -23978,7 +24063,7 @@ class KritzelCore {
23978
24063
  height: this._store.state.viewportHeight / this._store.state.scale,
23979
24064
  depth: 100,
23980
24065
  };
23981
- const objectsInViewport = this._store.state.objects
24066
+ const objectsInViewport = this._store.objects
23982
24067
  .query(viewportBounds)
23983
24068
  .filter(o => o.isInViewport())
23984
24069
  .filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox) && !(o instanceof KritzelContextMenu));
@@ -24005,7 +24090,7 @@ class KritzelCore {
24005
24090
  clearSelection() {
24006
24091
  this.removeSelectionGroup();
24007
24092
  const localUserId = this._user?.id;
24008
- this._store.state.objects.remove(o => o instanceof KritzelSelectionBox ||
24093
+ this._store.objects.remove(o => o instanceof KritzelSelectionBox ||
24009
24094
  (o instanceof KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
24010
24095
  this._store.setSelectionBox(null);
24011
24096
  this._store.setSelectionGroup(null);
@@ -24014,7 +24099,7 @@ class KritzelCore {
24014
24099
  this._store.state.isRotationHandleSelected = false;
24015
24100
  this._store.state.isLineHandleSelected = false;
24016
24101
  this._store.state.isLineHandleDragging = false;
24017
- this._store.state.lineHandleType = null;
24102
+ this._store.state.lineHandleType = undefined;
24018
24103
  this.rerender();
24019
24104
  }
24020
24105
  /**
@@ -24060,7 +24145,9 @@ class KritzelCore {
24060
24145
  const selectedObject = elementAtPoint.closest(selector);
24061
24146
  if (selectedObject) {
24062
24147
  const foundObject = this._store.allObjects.find(object => selectedObject.id === object.id);
24063
- const isHit = foundObject?.hitTest(clientX, clientY);
24148
+ if (!foundObject)
24149
+ return null;
24150
+ const isHit = foundObject.hitTest(clientX, clientY);
24064
24151
  return isHit ? foundObject : null;
24065
24152
  }
24066
24153
  return null;
@@ -24142,7 +24229,7 @@ class KritzelCore {
24142
24229
  // saving the old workspace's viewport to the new workspace
24143
24230
  this._kritzelEngine.viewport?.cancelPendingUpdates();
24144
24231
  // Immediately save the current workspace's viewport before switching
24145
- const currentWorkspace = this._store.state.activeWorkspace;
24232
+ const currentWorkspace = this._store.activeWorkspace;
24146
24233
  if (currentWorkspace) {
24147
24234
  this.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
24148
24235
  }
@@ -25484,7 +25571,7 @@ async function toPng(node, options = {}) {
25484
25571
  return canvas.toDataURL();
25485
25572
  }
25486
25573
 
25487
- 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}`;
25574
+ 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}`;
25488
25575
 
25489
25576
  const KritzelEngine = class {
25490
25577
  get host() { return getElement(this); }
@@ -25497,13 +25584,13 @@ const KritzelEngine = class {
25497
25584
  }
25498
25585
  // Let batched prop updates settle, then perform an idempotent re-check.
25499
25586
  await Promise.resolve();
25500
- const currentWorkspaceId = this.core.store.state.activeWorkspace?.id;
25587
+ const currentWorkspaceId = this.core.store.activeWorkspace?.id;
25501
25588
  if (currentWorkspaceId === newWorkspaceId) {
25502
25589
  return;
25503
25590
  }
25504
25591
  this.core.beforeWorkspaceChange();
25505
25592
  await this.initializeWorkspaceIfNeeded(newWorkspace);
25506
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
25593
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
25507
25594
  }
25508
25595
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
25509
25596
  editorId;
@@ -25603,6 +25690,11 @@ const KritzelEngine = class {
25603
25690
  }
25604
25691
  /** When false, wheel events will not trigger viewport pan/zoom. The event still propagates to parent elements. */
25605
25692
  wheelEnabled = true;
25693
+ /** External loading state. Combined with internal workspace-loading state to drive the overlay. */
25694
+ isLoading = false;
25695
+ onIsLoadingChange() {
25696
+ this.syncLoadingState();
25697
+ }
25606
25698
  /** Emitted when the engine has fully initialized and is ready for interaction. */
25607
25699
  isEngineReady;
25608
25700
  /** Emitted when the active drawing tool changes. */
@@ -25711,7 +25803,7 @@ const KritzelEngine = class {
25711
25803
  this.core.store.state?.activeTool?.handlePointerUp(ev);
25712
25804
  }
25713
25805
  handlePointerLeave() {
25714
- this.core.store.state.objects?.clearCursorPosition();
25806
+ this.core.store.objects?.clearCursorPosition();
25715
25807
  }
25716
25808
  handleLongPress(ev) {
25717
25809
  this.contextMenuHandler.handleContextMenu(ev.detail);
@@ -25894,9 +25986,9 @@ const KritzelEngine = class {
25894
25986
  async hideContextMenu() {
25895
25987
  this.core.store.state.pointers.clear();
25896
25988
  this.core.store.state.isContextMenuVisible = false;
25897
- this.core.store.state.objects.remove(o => o instanceof KritzelSelectionBox);
25989
+ this.core.store.objects?.remove(o => o instanceof KritzelSelectionBox);
25898
25990
  this.core.store.setSelectionBox(null);
25899
- this.core.store.state.objects.clearLocalSelectionBox();
25991
+ this.core.store.objects?.clearLocalSelectionBox();
25900
25992
  this.core.store.state.isSelecting = false;
25901
25993
  this.core.store.state.isEnabled = true;
25902
25994
  this.core.rerender();
@@ -25950,7 +26042,7 @@ const KritzelEngine = class {
25950
26042
  object._core = this.core;
25951
26043
  object.scale = this.core.store.state.scale;
25952
26044
  object.zIndex = this.core.store.currentZIndex;
25953
- object.workspaceId = this.core.store.state.activeWorkspace.id;
26045
+ object.workspaceId = this.core.store.activeWorkspace.id;
25954
26046
  // Handle KritzelText: recreate the editor now that _core is available
25955
26047
  // The editor's dispatchTransaction callback needs _core for persisting changes
25956
26048
  if (KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
@@ -25971,7 +26063,7 @@ const KritzelEngine = class {
25971
26063
  child._core = this.core;
25972
26064
  child.scale = this.core.store.state.scale;
25973
26065
  child.zIndex = this.core.store.currentZIndex;
25974
- child.workspaceId = this.core.store.state.activeWorkspace.id;
26066
+ child.workspaceId = this.core.store.activeWorkspace.id;
25975
26067
  idRemapping.set(oldId, child.id);
25976
26068
  object.childIds.push(child.id);
25977
26069
  });
@@ -26025,8 +26117,12 @@ const KritzelEngine = class {
26025
26117
  * @returns The removed object.
26026
26118
  */
26027
26119
  async removeObject(object) {
26120
+ const objectsMap = this.core.store.objects;
26121
+ if (!objectsMap) {
26122
+ return null;
26123
+ }
26028
26124
  this.core.deselectAllObjects();
26029
- this.core.store.state.objects.remove(o => o.id === object.id);
26125
+ objectsMap.remove(o => o.id === object.id);
26030
26126
  this.core.rerender();
26031
26127
  this.emitObjectsRemoved([object]);
26032
26128
  return object;
@@ -26045,15 +26141,23 @@ const KritzelEngine = class {
26045
26141
  * @param objects - The objects to select.
26046
26142
  */
26047
26143
  async selectObjects(objects) {
26144
+ const selectionTool = KritzelToolRegistry.getTool('selection');
26145
+ if (!selectionTool) {
26146
+ return;
26147
+ }
26048
26148
  this.core.store.state.activeTool?.onDeactivate();
26049
- this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
26149
+ this.core.store.setState('activeTool', selectionTool);
26050
26150
  this.core.deselectAllObjects();
26051
26151
  this.core.selectObjects(objects);
26052
26152
  }
26053
26153
  /** Selects all objects currently visible in the viewport. Switches to the selection tool automatically. */
26054
26154
  async selectAllObjectsInViewport() {
26155
+ const selectionTool = KritzelToolRegistry.getTool('selection');
26156
+ if (!selectionTool) {
26157
+ return;
26158
+ }
26055
26159
  this.core.store.state.activeTool?.onDeactivate();
26056
- this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
26160
+ this.core.store.setState('activeTool', selectionTool);
26057
26161
  this.core.deselectAllObjects();
26058
26162
  this.core.selectAllObjectsInViewport();
26059
26163
  }
@@ -26159,8 +26263,8 @@ const KritzelEngine = class {
26159
26263
  return null;
26160
26264
  // Save critical state before screenshot to restore after
26161
26265
  const savedState = {
26162
- objects: this.core.store.state.objects,
26163
- activeWorkspace: this.core.store.state.activeWorkspace,
26266
+ objects: this.core.store.objects,
26267
+ activeWorkspace: this.core.store.activeWorkspace,
26164
26268
  workspaces: this.core.store.state.workspaces,
26165
26269
  activeTool: this.core.store.state.activeTool,
26166
26270
  isReady: this.core.store.state.isReady,
@@ -26211,6 +26315,10 @@ const KritzelEngine = class {
26211
26315
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26212
26316
  const filename = `${activeWorkspaceName}-${timestamp}.png`;
26213
26317
  const dataUrl = await this.getScreenshot('png');
26318
+ if (!dataUrl) {
26319
+ console.error('Failed to export viewport as PNG: screenshot could not be generated');
26320
+ return;
26321
+ }
26214
26322
  const link = document.createElement('a');
26215
26323
  link.download = filename;
26216
26324
  link.href = dataUrl;
@@ -26228,6 +26336,10 @@ const KritzelEngine = class {
26228
26336
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26229
26337
  const filename = `${activeWorkspaceName}-${timestamp}.svg`;
26230
26338
  const dataUrl = await this.getScreenshot('svg');
26339
+ if (!dataUrl) {
26340
+ console.error('Failed to export viewport as SVG: screenshot could not be generated');
26341
+ return;
26342
+ }
26231
26343
  const link = document.createElement('a');
26232
26344
  link.download = filename;
26233
26345
  link.href = dataUrl;
@@ -26350,7 +26462,10 @@ const KritzelEngine = class {
26350
26462
  * @returns A JSON string representing the complete workspace state.
26351
26463
  */
26352
26464
  async exportAsJson() {
26353
- const workspace = this.core.store.state.activeWorkspace;
26465
+ const workspace = this.core.store.activeWorkspace;
26466
+ if (!workspace) {
26467
+ throw new Error('Cannot export workspace: no active workspace is loaded');
26468
+ }
26354
26469
  const serialized = workspace.serialize({ includeObjects: true });
26355
26470
  return JSON.stringify(serialized, null, 2);
26356
26471
  }
@@ -26423,7 +26538,11 @@ const KritzelEngine = class {
26423
26538
  if (data.version && data.version !== WORKSPACE_EXPORT_VERSION) {
26424
26539
  console.warn(`Workspace version mismatch: expected ${WORKSPACE_EXPORT_VERSION}, got ${data.version}`);
26425
26540
  }
26426
- const currentWorkspaceId = this.core.store.state.activeWorkspace.id;
26541
+ const activeWorkspace = this.core.store.activeWorkspace;
26542
+ if (!activeWorkspace) {
26543
+ throw new Error('Cannot load objects: no active workspace is loaded');
26544
+ }
26545
+ const currentWorkspaceId = activeWorkspace.id;
26427
26546
  let loadedCount = 0;
26428
26547
  // Revive and add objects to the current workspace
26429
26548
  if (data.objects && Array.isArray(data.objects)) {
@@ -26559,7 +26678,11 @@ const KritzelEngine = class {
26559
26678
  }
26560
26679
  /** Returns the currently active workspace. */
26561
26680
  async getActiveWorkspace() {
26562
- return this.core.store.state.activeWorkspace;
26681
+ const activeWorkspace = this.core.store.activeWorkspace;
26682
+ if (!activeWorkspace) {
26683
+ throw new Error('No active workspace is loaded');
26684
+ }
26685
+ return activeWorkspace;
26563
26686
  }
26564
26687
  /**
26565
26688
  * Gets whether the active workspace is publicly accessible.
@@ -26588,7 +26711,7 @@ const KritzelEngine = class {
26588
26711
  this.workspacesChange.emit(this.core.store.state.workspaces);
26589
26712
  this.core.beforeWorkspaceChange();
26590
26713
  await this.initializeWorkspaceIfNeeded(workspace);
26591
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
26714
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
26592
26715
  }
26593
26716
  /**
26594
26717
  * Reinitializes sync by performing a full teardown and re-initialization.
@@ -26598,8 +26721,8 @@ const KritzelEngine = class {
26598
26721
  */
26599
26722
  async reinitSync() {
26600
26723
  this.core.setSyncConfig(this.syncConfig);
26601
- this.core.store.state.objects?.clearCursorPosition();
26602
- this.core.store.state.objects?.destroy();
26724
+ this.core.store.objects?.clearCursorPosition();
26725
+ this.core.store.objects?.destroy();
26603
26726
  this.core.appStateMap.destroy();
26604
26727
  this._isYjsInitialized = false;
26605
26728
  await this.initializeSyncAndWorkspace();
@@ -26617,6 +26740,16 @@ const KritzelEngine = class {
26617
26740
  _workspaceInitializationTargetKey = null;
26618
26741
  _syncInitPromise = null;
26619
26742
  _syncConfigRevision = 0;
26743
+ _isWorkspaceLoading = false;
26744
+ _defaultUndoState = {
26745
+ canUndo: false,
26746
+ canRedo: false,
26747
+ undoStackSize: 0,
26748
+ redoStackSize: 0,
26749
+ };
26750
+ syncLoadingState() {
26751
+ this.core.store.state.isLoading = this._isWorkspaceLoading || this.isLoading;
26752
+ }
26620
26753
  get isSelecting() {
26621
26754
  return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.isSelecting;
26622
26755
  }
@@ -26644,10 +26777,10 @@ const KritzelEngine = class {
26644
26777
  disconnectedCallback() {
26645
26778
  this.throttledPointerMoveMulti.cancel();
26646
26779
  // Clear cursor position in awareness before destroying
26647
- this.core.store.state.objects?.clearCursorPosition();
26780
+ this.core.store.objects?.clearCursorPosition();
26648
26781
  // Clean up current workspace's ObjectMap
26649
- if (this.core.store.state.objects) {
26650
- this.core.store.state.objects.destroy();
26782
+ if (this.core.store.objects) {
26783
+ this.core.store.objects.destroy();
26651
26784
  }
26652
26785
  // Clean up AppStateMap (workspaces Y.Doc)
26653
26786
  this.core.appStateMap.destroy();
@@ -26665,6 +26798,8 @@ const KritzelEngine = class {
26665
26798
  this.core.store.state.viewportBoundaryRight = this.viewportBoundaryRight;
26666
26799
  this.core.store.state.viewportBoundaryTop = this.viewportBoundaryTop;
26667
26800
  this.core.store.state.viewportBoundaryBottom = this.viewportBoundaryBottom;
26801
+ this._isWorkspaceLoading = true;
26802
+ this.syncLoadingState();
26668
26803
  }
26669
26804
  async componentDidLoad() {
26670
26805
  setTimeout(async () => {
@@ -26673,7 +26808,9 @@ const KritzelEngine = class {
26673
26808
  this.viewport = new KritzelViewport(this.core, this.host);
26674
26809
  // Initialize cursor manager with target element and shadow root
26675
26810
  this.core.cursorManager.setTargetElement(this.cursorTarget || document.body);
26676
- this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
26811
+ if (this.host.shadowRoot) {
26812
+ this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
26813
+ }
26677
26814
  // Initialize theme manager with kritzel-editor as target element
26678
26815
  const editorElement = this.host.closest('kritzel-editor');
26679
26816
  this.core.themeManager.setTargetElement(editorElement || this.host);
@@ -26734,7 +26871,7 @@ const KritzelEngine = class {
26734
26871
  await this.initializeWorkspaceIfNeeded(startupWorkspace);
26735
26872
  }
26736
26873
  // Emit initial active workspace once startup initialization has completed
26737
- const initialActiveWorkspace = this.core.store.state.activeWorkspace;
26874
+ const initialActiveWorkspace = this.core.store.activeWorkspace;
26738
26875
  if (initialActiveWorkspace) {
26739
26876
  this.activeWorkspaceChange.emit(initialActiveWorkspace);
26740
26877
  }
@@ -26763,7 +26900,7 @@ const KritzelEngine = class {
26763
26900
  if (!this.activeWorkspaceId || this._isResolvingActiveWorkspaceId) {
26764
26901
  return;
26765
26902
  }
26766
- if (this.core.store.state.activeWorkspace?.id === this.activeWorkspaceId) {
26903
+ if (this.core.store.activeWorkspace?.id === this.activeWorkspaceId) {
26767
26904
  return;
26768
26905
  }
26769
26906
  this._isResolvingActiveWorkspaceId = true;
@@ -26779,24 +26916,25 @@ const KritzelEngine = class {
26779
26916
  }
26780
26917
  return;
26781
26918
  }
26782
- if (this.core.store.state.activeWorkspace?.id === workspace.id) {
26919
+ if (this.core.store.activeWorkspace?.id === workspace.id) {
26783
26920
  return;
26784
26921
  }
26785
26922
  this.core.beforeWorkspaceChange();
26786
26923
  await this.initializeWorkspaceIfNeeded(workspace);
26787
- this.activeWorkspaceChange.emit(this.core.store.state.activeWorkspace);
26924
+ this.activeWorkspaceChange.emit(this.core.store.activeWorkspace);
26788
26925
  }
26789
26926
  async initializeWorkspaceIfNeeded(workspace, options) {
26790
26927
  const targetWorkspaceId = workspace?.id ?? null;
26791
26928
  const targetKey = targetWorkspaceId ?? (options?.skipFallbackCreation ? '__NO_FALLBACK__' : '__AUTO__');
26792
- if (targetWorkspaceId && this.core.store.state.activeWorkspace?.id === targetWorkspaceId) {
26929
+ if (targetWorkspaceId && this.core.store.activeWorkspace?.id === targetWorkspaceId) {
26793
26930
  return;
26794
26931
  }
26795
26932
  if (this._workspaceInitializationPromise && this._workspaceInitializationTargetKey === targetKey) {
26796
26933
  await this._workspaceInitializationPromise;
26797
26934
  return;
26798
26935
  }
26799
- this.core.store.state.isWorkspaceLoading = true;
26936
+ this._isWorkspaceLoading = true;
26937
+ this.syncLoadingState();
26800
26938
  const initializationPromise = this.core.initializeWorkspace(workspace, options);
26801
26939
  this._workspaceInitializationPromise = initializationPromise;
26802
26940
  this._workspaceInitializationTargetKey = targetKey;
@@ -26808,12 +26946,23 @@ const KritzelEngine = class {
26808
26946
  this._workspaceInitializationPromise = null;
26809
26947
  this._workspaceInitializationTargetKey = null;
26810
26948
  }
26811
- this.core.store.state.isWorkspaceLoading = false;
26949
+ this._isWorkspaceLoading = false;
26950
+ this.syncLoadingState();
26812
26951
  }
26813
26952
  }
26814
26953
  emitObjectsChange() {
26954
+ const objectsMap = this.core.store.objects;
26955
+ if (!objectsMap) {
26956
+ this.objectsChange.emit([]);
26957
+ this.undoStateChange.emit(this._defaultUndoState);
26958
+ if (this._lastHadSelectionGroup) {
26959
+ this._lastHadSelectionGroup = false;
26960
+ this.objectsSelectionChange.emit();
26961
+ }
26962
+ return;
26963
+ }
26815
26964
  const objects = this.core.store.allObjects;
26816
- const undoState = this.core.store.state.objects.undoState;
26965
+ const undoState = objectsMap.undoState;
26817
26966
  const hasSelectionGroup = this.core.store.selectionGroup !== null;
26818
26967
  this.objectsChange.emit(objects);
26819
26968
  this.undoStateChange.emit(undoState);
@@ -26844,22 +26993,24 @@ const KritzelEngine = class {
26844
26993
  _handleActiveToolChange(activeTool) {
26845
26994
  if (!(activeTool instanceof KritzelSelectionTool)) {
26846
26995
  this.core.clearSelection();
26847
- this.core.store.state.objects.remove(o => o instanceof KritzelSelectionBox);
26996
+ this.core.store.objects?.remove(o => o instanceof KritzelSelectionBox);
26848
26997
  this.core.store.setSelectionBox(null);
26849
- this.core.store.state.objects.clearLocalSelectionBox();
26998
+ this.core.store.objects?.clearLocalSelectionBox();
26850
26999
  this.core.store.state.isSelecting = false;
26851
27000
  this.core.store.state.isResizeHandleSelected = false;
26852
27001
  this.core.store.state.isRotationHandleSelected = false;
26853
27002
  }
26854
27003
  this.core.store.state.skipContextMenu = false;
26855
- this.core.store.state.copiedObjects = null;
26856
- this.activeToolChange.emit(activeTool);
27004
+ this.core.store.state.copiedObjects = undefined;
27005
+ if (activeTool) {
27006
+ this.activeToolChange.emit(activeTool);
27007
+ }
26857
27008
  KritzelKeyboardHelper.forceHideKeyboard();
26858
27009
  this.core.rerender();
26859
27010
  }
26860
27011
  render() {
26861
27012
  if (!this.viewport) {
26862
- return null;
27013
+ return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading..."))));
26863
27014
  }
26864
27015
  const currentTheme = this.core.themeManager.getStoredTheme();
26865
27016
  const computedStyle = window.getComputedStyle(this.host);
@@ -26876,7 +27027,7 @@ const KritzelEngine = class {
26876
27027
  this.emitObjectsInViewportChange();
26877
27028
  }
26878
27029
  }
26879
- return (h(Host, null, this.core.store.state.isWorkspaceLoading && (h("div", { class: "workspace-loading-overlay" }, "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
27030
+ return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
26880
27031
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
26881
27032
  } }, visibleObjects?.map(object => {
26882
27033
  return (h("div", { key: object.id, id: object.id, class: "object", style: {
@@ -26885,7 +27036,7 @@ const KritzelEngine = class {
26885
27036
  position: 'absolute',
26886
27037
  zIndex: object.zIndex.toString(),
26887
27038
  pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
26888
- } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
27039
+ } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
26889
27040
  height: object?.totalHeight + 'px',
26890
27041
  width: object?.totalWidth + 'px',
26891
27042
  left: '0',
@@ -26896,7 +27047,7 @@ const KritzelEngine = class {
26896
27047
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26897
27048
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26898
27049
  overflow: 'visible',
26899
- }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
27050
+ }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.resolveThemeColor(object.fill, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
26900
27051
  height: object?.totalHeight + 'px',
26901
27052
  width: object?.totalWidth + 'px',
26902
27053
  left: '0',
@@ -26907,7 +27058,7 @@ const KritzelEngine = class {
26907
27058
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26908
27059
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26909
27060
  overflow: 'visible',
26910
- }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => object.mount(el), src: object.src, style: {
27061
+ }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.resolveThemeColor(object?.stroke, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => el && object.mount(el), src: object.src, style: {
26911
27062
  position: 'absolute',
26912
27063
  left: '0',
26913
27064
  top: '0',
@@ -26925,7 +27076,7 @@ const KritzelEngine = class {
26925
27076
  overflow: 'visible',
26926
27077
  userSelect: 'none',
26927
27078
  imageRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'pixelated' : 'auto',
26928
- }, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", { ref: el => object.mount(el), style: {
27079
+ }, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", { ref: el => el && object.mount(el), style: {
26929
27080
  position: 'absolute',
26930
27081
  left: '0',
26931
27082
  top: '0',
@@ -26942,7 +27093,7 @@ const KritzelEngine = class {
26942
27093
  padding: object.padding + 'px',
26943
27094
  overflow: 'hidden',
26944
27095
  display: 'block',
26945
- } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => object.mount(el), style: {
27096
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => el && object.mount(el), style: {
26946
27097
  position: 'absolute',
26947
27098
  left: '0',
26948
27099
  top: '0',
@@ -26952,7 +27103,7 @@ const KritzelEngine = class {
26952
27103
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
26953
27104
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26954
27105
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26955
- } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => object.mount(el), style: {
27106
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => el && object.mount(el), style: {
26956
27107
  position: 'absolute',
26957
27108
  left: '0',
26958
27109
  top: '0',
@@ -26976,7 +27127,7 @@ const KritzelEngine = class {
26976
27127
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
26977
27128
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
26978
27129
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
26979
- } }, 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: {
27130
+ } }, 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: {
26980
27131
  minWidth: object.initialWidth + 'px',
26981
27132
  minHeight: object.initialHeight + 'px',
26982
27133
  maxWidth: '500px',
@@ -26986,7 +27137,7 @@ const KritzelEngine = class {
26986
27137
  transform: `scale(${object.scaleFactor})`,
26987
27138
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
26988
27139
  overflow: 'visible',
26989
- } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
27140
+ } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
26990
27141
  position: 'absolute',
26991
27142
  left: '0',
26992
27143
  top: '0',
@@ -27005,7 +27156,7 @@ const KritzelEngine = class {
27005
27156
  height: '100%',
27006
27157
  overflow: 'visible',
27007
27158
  pointerEvents: 'none',
27008
- }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), h("div", { ref: el => object.mountTextEditor(el), style: {
27159
+ }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme), stroke: KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme), "stroke-width": object.strokeWidth })), h("div", { ref: el => el && object.mountTextEditor(el), style: {
27009
27160
  position: 'absolute',
27010
27161
  top: '0',
27011
27162
  left: '0',
@@ -27026,8 +27177,8 @@ const KritzelEngine = class {
27026
27177
  } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
27027
27178
  (() => {
27028
27179
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
27029
- const localClientId = this.core.store.state.objects?.localClientId;
27030
- const awarenessStates = this.core.store.state.objects?.awareness?.getStates();
27180
+ const localClientId = this.core.store.objects?.localClientId;
27181
+ const awarenessStates = this.core.store.objects?.awareness?.getStates();
27031
27182
  const isRemoteSelection = isSelectionGroup && (
27032
27183
  // Different user
27033
27184
  (object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
@@ -27255,18 +27406,20 @@ const KritzelEngine = class {
27255
27406
  stroke: 'var(--kritzel-snap-indicator-stroke, #007bff)',
27256
27407
  strokeWidth: data.indicatorStrokeWidth,
27257
27408
  } }))));
27258
- })()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
27409
+ })()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { class: "context-menu", ref: el => (this.contextMenuElement = el ?? null), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
27259
27410
  position: 'fixed',
27260
27411
  left: `${this.core.store.state.contextMenuX}px`,
27261
27412
  top: `${this.core.store.state.contextMenuY}px`,
27262
27413
  zIndex: '10002',
27263
27414
  }, onActionSelected: event => {
27264
- event.detail.action({
27265
- x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
27266
- y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
27267
- }, this.core.store.selectionGroup?.objects);
27415
+ if (event.detail.action) {
27416
+ event.detail.action({
27417
+ x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
27418
+ y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
27419
+ }, this.core.store.selectionGroup?.objects || []);
27420
+ }
27268
27421
  this.hideContextMenu();
27269
- }, onClose: () => this.hideContextMenu() })), this.core.store.state.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core })));
27422
+ }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core })));
27270
27423
  }
27271
27424
  static get watchers() { return {
27272
27425
  "workspace": [{
@@ -27310,6 +27463,9 @@ const KritzelEngine = class {
27310
27463
  }],
27311
27464
  "debugInfo": [{
27312
27465
  "onDebugInfoChange": 0
27466
+ }],
27467
+ "isLoading": [{
27468
+ "onIsLoadingChange": 0
27313
27469
  }]
27314
27470
  }; }
27315
27471
  };
@@ -28537,7 +28693,7 @@ const KritzelPortal = class {
28537
28693
  * This file is auto-generated by the version bump scripts.
28538
28694
  * Do not modify manually.
28539
28695
  */
28540
- const KRITZEL_VERSION = '0.1.78';
28696
+ const KRITZEL_VERSION = '0.1.80';
28541
28697
 
28542
28698
  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)}`;
28543
28699