kritzel-stencil 0.3.1 → 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 (67) hide show
  1. package/dist/cjs/index.cjs.js +70 -1
  2. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +200 -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-D5sPPbQN.js → workspace.migrations-BlC8KRoQ.js} +12 -63
  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/context-menu.handler.js +2 -2
  9. package/dist/collection/classes/handlers/key.handler.js +1 -2
  10. package/dist/collection/classes/objects/shape.class.js +2 -3
  11. package/dist/collection/classes/objects/text.class.js +2 -3
  12. package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +68 -0
  13. package/dist/collection/classes/registries/tool.registry.js +29 -8
  14. package/dist/collection/classes/tools/image-tool.class.js +2 -3
  15. package/dist/collection/classes/tools/line-tool.class.js +1 -2
  16. package/dist/collection/classes/tools/shape-tool.class.js +3 -4
  17. package/dist/collection/classes/tools/text-tool.class.js +2 -3
  18. package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +0 -2
  19. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +16 -7
  20. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +2 -1
  21. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +56 -32
  22. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.css +1 -0
  23. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +43 -9
  24. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +1 -1
  25. package/dist/collection/constants/version.js +1 -1
  26. package/dist/collection/helpers/tool-config.helper.js +6 -5
  27. package/dist/collection/index.js +1 -0
  28. package/dist/components/index.js +1 -1
  29. package/dist/components/kritzel-controls.js +1 -1
  30. package/dist/components/kritzel-editor.js +1 -1
  31. package/dist/components/kritzel-engine.js +1 -1
  32. package/dist/components/kritzel-more-menu.js +1 -1
  33. package/dist/components/kritzel-settings.js +1 -1
  34. package/dist/components/kritzel-tool-config.js +1 -1
  35. package/dist/components/kritzel-utility-panel.js +1 -1
  36. package/dist/components/p-8b9zAWnS.js +1 -0
  37. package/dist/components/{p-Cx6YyDdF.js → p-BV3EJRtU.js} +1 -1
  38. package/dist/components/p-CSODtZrV.js +1 -0
  39. package/dist/components/p-CoJdbj3f.js +1 -0
  40. package/dist/components/p-Ctd1w9-z.js +1 -0
  41. package/dist/components/{p-C9jegh9w.js → p-D0ctIEh_.js} +1 -1
  42. package/dist/components/p-P0p4WBpa.js +9 -0
  43. package/dist/esm/index.js +71 -3
  44. package/dist/esm/kritzel-active-users_42.entry.js +200 -41
  45. package/dist/esm/loader.js +1 -1
  46. package/dist/esm/stencil.js +1 -1
  47. package/dist/esm/{workspace.migrations-BnTvdnKU.js → workspace.migrations-BLXBI--a.js} +13 -62
  48. package/dist/stencil/index.esm.js +1 -1
  49. package/dist/stencil/p-3058e485.entry.js +9 -0
  50. package/dist/stencil/p-BLXBI--a.js +1 -0
  51. package/dist/stencil/stencil.esm.js +1 -1
  52. package/dist/types/classes/core/core.class.d.ts +8 -0
  53. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +38 -0
  54. package/dist/types/classes/registries/tool.registry.d.ts +24 -7
  55. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +5 -0
  56. package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +4 -0
  57. package/dist/types/components.d.ts +2 -0
  58. package/dist/types/constants/version.d.ts +1 -1
  59. package/dist/types/index.d.ts +1 -0
  60. package/package.json +1 -1
  61. package/dist/components/p-BWB2UGxj.js +0 -9
  62. package/dist/components/p-BWJGv9ZO.js +0 -1
  63. package/dist/components/p-BWRjTm0J.js +0 -1
  64. package/dist/components/p-Clo5Ydi1.js +0 -1
  65. package/dist/components/p-D9-C4GfD.js +0 -1
  66. package/dist/stencil/p-BnTvdnKU.js +0 -1
  67. package/dist/stencil/p-bfd1fca8.entry.js +0 -9
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-D9HaikfQ.js';
2
- import { b as KritzelPath, d as KritzelLine, G as KritzelColorHelper, n as KritzelSelectionTool, g as KritzelBrushTool, h as KritzelLineTool, l as KritzelShapeTool, k as KritzelTextTool, J as KritzelDevicesHelper, L as KritzelMouseButton, M as DEFAULT_COLOR_PALETTE, S as ShapeType, I as IndexedDBSyncProvider, D as DEFAULT_BRUSH_CONFIG, i as KritzelEraserTool, u as DEFAULT_LINE_TOOL_CONFIG, t as DEFAULT_TEXT_CONFIG, j as KritzelImageTool, y as KritzelAlignment, v as DEFAULT_ASSET_STORAGE_CONFIG, N as KritzelSelectionGroup, O as KritzelSelectionBox, P as KritzelIconRegistry, Q as KritzelKeyboardHelper, R as KritzelBaseHandler, T as KritzelToolRegistry, U as KritzelBaseObject, q as KritzelWorkspace, e as KritzelGroup, c as KritzelImage, f as KritzelShape, K as KritzelText, B as runMigrations, z as CURRENT_WORKSPACE_SCHEMA_VERSION, F as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, E as APP_STATE_MIGRATIONS, V as ObjectHelper, m as KritzelCursorHelper, r as KritzelAnchorManager, s as KritzelThemeManager, o as KritzelAssetResolver, X as KritzelClassHelper, Y as KritzelEventHelper, Z as KritzelBaseTool, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-BnTvdnKU.js';
2
+ import { b as KritzelPath, d as KritzelLine, G as KritzelColorHelper, n as KritzelSelectionTool, g as KritzelBrushTool, h as KritzelLineTool, l as KritzelShapeTool, k as KritzelTextTool, J as KritzelDevicesHelper, L as KritzelMouseButton, M as DEFAULT_COLOR_PALETTE, S as ShapeType, I as IndexedDBSyncProvider, D as DEFAULT_BRUSH_CONFIG, i as KritzelEraserTool, u as DEFAULT_LINE_TOOL_CONFIG, t as DEFAULT_TEXT_CONFIG, j as KritzelImageTool, y as KritzelAlignment, v as DEFAULT_ASSET_STORAGE_CONFIG, N as KritzelSelectionGroup, O as KritzelSelectionBox, P as KritzelIconRegistry, Q as KritzelKeyboardHelper, R as KritzelBaseHandler, T as KritzelBaseObject, q as KritzelWorkspace, e as KritzelGroup, c as KritzelImage, f as KritzelShape, K as KritzelText, B as runMigrations, z as CURRENT_WORKSPACE_SCHEMA_VERSION, F as WORKSPACE_MIGRATIONS, C as CURRENT_APP_STATE_SCHEMA_VERSION, E as APP_STATE_MIGRATIONS, U as ObjectHelper, m as KritzelCursorHelper, r as KritzelAnchorManager, s as KritzelThemeManager, o as KritzelAssetResolver, V as KritzelClassHelper, X as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './workspace.migrations-BLXBI--a.js';
3
3
  import * as Y from 'yjs';
4
4
  import 'y-indexeddb';
5
5
  import 'y-websocket';
@@ -811,10 +811,11 @@ KritzelContextMenu.style = kritzelContextMenuCss();
811
811
 
812
812
  class KritzelToolConfigHelper {
813
813
  static getToolConfig(tool) {
814
- if (tool instanceof KritzelSelectionTool) {
814
+ const toolConstructorName = tool?.constructor?.name;
815
+ if (tool instanceof KritzelSelectionTool || toolConstructorName === 'KritzelSelectionTool') {
815
816
  return tool.getToolConfig();
816
817
  }
817
- if (tool instanceof KritzelBrushTool) {
818
+ if (tool instanceof KritzelBrushTool || toolConstructorName === 'KritzelBrushTool') {
818
819
  return {
819
820
  type: 'brush',
820
821
  colorProperty: 'color',
@@ -826,7 +827,7 @@ class KritzelToolConfigHelper {
826
827
  ],
827
828
  };
828
829
  }
829
- if (tool instanceof KritzelLineTool) {
830
+ if (tool instanceof KritzelLineTool || toolConstructorName === 'KritzelLineTool') {
830
831
  return {
831
832
  type: 'line',
832
833
  colorProperty: 'color',
@@ -839,7 +840,7 @@ class KritzelToolConfigHelper {
839
840
  ],
840
841
  };
841
842
  }
842
- if (tool instanceof KritzelShapeTool) {
843
+ if (tool instanceof KritzelShapeTool || toolConstructorName === 'KritzelShapeTool') {
843
844
  return {
844
845
  type: 'shape',
845
846
  colorProperty: 'strokeColor',
@@ -852,7 +853,7 @@ class KritzelToolConfigHelper {
852
853
  ],
853
854
  };
854
855
  }
855
- if (tool instanceof KritzelTextTool) {
856
+ if (tool instanceof KritzelTextTool || toolConstructorName === 'KritzelTextTool') {
856
857
  return {
857
858
  type: 'text',
858
859
  colorProperty: 'fontColor',
@@ -870,7 +871,7 @@ class KritzelToolConfigHelper {
870
871
  }
871
872
  }
872
873
 
873
- 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}`;
874
+ 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}`;
874
875
 
875
876
  const KritzelControls = class {
876
877
  constructor(hostRef) {
@@ -891,6 +892,9 @@ const KritzelControls = class {
891
892
  canScrollRight = false;
892
893
  needsScrolling = false;
893
894
  displayValues = null;
895
+ internalControls = [];
896
+ handleActiveToolChangeBound = this.handleActiveToolChange.bind(this);
897
+ handleSelectionChangeBound = this.handleSelectionChange.bind(this);
894
898
  handleKeyDown(event) {
895
899
  if (event.key === 'Escape') {
896
900
  event.preventDefault();
@@ -899,7 +903,7 @@ const KritzelControls = class {
899
903
  }
900
904
  }
901
905
  async handleActiveToolChange(event) {
902
- this.activeControl = this.controls.find(control => control.tool === event.detail) || null;
906
+ this.activeControl = this.internalControls.find(control => control.tool === event.detail) || null;
903
907
  if (this.activeControl?.tool) {
904
908
  this.updateDisplayValues(this.activeControl.tool);
905
909
  }
@@ -910,6 +914,11 @@ const KritzelControls = class {
910
914
  this.updateDisplayValues(this.activeControl.tool);
911
915
  }
912
916
  }
917
+ async onControlsChange() {
918
+ if (this.kritzelEngine) {
919
+ await this.initializeTools();
920
+ }
921
+ }
913
922
  onThemeChange() {
914
923
  if (this.activeControl?.tool) {
915
924
  this.updateDisplayValues(this.activeControl.tool);
@@ -976,6 +985,12 @@ const KritzelControls = class {
976
985
  componentDidRender() {
977
986
  this.updateScrollIndicators();
978
987
  }
988
+ disconnectedCallback() {
989
+ if (this.kritzelEngine) {
990
+ this.kritzelEngine.removeEventListener('activeToolChange', this.handleActiveToolChangeBound);
991
+ this.kritzelEngine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
992
+ }
993
+ }
979
994
  updateScrollIndicators() {
980
995
  if (!this.toolsScrollRef)
981
996
  return;
@@ -1000,16 +1015,28 @@ const KritzelControls = class {
1000
1015
  if (!this.kritzelEngine) {
1001
1016
  throw new Error('kritzel-engine not found in parent element.');
1002
1017
  }
1018
+ this.kritzelEngine.addEventListener('activeToolChange', this.handleActiveToolChangeBound);
1019
+ this.kritzelEngine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
1003
1020
  }
1004
1021
  async initializeTools() {
1005
- for (const c of this.controls) {
1022
+ let hasDefault = false;
1023
+ const newControls = this.controls.map(c => ({ ...c }));
1024
+ for (const c of newControls) {
1006
1025
  if (c.type === 'tool' && c.tool) {
1007
- c.tool = await this.kritzelEngine.registerTool(c.name, c.tool, c.config);
1026
+ let toolConstructor = c.tool;
1027
+ if (typeof toolConstructor !== 'function') {
1028
+ toolConstructor = toolConstructor.constructor;
1029
+ }
1030
+ const registered = await this.kritzelEngine.registerTool(c.name, toolConstructor, c.config);
1031
+ if (registered) {
1032
+ c.tool = registered;
1033
+ }
1008
1034
  }
1009
1035
  if (c.type === 'tool' && c.isDefault && c.tool) {
1010
1036
  await this.kritzelEngine.changeActiveTool(c.tool);
1011
1037
  this.activeControl = c;
1012
1038
  this.updateDisplayValues(c.tool);
1039
+ hasDefault = true;
1013
1040
  }
1014
1041
  if (c.type === 'config') {
1015
1042
  if (this.firstConfig === null) {
@@ -1020,6 +1047,16 @@ const KritzelControls = class {
1020
1047
  }
1021
1048
  }
1022
1049
  }
1050
+ this.internalControls = newControls;
1051
+ // If no tool is marked as default, activate the first tool control
1052
+ if (!hasDefault) {
1053
+ const firstTool = this.internalControls.find(c => c.type === 'tool' && c.tool);
1054
+ if (firstTool) {
1055
+ await this.kritzelEngine.changeActiveTool(firstTool.tool);
1056
+ this.activeControl = firstTool;
1057
+ this.updateDisplayValues(firstTool.tool);
1058
+ }
1059
+ }
1023
1060
  }
1024
1061
  async handleControlClick(control) {
1025
1062
  this.activeControl = control;
@@ -1059,21 +1096,20 @@ const KritzelControls = class {
1059
1096
  await this.handleControlClick(control);
1060
1097
  }
1061
1098
  render() {
1062
- const hasConfigUI = this.activeControl?.tool instanceof KritzelBrushTool ||
1063
- this.activeControl?.tool instanceof KritzelTextTool ||
1064
- this.activeControl?.tool instanceof KritzelLineTool ||
1065
- this.activeControl?.tool instanceof KritzelShapeTool ||
1066
- (this.activeControl?.tool instanceof KritzelSelectionTool && this.activeControl.tool.hasSelection());
1099
+ const activeToolConfig = this.activeControl?.tool
1100
+ ? KritzelToolConfigHelper.getToolConfig(this.activeControl.tool)
1101
+ : null;
1102
+ const hasConfigUI = activeToolConfig !== null;
1067
1103
  // Separate tool controls from config control
1068
- const toolControls = this.controls.filter(c => c.type === 'tool' || c.type === 'separator');
1069
- const configControl = this.controls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
1070
- return (h(Host, { key: '93d08a3268edb67fc4cccb291b6e0aff6cf5a4bd', class: {
1104
+ const toolControls = this.internalControls.filter(c => c.type === 'tool' || c.type === 'separator');
1105
+ const configControl = this.internalControls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
1106
+ return (h(Host, { key: '7f2a5fed45ac89b34a86b87552ffaa1b94f44d8b', class: {
1071
1107
  mobile: this.isTouchDevice,
1072
- } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '8862ea7e524b3e23d87ffea2929e04df7231bb0c', style: {
1108
+ } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '2dcbbe498bce0b59fbd225d103f2e322d3b7ff85', style: {
1073
1109
  position: 'absolute',
1074
1110
  bottom: '56px',
1075
1111
  left: '12px',
1076
- }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '2ea2a41ba4cda77f5abde9231d293da181a2a568', class: "kritzel-controls" }, h("div", { key: '6bd4f6d930a0a51d5549b6dbae1e7be14cbe7822', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), h("div", { key: 'c712ca502a4ebd244394158b39391a49839bc386', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1112
+ }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '6431079040502a78f021c612a7e953b1349f319a', class: "kritzel-controls" }, h("div", { key: '6e0d6dce107cf6b54fb904809fd525ce3b2ae4f0', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), h("div", { key: '2686304ad10deac2d022e1deba19195587659d64', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1077
1113
  // Check if this control has sub-options (split-button)
1078
1114
  if (control.subOptions?.length) {
1079
1115
  const selectedSubOption = this.getSelectedSubOption(control);
@@ -1103,10 +1139,10 @@ const KritzelControls = class {
1103
1139
  'kritzel-control': true,
1104
1140
  'selected': this.activeControl?.name === control?.name,
1105
1141
  }, key: control.name, "data-testid": `tool-${control.name}`, onClick: _event => this.handleControlClick?.(control), "aria-label": control.name.charAt(0).toUpperCase() + control.name.slice(1) }, h("kritzel-icon", { name: control.icon })));
1106
- })), h("div", { key: '0d8ae76ea22cb0aea4f7971a17c787c722d1f476', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (h("div", { class: {
1142
+ })), h("div", { key: 'f4bcbc856f6e027cdb579356faf54288b43aa080', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (h("div", { class: {
1107
1143
  'kritzel-config-container': true,
1108
1144
  'visible': hasConfigUI,
1109
- }, key: configControl.name }, h("div", { key: 'd3da3913362d96109f618c86bd8370f6253a1b7c', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), h("kritzel-tooltip", { key: '26fed6901c67362ec0c18eacd23b48fff5a361ef', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, h("kritzel-tool-config", { key: '0371c038859c0bc3c413b8c72a836d611da01608', tool: this.activeControl.tool, theme: this.theme, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), h("div", { key: 'b9bb29fc19ee335103ea050155f5e240f2ad2cd9', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1145
+ }, key: configControl.name }, h("div", { key: '0646c98b32047f51841f75dd5fb57813ebb153f5', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), h("kritzel-tooltip", { key: '0816b8d7ca55add3c6a81de788be3c61a8a814f2', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, 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%' } })), h("div", { key: '8b2dc1dcc61df93a92cea8ba2aeb776e57965ab3', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1110
1146
  if (el)
1111
1147
  this.configTriggerRef = el;
1112
1148
  }, onKeyDown: event => {
@@ -1115,13 +1151,16 @@ const KritzelControls = class {
1115
1151
  }
1116
1152
  }, style: {
1117
1153
  cursor: 'pointer',
1118
- } }, this.displayValues && (h("div", { key: '5918f90d824c41700c5dac4fca13cb8b47759473', class: "color-container" }, h("kritzel-color", { key: '08b7847f1d9117cec216979016d10d7b25076ecc', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1154
+ } }, this.displayValues && (h("div", { key: '1074fc05048aed92ec9d62e347822df0a57a80e4', class: "color-container" }, h("kritzel-color", { key: '222efa6883ccbc6c97d10360039a1315de7d6273', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1119
1155
  borderRadius: '50%',
1120
1156
  border: 'none',
1121
1157
  } })))))))));
1122
1158
  }
1123
1159
  static get assetsDirs() { return ["../assets"]; }
1124
1160
  static get watchers() { return {
1161
+ "controls": [{
1162
+ "onControlsChange": 0
1163
+ }],
1125
1164
  "theme": [{
1126
1165
  "onThemeChange": 0
1127
1166
  }]
@@ -2069,7 +2108,7 @@ const DEFAULT_SYNC_CONFIG = {
2069
2108
  ],
2070
2109
  };
2071
2110
 
2072
- 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}`;
2111
+ 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}`;
2073
2112
 
2074
2113
  const KritzelEditor = class {
2075
2114
  constructor(hostRef) {
@@ -20940,7 +20979,7 @@ class KritzelKeyHandler extends KritzelBaseHandler {
20940
20979
  * @param index - The zero-based index of the tool to activate from the tool registry.
20941
20980
  */
20942
20981
  switchToolByIndex(index) {
20943
- const toolInstance = KritzelToolRegistry.getToolByIndex(index);
20982
+ const toolInstance = this._core.toolRegistry.getToolByIndex(index);
20944
20983
  if (toolInstance) {
20945
20984
  this._core.store.setState('activeTool', toolInstance);
20946
20985
  this._core.deselectAllObjects();
@@ -21071,8 +21110,8 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
21071
21110
  let y = clickY;
21072
21111
  const menuWidthEstimate = 150;
21073
21112
  const margin = 10;
21074
- if (x + menuWidthEstimate > window.innerWidth - margin) {
21075
- x = window.innerWidth - menuWidthEstimate - margin;
21113
+ if (x + menuWidthEstimate > this._core.store.state.viewportWidth - margin) {
21114
+ x = this._core.store.state.viewportWidth - menuWidthEstimate - margin;
21076
21115
  }
21077
21116
  x = Math.max(margin, x);
21078
21117
  y = Math.max(margin, y);
@@ -21452,6 +21491,76 @@ class AlignmentHelper {
21452
21491
  }
21453
21492
  }
21454
21493
 
21494
+ /**
21495
+ * A per-engine registry for managing drawing tools in the Kritzel library.
21496
+ * Each `KritzelCore` owns its own `KritzelToolRegistry` instance so that
21497
+ * multiple editors on the same page do not share tool instances or configs.
21498
+ *
21499
+ * Tools are instantiated and stored by name, allowing retrieval by name or index.
21500
+ */
21501
+ class KritzelToolRegistry {
21502
+ core;
21503
+ /** Internal storage for registered tools, mapping tool names to their instances. */
21504
+ registry = {};
21505
+ /**
21506
+ * Creates a new tool registry bound to a specific `KritzelCore` instance.
21507
+ * The bound core is used as the constructor argument when registering new tools.
21508
+ *
21509
+ * @param core - The `KritzelCore` instance this registry is bound to.
21510
+ */
21511
+ constructor(core) {
21512
+ this.core = core;
21513
+ }
21514
+ /**
21515
+ * Registers a new tool by instantiating it with the registry's bound core.
21516
+ * The tool is stored in the registry under the specified name.
21517
+ *
21518
+ * @param toolName - The unique identifier for the tool.
21519
+ * @param constructor - The tool class constructor that extends `KritzelBaseTool`.
21520
+ * @returns The newly created and registered tool instance.
21521
+ */
21522
+ registerTool(toolName, constructor) {
21523
+ const toolInstance = new constructor(this.core);
21524
+ toolInstance.name = toolName;
21525
+ this.registry[toolName] = toolInstance;
21526
+ return toolInstance;
21527
+ }
21528
+ /**
21529
+ * Checks if a tool with the given name is registered.
21530
+ *
21531
+ * @param toolName - The unique identifier of the tool to check.
21532
+ * @returns `true` if the tool is registered, `false` otherwise.
21533
+ */
21534
+ hasTool(toolName) {
21535
+ return toolName in this.registry;
21536
+ }
21537
+ /**
21538
+ * Retrieves a registered tool by its name.
21539
+ * Logs a warning if the tool is not found.
21540
+ *
21541
+ * @param toolName - The unique identifier of the tool to retrieve.
21542
+ * @returns The tool instance if found, or `null` if not registered.
21543
+ */
21544
+ getTool(toolName) {
21545
+ const toolInstance = this.registry[toolName];
21546
+ if (!toolInstance) {
21547
+ console.warn(`Unknown tool: ${toolName}`);
21548
+ return null;
21549
+ }
21550
+ return toolInstance;
21551
+ }
21552
+ /**
21553
+ * Retrieves a registered tool by its index in the registry.
21554
+ * The index is based on the order tools were registered.
21555
+ *
21556
+ * @param index - The zero-based index of the tool in the registry.
21557
+ * @returns The tool instance at the specified index, or `null` if the index is out of bounds.
21558
+ */
21559
+ getToolByIndex(index) {
21560
+ return Object.values(this.registry)[index] ?? null;
21561
+ }
21562
+ }
21563
+
21455
21564
  /**
21456
21565
  * A quadtree data structure for efficient spatial indexing of objects.
21457
21566
  * Quadtrees recursively subdivide 2D space into four quadrants to enable
@@ -22960,7 +23069,14 @@ class KritzelStore {
22960
23069
  * @param state - The initial engine state configuration
22961
23070
  */
22962
23071
  constructor(state) {
22963
- this._state = state;
23072
+ this._state = {
23073
+ ...state,
23074
+ contextMenuItems: [...state.contextMenuItems],
23075
+ debugInfo: { ...state.debugInfo },
23076
+ pointers: new Map(state.pointers),
23077
+ workspaces: [...state.workspaces],
23078
+ cursor: { ...state.cursor },
23079
+ };
22964
23080
  this._state.objects = new KritzelObjectMap();
22965
23081
  }
22966
23082
  /**
@@ -23599,6 +23715,8 @@ class KritzelCore {
23599
23715
  _cursorManager;
23600
23716
  /** Manager for theme styling */
23601
23717
  _themeManager;
23718
+ /** Per-core registry of drawing tools (one instance per editor). */
23719
+ _toolRegistry;
23602
23720
  /** Optional unique identifier for namespacing storage keys across multiple editor instances */
23603
23721
  _editorId;
23604
23722
  /** Current user for awareness broadcasting */
@@ -23645,6 +23763,13 @@ class KritzelCore {
23645
23763
  get themeManager() {
23646
23764
  return this._themeManager;
23647
23765
  }
23766
+ /**
23767
+ * Gets the tool registry scoped to this core instance.
23768
+ * @returns The KritzelToolRegistry owned by this core
23769
+ */
23770
+ get toolRegistry() {
23771
+ return this._toolRegistry;
23772
+ }
23648
23773
  /**
23649
23774
  * Gets the editor ID used for namespacing storage keys.
23650
23775
  * @returns The editor ID or undefined if not set
@@ -23690,6 +23815,7 @@ class KritzelCore {
23690
23815
  this._anchorManager = new KritzelAnchorManager(this);
23691
23816
  this._cursorManager = new KritzelCursorManager(this);
23692
23817
  this._themeManager = new KritzelThemeManager(this);
23818
+ this._toolRegistry = new KritzelToolRegistry(this);
23693
23819
  this._assetResolver = new KritzelAssetResolver();
23694
23820
  }
23695
23821
  /**
@@ -23796,6 +23922,7 @@ class KritzelCore {
23796
23922
  async initializeWorkspace(workspace, options) {
23797
23923
  // Load all workspaces from app state map
23798
23924
  const workspaces = this.loadWorkspacesFromAppState();
23925
+ const shouldCreateEditorScopedFallback = !workspace && !!this._editorId;
23799
23926
  // Find newest created workspace (tie-break by most recently updated)
23800
23927
  const newestCreatedWorkspace = workspaces.length > 0
23801
23928
  ? [...workspaces].sort((a, b) => {
@@ -23821,7 +23948,7 @@ class KritzelCore {
23821
23948
  // Use last active workspace from localStorage
23822
23949
  activeWorkspace = lastActiveWorkspace;
23823
23950
  }
23824
- else if (newestCreatedWorkspace) {
23951
+ else if (newestCreatedWorkspace && !shouldCreateEditorScopedFallback) {
23825
23952
  // Use newest created workspace
23826
23953
  activeWorkspace = newestCreatedWorkspace;
23827
23954
  }
@@ -24386,7 +24513,7 @@ class KritzelCore {
24386
24513
  this._store.state.copiedObjectIdMapping = newIdMapping;
24387
24514
  }
24388
24515
  });
24389
- this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
24516
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24390
24517
  this.engine.emitObjectsChange();
24391
24518
  this.rerender();
24392
24519
  }
@@ -24575,7 +24702,7 @@ class KritzelCore {
24575
24702
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
24576
24703
  }
24577
24704
  this.addSelectionGroup(selectionGroup);
24578
- this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
24705
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24579
24706
  this.rerender();
24580
24707
  }
24581
24708
  }
@@ -24609,7 +24736,7 @@ class KritzelCore {
24609
24736
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
24610
24737
  }
24611
24738
  this.addSelectionGroup(selectionGroup);
24612
- this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
24739
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24613
24740
  this.rerender();
24614
24741
  }
24615
24742
  }
@@ -24765,7 +24892,7 @@ class KritzelCore {
24765
24892
  }
24766
24893
  this.resetActiveText();
24767
24894
  this.clearSelection();
24768
- this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
24895
+ this._store.setState('activeTool', this._toolRegistry.getTool('selection'));
24769
24896
  }
24770
24897
  /**
24771
24898
  * Determines whether to display the selection group UI for an object.
@@ -26453,11 +26580,22 @@ const KritzelEngine = class {
26453
26580
  * @returns The registered tool instance, or `null` if registration failed.
26454
26581
  */
26455
26582
  async registerTool(toolName, toolClass, toolConfig) {
26456
- if (typeof toolClass !== 'function' || !(toolClass.prototype instanceof KritzelBaseTool)) {
26583
+ if (typeof toolClass !== 'function') {
26457
26584
  console.error(`Failed to register tool "${toolName}": Tool class must be a constructor function`);
26458
26585
  return null;
26459
26586
  }
26460
- const registeredTool = KritzelToolRegistry.registerTool(toolName, toolClass, this.core);
26587
+ // If a tool with this name is already registered, return the existing instance
26588
+ // This avoids dual-package issues when tool classes are passed from external bundles
26589
+ if (this.core.toolRegistry.hasTool(toolName)) {
26590
+ const existingTool = this.core.toolRegistry.getTool(toolName);
26591
+ if (toolConfig) {
26592
+ Object.entries(toolConfig).forEach(([key, value]) => {
26593
+ existingTool[key] = value;
26594
+ });
26595
+ }
26596
+ return existingTool;
26597
+ }
26598
+ const registeredTool = this.core.toolRegistry.registerTool(toolName, toolClass);
26461
26599
  if (toolConfig) {
26462
26600
  Object.entries(toolConfig).forEach(([key, value]) => {
26463
26601
  registeredTool[key] = value;
@@ -26735,7 +26873,7 @@ const KritzelEngine = class {
26735
26873
  * @param objects - The objects to select.
26736
26874
  */
26737
26875
  async selectObjects(objects) {
26738
- const selectionTool = KritzelToolRegistry.getTool('selection');
26876
+ const selectionTool = this.core.toolRegistry.getTool('selection');
26739
26877
  if (!selectionTool) {
26740
26878
  return;
26741
26879
  }
@@ -26746,7 +26884,7 @@ const KritzelEngine = class {
26746
26884
  }
26747
26885
  /** Selects all objects currently visible in the viewport. Switches to the selection tool automatically. */
26748
26886
  async selectAllObjectsInViewport() {
26749
- const selectionTool = KritzelToolRegistry.getTool('selection');
26887
+ const selectionTool = this.core.toolRegistry.getTool('selection');
26750
26888
  if (!selectionTool) {
26751
26889
  return;
26752
26890
  }
@@ -28105,7 +28243,7 @@ const KritzelEngine = class {
28105
28243
  strokeWidth: data.indicatorStrokeWidth,
28106
28244
  } }))));
28107
28245
  })()), 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: {
28108
- position: 'fixed',
28246
+ position: 'absolute',
28109
28247
  left: `${this.core.store.state.contextMenuX}px`,
28110
28248
  top: `${this.core.store.state.contextMenuY}px`,
28111
28249
  zIndex: '10002',
@@ -28850,7 +28988,7 @@ const KritzelMenuItem = class {
28850
28988
  };
28851
28989
  KritzelMenuItem.style = kritzelMenuItemCss();
28852
28990
 
28853
- 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%))}`;
28991
+ 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%))}`;
28854
28992
 
28855
28993
  const KritzelMoreMenu = class {
28856
28994
  constructor(hostRef) {
@@ -29414,7 +29552,7 @@ const KritzelPortal = class {
29414
29552
  * This file is auto-generated by the version bump scripts.
29415
29553
  * Do not modify manually.
29416
29554
  */
29417
- const KRITZEL_VERSION = '0.3.1';
29555
+ const KRITZEL_VERSION = '0.3.7';
29418
29556
 
29419
29557
  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)}`;
29420
29558
 
@@ -29940,9 +30078,19 @@ const KritzelToolConfig = class {
29940
30078
  }
29941
30079
  isExpanded = false;
29942
30080
  theme;
30081
+ engine;
30082
+ handleSelectionChangeBound = this.handleSelectionChange.bind(this);
29943
30083
  onThemeChange() {
29944
30084
  this.emitDisplayValues();
29945
30085
  }
30086
+ handleEngineChange(newEngine, oldEngine) {
30087
+ if (oldEngine) {
30088
+ oldEngine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30089
+ }
30090
+ if (newEngine) {
30091
+ newEngine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30092
+ }
30093
+ }
29946
30094
  toolChange;
29947
30095
  displayValuesChange;
29948
30096
  config;
@@ -29959,6 +30107,11 @@ const KritzelToolConfig = class {
29959
30107
  }
29960
30108
  }
29961
30109
  }
30110
+ disconnectedCallback() {
30111
+ if (this.engine) {
30112
+ this.engine.removeEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30113
+ }
30114
+ }
29962
30115
  componentWillLoad() {
29963
30116
  this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
29964
30117
  if (this.config) {
@@ -29966,6 +30119,9 @@ const KritzelToolConfig = class {
29966
30119
  this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
29967
30120
  this.emitDisplayValues();
29968
30121
  }
30122
+ if (this.engine) {
30123
+ this.engine.addEventListener('objectsSelectionChange', this.handleSelectionChangeBound);
30124
+ }
29969
30125
  }
29970
30126
  emitDisplayValues() {
29971
30127
  if (!this.config)
@@ -30097,6 +30253,9 @@ const KritzelToolConfig = class {
30097
30253
  }],
30098
30254
  "theme": [{
30099
30255
  "onThemeChange": 0
30256
+ }],
30257
+ "engine": [{
30258
+ "handleEngineChange": 0
30100
30259
  }]
30101
30260
  }; }
30102
30261
  };
@@ -30257,7 +30416,7 @@ const KritzelTooltip = class {
30257
30416
  };
30258
30417
  KritzelTooltip.style = kritzelTooltipCss();
30259
30418
 
30260
- 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%))}`;
30419
+ 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%))}`;
30261
30420
 
30262
30421
  const KritzelUtilityPanel = class {
30263
30422
  constructor(hostRef) {