kritzel-stencil 0.3.2 → 0.3.7

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 (66) hide show
  1. package/dist/cjs/index.cjs.js +70 -1
  2. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +167 -41
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/stencil.cjs.js +1 -1
  5. package/dist/cjs/{workspace.migrations-C1ZoE9o5.js → workspace.migrations-BlC8KRoQ.js} +12 -71
  6. package/dist/collection/classes/core/core.class.js +16 -5
  7. package/dist/collection/classes/core/store.class.js +8 -1
  8. package/dist/collection/classes/handlers/key.handler.js +1 -2
  9. package/dist/collection/classes/objects/shape.class.js +2 -3
  10. package/dist/collection/classes/objects/text.class.js +2 -3
  11. package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +68 -0
  12. package/dist/collection/classes/registries/tool.registry.js +21 -9
  13. package/dist/collection/classes/tools/image-tool.class.js +2 -3
  14. package/dist/collection/classes/tools/line-tool.class.js +1 -2
  15. package/dist/collection/classes/tools/shape-tool.class.js +3 -4
  16. package/dist/collection/classes/tools/text-tool.class.js +2 -3
  17. package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +0 -2
  18. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +5 -6
  19. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +2 -1
  20. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +36 -34
  21. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.css +1 -0
  22. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +43 -9
  23. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +1 -1
  24. package/dist/collection/constants/version.js +1 -1
  25. package/dist/collection/helpers/tool-config.helper.js +6 -5
  26. package/dist/collection/index.js +1 -0
  27. package/dist/components/index.js +1 -1
  28. package/dist/components/kritzel-controls.js +1 -1
  29. package/dist/components/kritzel-editor.js +1 -1
  30. package/dist/components/kritzel-engine.js +1 -1
  31. package/dist/components/kritzel-more-menu.js +1 -1
  32. package/dist/components/kritzel-settings.js +1 -1
  33. package/dist/components/kritzel-tool-config.js +1 -1
  34. package/dist/components/kritzel-utility-panel.js +1 -1
  35. package/dist/components/p-8b9zAWnS.js +1 -0
  36. package/dist/components/{p-Cx6YyDdF.js → p-BV3EJRtU.js} +1 -1
  37. package/dist/components/p-CSODtZrV.js +1 -0
  38. package/dist/components/p-CoJdbj3f.js +1 -0
  39. package/dist/components/p-Ctd1w9-z.js +1 -0
  40. package/dist/components/{p-CTvfEvp0.js → p-D0ctIEh_.js} +1 -1
  41. package/dist/components/p-P0p4WBpa.js +9 -0
  42. package/dist/esm/index.js +71 -3
  43. package/dist/esm/kritzel-active-users_42.entry.js +167 -41
  44. package/dist/esm/loader.js +1 -1
  45. package/dist/esm/stencil.js +1 -1
  46. package/dist/esm/{workspace.migrations-DAPZgVVd.js → workspace.migrations-BLXBI--a.js} +13 -71
  47. package/dist/stencil/index.esm.js +1 -1
  48. package/dist/stencil/p-3058e485.entry.js +9 -0
  49. package/dist/stencil/p-BLXBI--a.js +1 -0
  50. package/dist/stencil/stencil.esm.js +1 -1
  51. package/dist/types/classes/core/core.class.d.ts +8 -0
  52. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +38 -0
  53. package/dist/types/classes/registries/tool.registry.d.ts +18 -8
  54. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +4 -0
  55. package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +4 -0
  56. package/dist/types/components.d.ts +2 -0
  57. package/dist/types/constants/version.d.ts +1 -1
  58. package/dist/types/index.d.ts +1 -0
  59. package/package.json +1 -1
  60. package/dist/components/p-BlkUdg5N.js +0 -1
  61. package/dist/components/p-CJfHfT5E.js +0 -1
  62. package/dist/components/p-CQVYExZL.js +0 -9
  63. package/dist/components/p-Clo5Ydi1.js +0 -1
  64. package/dist/components/p-S3uDfF_D.js +0 -1
  65. package/dist/stencil/p-DAPZgVVd.js +0 -1
  66. package/dist/stencil/p-ef426a72.entry.js +0 -9
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var workspace_migrations = require('./workspace.migrations-C1ZoE9o5.js');
3
+ var workspace_migrations = require('./workspace.migrations-BlC8KRoQ.js');
4
4
  var Y = require('yjs');
5
5
  var yWebsocket = require('y-websocket');
6
6
  require('y-indexeddb');
@@ -452,6 +452,74 @@ class BroadcastSyncProvider {
452
452
  }
453
453
  }
454
454
 
455
+ /**
456
+ * Module-scoped cache that survives component removal and remounting
457
+ * within the same JS runtime. Cleared on page reload.
458
+ */
459
+ const sessionCache = new Map();
460
+ /**
461
+ * In-memory sync provider for session-scoped persistence.
462
+ *
463
+ * State survives the component being removed from the DOM and later
464
+ * re-added within the same page session, but is lost on page reload.
465
+ * Intended for documentation demos where durable IndexedDB persistence
466
+ * is not desired.
467
+ */
468
+ class InMemorySyncProvider {
469
+ type = 'local';
470
+ doc;
471
+ cacheKey;
472
+ isConnected = false;
473
+ constructor(docName, doc, options) {
474
+ this.doc = doc;
475
+ this.cacheKey = options?.name ?? docName;
476
+ }
477
+ handleUpdate = (_update, origin) => {
478
+ // Skip updates that originated from connect() rehydration to avoid a
479
+ // redundant re-encode of the state we just applied.
480
+ if (origin === this) {
481
+ return;
482
+ }
483
+ sessionCache.set(this.cacheKey, Y__namespace.encodeStateAsUpdate(this.doc));
484
+ };
485
+ async connect() {
486
+ if (this.isConnected) {
487
+ return;
488
+ }
489
+ const cached = sessionCache.get(this.cacheKey);
490
+ if (cached) {
491
+ Y__namespace.applyUpdate(this.doc, cached, this);
492
+ }
493
+ this.doc.on('update', this.handleUpdate);
494
+ this.isConnected = true;
495
+ }
496
+ disconnect() {
497
+ this.isConnected = false;
498
+ }
499
+ async reconnect() {
500
+ this.disconnect();
501
+ return this.connect();
502
+ }
503
+ destroy() {
504
+ this.doc.off('update', this.handleUpdate);
505
+ this.isConnected = false;
506
+ }
507
+ /**
508
+ * Clears the in-memory cache.
509
+ *
510
+ * @param name - If provided, only the entry with this cache key is removed.
511
+ * If omitted, all entries are cleared.
512
+ */
513
+ static clear(name) {
514
+ if (name !== undefined) {
515
+ sessionCache.delete(name);
516
+ }
517
+ else {
518
+ sessionCache.clear();
519
+ }
520
+ }
521
+ }
522
+
455
523
  /**
456
524
  * WebSocket sync provider for real-time collaboration
457
525
  */
@@ -1128,5 +1196,6 @@ exports.runMigrations = workspace_migrations.runMigrations;
1128
1196
  exports.BroadcastSyncProvider = BroadcastSyncProvider;
1129
1197
  exports.HocuspocusSyncProvider = HocuspocusSyncProvider;
1130
1198
  exports.HttpAssetProvider = HttpAssetProvider;
1199
+ exports.InMemorySyncProvider = InMemorySyncProvider;
1131
1200
  exports.PresignedAssetProvider = PresignedAssetProvider;
1132
1201
  exports.WebSocketSyncProvider = WebSocketSyncProvider;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-CFnj_FXt.js');
4
- var workspace_migrations = require('./workspace.migrations-C1ZoE9o5.js');
4
+ var workspace_migrations = require('./workspace.migrations-BlC8KRoQ.js');
5
5
  var Y = require('yjs');
6
6
  require('y-indexeddb');
7
7
  require('y-websocket');
@@ -833,10 +833,11 @@ KritzelContextMenu.style = kritzelContextMenuCss();
833
833
 
834
834
  class KritzelToolConfigHelper {
835
835
  static getToolConfig(tool) {
836
- if (tool instanceof workspace_migrations.KritzelSelectionTool) {
836
+ const toolConstructorName = tool?.constructor?.name;
837
+ if (tool instanceof workspace_migrations.KritzelSelectionTool || toolConstructorName === 'KritzelSelectionTool') {
837
838
  return tool.getToolConfig();
838
839
  }
839
- if (tool instanceof workspace_migrations.KritzelBrushTool) {
840
+ if (tool instanceof workspace_migrations.KritzelBrushTool || toolConstructorName === 'KritzelBrushTool') {
840
841
  return {
841
842
  type: 'brush',
842
843
  colorProperty: 'color',
@@ -848,7 +849,7 @@ class KritzelToolConfigHelper {
848
849
  ],
849
850
  };
850
851
  }
851
- if (tool instanceof workspace_migrations.KritzelLineTool) {
852
+ if (tool instanceof workspace_migrations.KritzelLineTool || toolConstructorName === 'KritzelLineTool') {
852
853
  return {
853
854
  type: 'line',
854
855
  colorProperty: 'color',
@@ -861,7 +862,7 @@ class KritzelToolConfigHelper {
861
862
  ],
862
863
  };
863
864
  }
864
- if (tool instanceof workspace_migrations.KritzelShapeTool) {
865
+ if (tool instanceof workspace_migrations.KritzelShapeTool || toolConstructorName === 'KritzelShapeTool') {
865
866
  return {
866
867
  type: 'shape',
867
868
  colorProperty: 'strokeColor',
@@ -874,7 +875,7 @@ class KritzelToolConfigHelper {
874
875
  ],
875
876
  };
876
877
  }
877
- if (tool instanceof workspace_migrations.KritzelTextTool) {
878
+ if (tool instanceof workspace_migrations.KritzelTextTool || toolConstructorName === 'KritzelTextTool') {
878
879
  return {
879
880
  type: 'text',
880
881
  colorProperty: 'fontColor',
@@ -892,7 +893,7 @@ class KritzelToolConfigHelper {
892
893
  }
893
894
  }
894
895
 
895
- const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:100%}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:10000;position:relative;max-width:100%;overflow:hidden}.kritzel-tools-scroll{display:flex;flex-direction:row;align-items:center;gap:var(--kritzel-controls-gap, 8px);overflow-x:auto;overflow-y:hidden;flex:1 1 auto;min-width:0;padding:4px;margin:-4px;scrollbar-width:none;-ms-overflow-style:none}.kritzel-tools-scroll::-webkit-scrollbar{display:none}.scroll-indicator-left,.scroll-indicator-right{position:absolute;top:0;bottom:0;width:32px;pointer-events:none;opacity:0;transition:opacity 0.2s ease-out;z-index:1}.scroll-indicator-left{left:0;background:linear-gradient(to right, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:var(--kritzel-controls-border-radius, 16px) 0 0 var(--kritzel-controls-border-radius, 16px)}.scroll-indicator-right{right:0;background:linear-gradient(to left, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:0 var(--kritzel-controls-border-radius, 16px) var(--kritzel-controls-border-radius, 16px) 0}.scroll-indicator-left.visible,.scroll-indicator-right.visible{opacity:1}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-control-separator{width:1px;height:24px;background-color:var(--kritzel-controls-border, #ebebeb);margin:0 4px}.kritzel-control-split{position:relative;display:flex;align-items:center;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:var(--kritzel-controls-control-color, #000000)}.kritzel-control-split .kritzel-control-main{display:flex;justify-content:center;align-items:center;padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:inherit}.kritzel-control-split.selected .kritzel-control-main{border-radius:var(--kritzel-controls-control-border-radius, 12px) 0 0 var(--kritzel-controls-control-border-radius, 12px)}.kritzel-control-split .kritzel-control-dropdown{display:flex;justify-content:center;align-items:center;align-self:stretch;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:0 var(--kritzel-controls-control-border-radius, 12px) var(--kritzel-controls-control-border-radius, 12px) 0;color:inherit;width:0;padding:0;opacity:0;overflow:hidden;pointer-events:none;transition:width 0.15s ease-out, padding 0.15s ease-out, opacity 0.15s ease-out}.kritzel-control-split .kritzel-control-dropdown.visible{width:auto;padding:0 6px;opacity:1;pointer-events:auto}.kritzel-control-split .kritzel-control-main:focus,.kritzel-control-split .kritzel-control-main:hover,.kritzel-control-split .kritzel-control-dropdown:focus,.kritzel-control-split .kritzel-control-dropdown:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control-split .kritzel-control-main:active,.kritzel-control-split .kritzel-control-dropdown:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control-split.selected{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control-split.selected .kritzel-control-main:hover,.kritzel-control-split.selected .kritzel-control-dropdown:hover{background-color:rgba(255, 255, 255, 0.15)}.kritzel-submenu-content{display:flex;flex-direction:column;gap:var(--kritzel-submenu-gap, 4px);min-width:140px}.kritzel-submenu-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:8px;color:var(--kritzel-controls-control-color, #000000);font-size:14px;text-align:left;white-space:nowrap;-webkit-tap-highlight-color:transparent}.kritzel-submenu-item:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-submenu-item.active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF);color:var(--kritzel-controls-control-selected-color, #ffffff)}.kritzel-submenu-item.active:hover{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF)}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent;flex-shrink:0;width:0;opacity:0;overflow:hidden;pointer-events:none;margin-left:calc(-1 * var(--kritzel-controls-gap, 8px));transition:width 0.2s ease-out, opacity 0.2s ease-out, margin-left 0.2s ease-out}.kritzel-config-container.visible{width:40px;opacity:1;pointer-events:auto;margin-left:0;overflow:visible}.config-gradient-left{position:absolute;top:0;bottom:0;left:-32px;width:32px;background:linear-gradient(to right, transparent, var(--kritzel-controls-background-color, #ffffff));pointer-events:none;z-index:1;opacity:0;transition:opacity 0.2s ease-out}.config-gradient-left.visible{opacity:1}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:50%}.color-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.font-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.no-config{height:24px;width:24px;border-radius:50%;border:1px dashed gray}kritzel-tooltip{z-index:10001}`;
896
+ const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:100%;z-index:1}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:1;position:relative;max-width:100%;overflow:hidden}.kritzel-tools-scroll{display:flex;flex-direction:row;align-items:center;gap:var(--kritzel-controls-gap, 8px);overflow-x:auto;overflow-y:hidden;flex:1 1 auto;min-width:0;padding:4px;margin:-4px;scrollbar-width:none;-ms-overflow-style:none}.kritzel-tools-scroll::-webkit-scrollbar{display:none}.scroll-indicator-left,.scroll-indicator-right{position:absolute;top:0;bottom:0;width:32px;pointer-events:none;opacity:0;transition:opacity 0.2s ease-out;z-index:1}.scroll-indicator-left{left:0;background:linear-gradient(to right, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:var(--kritzel-controls-border-radius, 16px) 0 0 var(--kritzel-controls-border-radius, 16px)}.scroll-indicator-right{right:0;background:linear-gradient(to left, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:0 var(--kritzel-controls-border-radius, 16px) var(--kritzel-controls-border-radius, 16px) 0}.scroll-indicator-left.visible,.scroll-indicator-right.visible{opacity:1}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-control-separator{width:1px;height:24px;background-color:var(--kritzel-controls-border, #ebebeb);margin:0 4px}.kritzel-control-split{position:relative;display:flex;align-items:center;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:var(--kritzel-controls-control-color, #000000)}.kritzel-control-split .kritzel-control-main{display:flex;justify-content:center;align-items:center;padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:inherit}.kritzel-control-split.selected .kritzel-control-main{border-radius:var(--kritzel-controls-control-border-radius, 12px) 0 0 var(--kritzel-controls-control-border-radius, 12px)}.kritzel-control-split .kritzel-control-dropdown{display:flex;justify-content:center;align-items:center;align-self:stretch;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:0 var(--kritzel-controls-control-border-radius, 12px) var(--kritzel-controls-control-border-radius, 12px) 0;color:inherit;width:0;padding:0;opacity:0;overflow:hidden;pointer-events:none;transition:width 0.15s ease-out, padding 0.15s ease-out, opacity 0.15s ease-out}.kritzel-control-split .kritzel-control-dropdown.visible{width:auto;padding:0 6px;opacity:1;pointer-events:auto}.kritzel-control-split .kritzel-control-main:focus,.kritzel-control-split .kritzel-control-main:hover,.kritzel-control-split .kritzel-control-dropdown:focus,.kritzel-control-split .kritzel-control-dropdown:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control-split .kritzel-control-main:active,.kritzel-control-split .kritzel-control-dropdown:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control-split.selected{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control-split.selected .kritzel-control-main:hover,.kritzel-control-split.selected .kritzel-control-dropdown:hover{background-color:rgba(255, 255, 255, 0.15)}.kritzel-submenu-content{display:flex;flex-direction:column;gap:var(--kritzel-submenu-gap, 4px);min-width:140px}.kritzel-submenu-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:8px;color:var(--kritzel-controls-control-color, #000000);font-size:14px;text-align:left;white-space:nowrap;-webkit-tap-highlight-color:transparent}.kritzel-submenu-item:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-submenu-item.active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF);color:var(--kritzel-controls-control-selected-color, #ffffff)}.kritzel-submenu-item.active:hover{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF)}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent;flex-shrink:0;width:0;opacity:0;overflow:hidden;pointer-events:none;margin-left:calc(-1 * var(--kritzel-controls-gap, 8px));transition:width 0.2s ease-out, opacity 0.2s ease-out, margin-left 0.2s ease-out}.kritzel-config-container.visible{width:40px;opacity:1;pointer-events:auto;margin-left:0;overflow:visible}.config-gradient-left{position:absolute;top:0;bottom:0;left:-32px;width:32px;background:linear-gradient(to right, transparent, var(--kritzel-controls-background-color, #ffffff));pointer-events:none;z-index:1;opacity:0;transition:opacity 0.2s ease-out}.config-gradient-left.visible{opacity:1}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-global-pointer-cursor, pointer);border-radius:50%}.color-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.font-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-global-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.no-config{height:24px;width:24px;border-radius:50%;border:1px dashed gray}kritzel-tooltip{z-index:10001}`;
896
897
 
897
898
  const KritzelControls = class {
898
899
  constructor(hostRef) {
@@ -913,6 +914,9 @@ const KritzelControls = class {
913
914
  canScrollRight = false;
914
915
  needsScrolling = false;
915
916
  displayValues = null;
917
+ internalControls = [];
918
+ handleActiveToolChangeBound = this.handleActiveToolChange.bind(this);
919
+ handleSelectionChangeBound = this.handleSelectionChange.bind(this);
916
920
  handleKeyDown(event) {
917
921
  if (event.key === 'Escape') {
918
922
  event.preventDefault();
@@ -921,7 +925,7 @@ const KritzelControls = class {
921
925
  }
922
926
  }
923
927
  async handleActiveToolChange(event) {
924
- this.activeControl = this.controls.find(control => control.tool === event.detail) || null;
928
+ this.activeControl = this.internalControls.find(control => control.tool === event.detail) || null;
925
929
  if (this.activeControl?.tool) {
926
930
  this.updateDisplayValues(this.activeControl.tool);
927
931
  }
@@ -1003,6 +1007,12 @@ const KritzelControls = class {
1003
1007
  componentDidRender() {
1004
1008
  this.updateScrollIndicators();
1005
1009
  }
1010
+ disconnectedCallback() {
1011
+ if (this.kritzelEngine) {
1012
+ this.kritzelEngine.removeEventListener('activeToolChange', this.handleActiveToolChangeBound);
1013
+ this.kritzelEngine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
1014
+ }
1015
+ }
1006
1016
  updateScrollIndicators() {
1007
1017
  if (!this.toolsScrollRef)
1008
1018
  return;
@@ -1027,12 +1037,19 @@ const KritzelControls = class {
1027
1037
  if (!this.kritzelEngine) {
1028
1038
  throw new Error('kritzel-engine not found in parent element.');
1029
1039
  }
1040
+ this.kritzelEngine.addEventListener('activeToolChange', this.handleActiveToolChangeBound);
1041
+ this.kritzelEngine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
1030
1042
  }
1031
1043
  async initializeTools() {
1032
1044
  let hasDefault = false;
1033
- for (const c of this.controls) {
1034
- if (c.type === 'tool' && c.tool && typeof c.tool === 'function') {
1035
- const registered = await this.kritzelEngine.registerTool(c.name, c.tool, c.config);
1045
+ const newControls = this.controls.map(c => ({ ...c }));
1046
+ for (const c of newControls) {
1047
+ if (c.type === 'tool' && c.tool) {
1048
+ let toolConstructor = c.tool;
1049
+ if (typeof toolConstructor !== 'function') {
1050
+ toolConstructor = toolConstructor.constructor;
1051
+ }
1052
+ const registered = await this.kritzelEngine.registerTool(c.name, toolConstructor, c.config);
1036
1053
  if (registered) {
1037
1054
  c.tool = registered;
1038
1055
  }
@@ -1052,9 +1069,10 @@ const KritzelControls = class {
1052
1069
  }
1053
1070
  }
1054
1071
  }
1072
+ this.internalControls = newControls;
1055
1073
  // If no tool is marked as default, activate the first tool control
1056
1074
  if (!hasDefault) {
1057
- const firstTool = this.controls.find(c => c.type === 'tool' && c.tool);
1075
+ const firstTool = this.internalControls.find(c => c.type === 'tool' && c.tool);
1058
1076
  if (firstTool) {
1059
1077
  await this.kritzelEngine.changeActiveTool(firstTool.tool);
1060
1078
  this.activeControl = firstTool;
@@ -1100,21 +1118,20 @@ const KritzelControls = class {
1100
1118
  await this.handleControlClick(control);
1101
1119
  }
1102
1120
  render() {
1103
- const hasConfigUI = this.activeControl?.tool instanceof workspace_migrations.KritzelBrushTool ||
1104
- this.activeControl?.tool instanceof workspace_migrations.KritzelTextTool ||
1105
- this.activeControl?.tool instanceof workspace_migrations.KritzelLineTool ||
1106
- this.activeControl?.tool instanceof workspace_migrations.KritzelShapeTool ||
1107
- (this.activeControl?.tool instanceof workspace_migrations.KritzelSelectionTool && this.activeControl.tool.hasSelection());
1121
+ const activeToolConfig = this.activeControl?.tool
1122
+ ? KritzelToolConfigHelper.getToolConfig(this.activeControl.tool)
1123
+ : null;
1124
+ const hasConfigUI = activeToolConfig !== null;
1108
1125
  // Separate tool controls from config control
1109
- const toolControls = this.controls.filter(c => c.type === 'tool' || c.type === 'separator');
1110
- const configControl = this.controls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
1111
- return (index.h(index.Host, { key: '1e1e558582af482f2bffe065005584b760eca0bb', class: {
1126
+ const toolControls = this.internalControls.filter(c => c.type === 'tool' || c.type === 'separator');
1127
+ const configControl = this.internalControls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
1128
+ return (index.h(index.Host, { key: '7f2a5fed45ac89b34a86b87552ffaa1b94f44d8b', class: {
1112
1129
  mobile: this.isTouchDevice,
1113
- } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: 'd4f3a0d30be09d7bdbf6ece5bc1255c2e15fa5c2', style: {
1130
+ } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '2dcbbe498bce0b59fbd225d103f2e322d3b7ff85', style: {
1114
1131
  position: 'absolute',
1115
1132
  bottom: '56px',
1116
1133
  left: '12px',
1117
- }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: 'cf7cdb4a097ff53b3788e05d76ea4b33eb58969b', class: "kritzel-controls" }, index.h("div", { key: '0d5561f50ddd3d1b0601855f8e46f47c0ceb0b75', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: '0e072381f68873156cd4482fab2ede6e8e994dc3', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1134
+ }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '6431079040502a78f021c612a7e953b1349f319a', class: "kritzel-controls" }, index.h("div", { key: '6e0d6dce107cf6b54fb904809fd525ce3b2ae4f0', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: '2686304ad10deac2d022e1deba19195587659d64', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1118
1135
  // Check if this control has sub-options (split-button)
1119
1136
  if (control.subOptions?.length) {
1120
1137
  const selectedSubOption = this.getSelectedSubOption(control);
@@ -1144,10 +1161,10 @@ const KritzelControls = class {
1144
1161
  'kritzel-control': true,
1145
1162
  'selected': this.activeControl?.name === control?.name,
1146
1163
  }, key: control.name, "data-testid": `tool-${control.name}`, onClick: _event => this.handleControlClick?.(control), "aria-label": control.name.charAt(0).toUpperCase() + control.name.slice(1) }, index.h("kritzel-icon", { name: control.icon })));
1147
- })), index.h("div", { key: 'fa36d29f6609b34d06beecf10402a48ee92a115a', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
1164
+ })), index.h("div", { key: 'f4bcbc856f6e027cdb579356faf54288b43aa080', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
1148
1165
  'kritzel-config-container': true,
1149
1166
  'visible': hasConfigUI,
1150
- }, key: configControl.name }, index.h("div", { key: '7ae1a911cc15561efe9fb6f60f4046e0b443959e', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: '6e27b488e1fffefafc85f0bc981f49695e317f99', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: '235d66bab4c80e77b04e8cefd9f4f3db17928d60', tool: this.activeControl.tool, theme: this.theme, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: 'e1752b2de626ecd36ded0fcbc45333bf6847b155', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1167
+ }, key: configControl.name }, index.h("div", { key: '0646c98b32047f51841f75dd5fb57813ebb153f5', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: '0816b8d7ca55add3c6a81de788be3c61a8a814f2', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: '8f299593454e7855d83ad5d79b528940b2dcb202', tool: this.activeControl.tool, theme: this.theme, engine: this.kritzelEngine, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: '8b2dc1dcc61df93a92cea8ba2aeb776e57965ab3', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1151
1168
  if (el)
1152
1169
  this.configTriggerRef = el;
1153
1170
  }, onKeyDown: event => {
@@ -1156,7 +1173,7 @@ const KritzelControls = class {
1156
1173
  }
1157
1174
  }, style: {
1158
1175
  cursor: 'pointer',
1159
- } }, this.displayValues && (index.h("div", { key: 'dd1bd3067a91a9b6bda71addce88ea2f0ad73e79', class: "color-container" }, index.h("kritzel-color", { key: 'b2882d7910f4df1f39672eacf540ecfe0bf4413c', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1176
+ } }, this.displayValues && (index.h("div", { key: '1074fc05048aed92ec9d62e347822df0a57a80e4', class: "color-container" }, index.h("kritzel-color", { key: '222efa6883ccbc6c97d10360039a1315de7d6273', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1160
1177
  borderRadius: '50%',
1161
1178
  border: 'none',
1162
1179
  } })))))))));
@@ -2113,7 +2130,7 @@ const DEFAULT_SYNC_CONFIG = {
2113
2130
  ],
2114
2131
  };
2115
2132
 
2116
- const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:start;line-height:normal}kritzel-controls{position:absolute;left:0;right:0;margin-inline:auto;width:max-content;max-width:calc(100% - 16px);bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px;z-index:10000}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px;z-index:10000}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
2133
+ const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:start;line-height:normal}kritzel-controls{position:absolute;left:0;right:0;margin-inline:auto;width:max-content;max-width:calc(100% - 16px);bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
2117
2134
 
2118
2135
  const KritzelEditor = class {
2119
2136
  constructor(hostRef) {
@@ -20984,7 +21001,7 @@ class KritzelKeyHandler extends workspace_migrations.KritzelBaseHandler {
20984
21001
  * @param index - The zero-based index of the tool to activate from the tool registry.
20985
21002
  */
20986
21003
  switchToolByIndex(index) {
20987
- const toolInstance = workspace_migrations.KritzelToolRegistry.getToolByIndex(index);
21004
+ const toolInstance = this._core.toolRegistry.getToolByIndex(index);
20988
21005
  if (toolInstance) {
20989
21006
  this._core.store.setState('activeTool', toolInstance);
20990
21007
  this._core.deselectAllObjects();
@@ -21496,6 +21513,76 @@ class AlignmentHelper {
21496
21513
  }
21497
21514
  }
21498
21515
 
21516
+ /**
21517
+ * A per-engine registry for managing drawing tools in the Kritzel library.
21518
+ * Each `KritzelCore` owns its own `KritzelToolRegistry` instance so that
21519
+ * multiple editors on the same page do not share tool instances or configs.
21520
+ *
21521
+ * Tools are instantiated and stored by name, allowing retrieval by name or index.
21522
+ */
21523
+ class KritzelToolRegistry {
21524
+ core;
21525
+ /** Internal storage for registered tools, mapping tool names to their instances. */
21526
+ registry = {};
21527
+ /**
21528
+ * Creates a new tool registry bound to a specific `KritzelCore` instance.
21529
+ * The bound core is used as the constructor argument when registering new tools.
21530
+ *
21531
+ * @param core - The `KritzelCore` instance this registry is bound to.
21532
+ */
21533
+ constructor(core) {
21534
+ this.core = core;
21535
+ }
21536
+ /**
21537
+ * Registers a new tool by instantiating it with the registry's bound core.
21538
+ * The tool is stored in the registry under the specified name.
21539
+ *
21540
+ * @param toolName - The unique identifier for the tool.
21541
+ * @param constructor - The tool class constructor that extends `KritzelBaseTool`.
21542
+ * @returns The newly created and registered tool instance.
21543
+ */
21544
+ registerTool(toolName, constructor) {
21545
+ const toolInstance = new constructor(this.core);
21546
+ toolInstance.name = toolName;
21547
+ this.registry[toolName] = toolInstance;
21548
+ return toolInstance;
21549
+ }
21550
+ /**
21551
+ * Checks if a tool with the given name is registered.
21552
+ *
21553
+ * @param toolName - The unique identifier of the tool to check.
21554
+ * @returns `true` if the tool is registered, `false` otherwise.
21555
+ */
21556
+ hasTool(toolName) {
21557
+ return toolName in this.registry;
21558
+ }
21559
+ /**
21560
+ * Retrieves a registered tool by its name.
21561
+ * Logs a warning if the tool is not found.
21562
+ *
21563
+ * @param toolName - The unique identifier of the tool to retrieve.
21564
+ * @returns The tool instance if found, or `null` if not registered.
21565
+ */
21566
+ getTool(toolName) {
21567
+ const toolInstance = this.registry[toolName];
21568
+ if (!toolInstance) {
21569
+ console.warn(`Unknown tool: ${toolName}`);
21570
+ return null;
21571
+ }
21572
+ return toolInstance;
21573
+ }
21574
+ /**
21575
+ * Retrieves a registered tool by its index in the registry.
21576
+ * The index is based on the order tools were registered.
21577
+ *
21578
+ * @param index - The zero-based index of the tool in the registry.
21579
+ * @returns The tool instance at the specified index, or `null` if the index is out of bounds.
21580
+ */
21581
+ getToolByIndex(index) {
21582
+ return Object.values(this.registry)[index] ?? null;
21583
+ }
21584
+ }
21585
+
21499
21586
  /**
21500
21587
  * A quadtree data structure for efficient spatial indexing of objects.
21501
21588
  * Quadtrees recursively subdivide 2D space into four quadrants to enable
@@ -23004,7 +23091,14 @@ class KritzelStore {
23004
23091
  * @param state - The initial engine state configuration
23005
23092
  */
23006
23093
  constructor(state) {
23007
- this._state = state;
23094
+ this._state = {
23095
+ ...state,
23096
+ contextMenuItems: [...state.contextMenuItems],
23097
+ debugInfo: { ...state.debugInfo },
23098
+ pointers: new Map(state.pointers),
23099
+ workspaces: [...state.workspaces],
23100
+ cursor: { ...state.cursor },
23101
+ };
23008
23102
  this._state.objects = new KritzelObjectMap();
23009
23103
  }
23010
23104
  /**
@@ -23643,6 +23737,8 @@ class KritzelCore {
23643
23737
  _cursorManager;
23644
23738
  /** Manager for theme styling */
23645
23739
  _themeManager;
23740
+ /** Per-core registry of drawing tools (one instance per editor). */
23741
+ _toolRegistry;
23646
23742
  /** Optional unique identifier for namespacing storage keys across multiple editor instances */
23647
23743
  _editorId;
23648
23744
  /** Current user for awareness broadcasting */
@@ -23689,6 +23785,13 @@ class KritzelCore {
23689
23785
  get themeManager() {
23690
23786
  return this._themeManager;
23691
23787
  }
23788
+ /**
23789
+ * Gets the tool registry scoped to this core instance.
23790
+ * @returns The KritzelToolRegistry owned by this core
23791
+ */
23792
+ get toolRegistry() {
23793
+ return this._toolRegistry;
23794
+ }
23692
23795
  /**
23693
23796
  * Gets the editor ID used for namespacing storage keys.
23694
23797
  * @returns The editor ID or undefined if not set
@@ -23734,6 +23837,7 @@ class KritzelCore {
23734
23837
  this._anchorManager = new workspace_migrations.KritzelAnchorManager(this);
23735
23838
  this._cursorManager = new KritzelCursorManager(this);
23736
23839
  this._themeManager = new workspace_migrations.KritzelThemeManager(this);
23840
+ this._toolRegistry = new KritzelToolRegistry(this);
23737
23841
  this._assetResolver = new workspace_migrations.KritzelAssetResolver();
23738
23842
  }
23739
23843
  /**
@@ -23840,6 +23944,7 @@ class KritzelCore {
23840
23944
  async initializeWorkspace(workspace, options) {
23841
23945
  // Load all workspaces from app state map
23842
23946
  const workspaces = this.loadWorkspacesFromAppState();
23947
+ const shouldCreateEditorScopedFallback = !workspace && !!this._editorId;
23843
23948
  // Find newest created workspace (tie-break by most recently updated)
23844
23949
  const newestCreatedWorkspace = workspaces.length > 0
23845
23950
  ? [...workspaces].sort((a, b) => {
@@ -23865,7 +23970,7 @@ class KritzelCore {
23865
23970
  // Use last active workspace from localStorage
23866
23971
  activeWorkspace = lastActiveWorkspace;
23867
23972
  }
23868
- else if (newestCreatedWorkspace) {
23973
+ else if (newestCreatedWorkspace && !shouldCreateEditorScopedFallback) {
23869
23974
  // Use newest created workspace
23870
23975
  activeWorkspace = newestCreatedWorkspace;
23871
23976
  }
@@ -24430,7 +24535,7 @@ class KritzelCore {
24430
24535
  this._store.state.copiedObjectIdMapping = newIdMapping;
24431
24536
  }
24432
24537
  });
24433
- this._store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
24538
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24434
24539
  this.engine.emitObjectsChange();
24435
24540
  this.rerender();
24436
24541
  }
@@ -24619,7 +24724,7 @@ class KritzelCore {
24619
24724
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
24620
24725
  }
24621
24726
  this.addSelectionGroup(selectionGroup);
24622
- this._store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
24727
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24623
24728
  this.rerender();
24624
24729
  }
24625
24730
  }
@@ -24653,7 +24758,7 @@ class KritzelCore {
24653
24758
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
24654
24759
  }
24655
24760
  this.addSelectionGroup(selectionGroup);
24656
- this._store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
24761
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24657
24762
  this.rerender();
24658
24763
  }
24659
24764
  }
@@ -24809,7 +24914,7 @@ class KritzelCore {
24809
24914
  }
24810
24915
  this.resetActiveText();
24811
24916
  this.clearSelection();
24812
- this._store.setState('activeTool', workspace_migrations.KritzelToolRegistry.getTool('selection'));
24917
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24813
24918
  }
24814
24919
  /**
24815
24920
  * Determines whether to display the selection group UI for an object.
@@ -26503,8 +26608,8 @@ const KritzelEngine = class {
26503
26608
  }
26504
26609
  // If a tool with this name is already registered, return the existing instance
26505
26610
  // This avoids dual-package issues when tool classes are passed from external bundles
26506
- if (workspace_migrations.KritzelToolRegistry.hasTool(toolName)) {
26507
- const existingTool = workspace_migrations.KritzelToolRegistry.getTool(toolName);
26611
+ if (this.core.toolRegistry.hasTool(toolName)) {
26612
+ const existingTool = this.core.toolRegistry.getTool(toolName);
26508
26613
  if (toolConfig) {
26509
26614
  Object.entries(toolConfig).forEach(([key, value]) => {
26510
26615
  existingTool[key] = value;
@@ -26512,7 +26617,7 @@ const KritzelEngine = class {
26512
26617
  }
26513
26618
  return existingTool;
26514
26619
  }
26515
- const registeredTool = workspace_migrations.KritzelToolRegistry.registerTool(toolName, toolClass, this.core);
26620
+ const registeredTool = this.core.toolRegistry.registerTool(toolName, toolClass);
26516
26621
  if (toolConfig) {
26517
26622
  Object.entries(toolConfig).forEach(([key, value]) => {
26518
26623
  registeredTool[key] = value;
@@ -26790,7 +26895,7 @@ const KritzelEngine = class {
26790
26895
  * @param objects - The objects to select.
26791
26896
  */
26792
26897
  async selectObjects(objects) {
26793
- const selectionTool = workspace_migrations.KritzelToolRegistry.getTool('selection');
26898
+ const selectionTool = this.core.toolRegistry.getTool('selection');
26794
26899
  if (!selectionTool) {
26795
26900
  return;
26796
26901
  }
@@ -26801,7 +26906,7 @@ const KritzelEngine = class {
26801
26906
  }
26802
26907
  /** Selects all objects currently visible in the viewport. Switches to the selection tool automatically. */
26803
26908
  async selectAllObjectsInViewport() {
26804
- const selectionTool = workspace_migrations.KritzelToolRegistry.getTool('selection');
26909
+ const selectionTool = this.core.toolRegistry.getTool('selection');
26805
26910
  if (!selectionTool) {
26806
26911
  return;
26807
26912
  }
@@ -28905,7 +29010,7 @@ const KritzelMenuItem = class {
28905
29010
  };
28906
29011
  KritzelMenuItem.style = kritzelMenuItemCss();
28907
29012
 
28908
- const kritzelMoreMenuCss = () => `:host{display:inline-flex}.more-menu-wrapper{display:inline-flex;padding:var(--kritzel-more-menu-padding, 4px);background-color:var(--kritzel-more-menu-background-color, #ffffff);border-radius:var(--kritzel-more-menu-border-radius, 12px);box-shadow:var(--kritzel-more-menu-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-more-menu-border, 1px solid #ebebeb);opacity:0;pointer-events:none;transition:opacity 0.2s ease-out}.more-menu-wrapper.visible{opacity:1;pointer-events:auto}:host(.mobile){--kritzel-more-menu-button-hover-background-color:transparent;--kritzel-more-menu-button-active-background-color:transparent}.more-menu-button{display:flex;align-items:center;justify-content:center;width:var(--kritzel-more-menu-button-width, 40px);height:var(--kritzel-more-menu-button-height, 40px);padding:0;border:none;border-radius:var(--kritzel-more-menu-inner-border-radius, 12px);background-color:transparent;cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:none;transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none;color:var(--kritzel-more-menu-button-color, currentColor)}.more-menu-button:hover{background-color:var(--kritzel-more-menu-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.more-menu-button:focus-visible{background-color:var(--kritzel-more-menu-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.more-menu-button:active{background-color:var(--kritzel-more-menu-button-active-background-color, hsl(0, 0%, 0%, 4.3%))}`;
29013
+ const kritzelMoreMenuCss = () => `:host{display:inline-flex;z-index:1}.more-menu-wrapper{display:inline-flex;padding:var(--kritzel-more-menu-padding, 4px);background-color:var(--kritzel-more-menu-background-color, #ffffff);border-radius:var(--kritzel-more-menu-border-radius, 12px);box-shadow:var(--kritzel-more-menu-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-more-menu-border, 1px solid #ebebeb);opacity:0;pointer-events:none;transition:opacity 0.2s ease-out}.more-menu-wrapper.visible{opacity:1;pointer-events:auto}:host(.mobile){--kritzel-more-menu-button-hover-background-color:transparent;--kritzel-more-menu-button-active-background-color:transparent}.more-menu-button{display:flex;align-items:center;justify-content:center;width:var(--kritzel-more-menu-button-width, 40px);height:var(--kritzel-more-menu-button-height, 40px);padding:0;border:none;border-radius:var(--kritzel-more-menu-inner-border-radius, 12px);background-color:transparent;cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:none;transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none;color:var(--kritzel-more-menu-button-color, currentColor)}.more-menu-button:hover{background-color:var(--kritzel-more-menu-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.more-menu-button:focus-visible{background-color:var(--kritzel-more-menu-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.more-menu-button:active{background-color:var(--kritzel-more-menu-button-active-background-color, hsl(0, 0%, 0%, 4.3%))}`;
28909
29014
 
28910
29015
  const KritzelMoreMenu = class {
28911
29016
  constructor(hostRef) {
@@ -29469,7 +29574,7 @@ const KritzelPortal = class {
29469
29574
  * This file is auto-generated by the version bump scripts.
29470
29575
  * Do not modify manually.
29471
29576
  */
29472
- const KRITZEL_VERSION = '0.3.2';
29577
+ const KRITZEL_VERSION = '0.3.7';
29473
29578
 
29474
29579
  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)}`;
29475
29580
 
@@ -29995,9 +30100,19 @@ const KritzelToolConfig = class {
29995
30100
  }
29996
30101
  isExpanded = false;
29997
30102
  theme;
30103
+ engine;
30104
+ handleSelectionChangeBound = this.handleSelectionChange.bind(this);
29998
30105
  onThemeChange() {
29999
30106
  this.emitDisplayValues();
30000
30107
  }
30108
+ handleEngineChange(newEngine, oldEngine) {
30109
+ if (oldEngine) {
30110
+ oldEngine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30111
+ }
30112
+ if (newEngine) {
30113
+ newEngine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30114
+ }
30115
+ }
30001
30116
  toolChange;
30002
30117
  displayValuesChange;
30003
30118
  config;
@@ -30014,6 +30129,11 @@ const KritzelToolConfig = class {
30014
30129
  }
30015
30130
  }
30016
30131
  }
30132
+ disconnectedCallback() {
30133
+ if (this.engine) {
30134
+ this.engine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30135
+ }
30136
+ }
30017
30137
  componentWillLoad() {
30018
30138
  this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
30019
30139
  if (this.config) {
@@ -30021,6 +30141,9 @@ const KritzelToolConfig = class {
30021
30141
  this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
30022
30142
  this.emitDisplayValues();
30023
30143
  }
30144
+ if (this.engine) {
30145
+ this.engine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30146
+ }
30024
30147
  }
30025
30148
  emitDisplayValues() {
30026
30149
  if (!this.config)
@@ -30152,6 +30275,9 @@ const KritzelToolConfig = class {
30152
30275
  }],
30153
30276
  "theme": [{
30154
30277
  "onThemeChange": 0
30278
+ }],
30279
+ "engine": [{
30280
+ "handleEngineChange": 0
30155
30281
  }]
30156
30282
  }; }
30157
30283
  };
@@ -30312,7 +30438,7 @@ const KritzelTooltip = class {
30312
30438
  };
30313
30439
  KritzelTooltip.style = kritzelTooltipCss();
30314
30440
 
30315
- const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none;z-index:10000}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
30441
+ const kritzelUtilityPanelCss = () => `:host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:var(--kritzel-utility-panel-background-color, #e2e2e2);width:fit-content;user-select:none;z-index:1}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;background:none;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-utility-panel-button-color, #333333);--kritzel-icon-color:var(--kritzel-utility-panel-button-color, #333333);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:hover,.utility-button:focus-visible{background-color:var(--kritzel-utility-panel-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-button:disabled{opacity:0.4;cursor:not-allowed;pointer-events:none}.utility-separator{width:1px;height:16px;background-color:var(--kritzel-utility-panel-separator-color, hsl(0, 0%, 0%, 8%))}`;
30316
30442
 
30317
30443
  const KritzelUtilityPanel = class {
30318
30444
  constructor(hostRef) {