kritzel-stencil 0.0.162 → 0.0.164

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 (116) hide show
  1. package/dist/cjs/{default-line-tool.config-D1Ns0NmM.js → default-line-tool.config-DJMYrkSu.js} +340 -9
  2. package/dist/cjs/default-line-tool.config-DJMYrkSu.js.map +1 -0
  3. package/dist/cjs/index.cjs.js +1 -1
  4. package/dist/cjs/kritzel-color_22.cjs.entry.js +760 -27
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/stencil.cjs.js +1 -1
  7. package/dist/collection/classes/core/core.class.js +19 -3
  8. package/dist/collection/classes/core/core.class.js.map +1 -1
  9. package/dist/collection/classes/core/reviver.class.js +16 -0
  10. package/dist/collection/classes/core/reviver.class.js.map +1 -1
  11. package/dist/collection/classes/core/store.class.js +5 -0
  12. package/dist/collection/classes/core/store.class.js.map +1 -1
  13. package/dist/collection/classes/core/viewport.class.js +8 -0
  14. package/dist/collection/classes/core/viewport.class.js.map +1 -1
  15. package/dist/collection/classes/managers/anchor.manager.js +181 -3
  16. package/dist/collection/classes/managers/anchor.manager.js.map +1 -1
  17. package/dist/collection/classes/objects/path.class.js +85 -0
  18. package/dist/collection/classes/objects/path.class.js.map +1 -1
  19. package/dist/collection/classes/objects/shape.class.js +372 -0
  20. package/dist/collection/classes/objects/shape.class.js.map +1 -0
  21. package/dist/collection/classes/registries/icon-registry.class.js +4 -0
  22. package/dist/collection/classes/registries/icon-registry.class.js.map +1 -1
  23. package/dist/collection/classes/tools/brush-tool.class.js +2 -2
  24. package/dist/collection/classes/tools/brush-tool.class.js.map +1 -1
  25. package/dist/collection/classes/tools/line-tool.class.js +2 -2
  26. package/dist/collection/classes/tools/line-tool.class.js.map +1 -1
  27. package/dist/collection/classes/tools/shape-tool.class.js +204 -0
  28. package/dist/collection/classes/tools/shape-tool.class.js.map +1 -0
  29. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +17 -6
  30. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
  31. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +44 -8
  32. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -1
  33. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +143 -5
  34. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +76 -12
  35. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js.map +1 -1
  36. package/dist/collection/configs/default-shape-tool.config.js +26 -0
  37. package/dist/collection/configs/default-shape-tool.config.js.map +1 -0
  38. package/dist/collection/enums/shape-type.enum.js +7 -0
  39. package/dist/collection/enums/shape-type.enum.js.map +1 -0
  40. package/dist/collection/helpers/geometry.helper.js +55 -0
  41. package/dist/collection/helpers/geometry.helper.js.map +1 -1
  42. package/dist/collection/interfaces/toolbar-control.interface.js.map +1 -1
  43. package/dist/components/index.js +3 -3
  44. package/dist/components/kritzel-brush-style.js +1 -1
  45. package/dist/components/kritzel-context-menu.js +1 -1
  46. package/dist/components/kritzel-control-brush-config.js +1 -1
  47. package/dist/components/kritzel-control-text-config.js +1 -1
  48. package/dist/components/kritzel-controls.js +1 -1
  49. package/dist/components/kritzel-editor.js +49 -16
  50. package/dist/components/kritzel-editor.js.map +1 -1
  51. package/dist/components/kritzel-engine.js +1 -1
  52. package/dist/components/kritzel-icon.js +1 -1
  53. package/dist/components/kritzel-menu-item.js +1 -1
  54. package/dist/components/kritzel-menu.js +1 -1
  55. package/dist/components/kritzel-split-button.js +1 -1
  56. package/dist/components/kritzel-utility-panel.js +1 -1
  57. package/dist/components/kritzel-workspace-manager.js +1 -1
  58. package/dist/components/{p-Cqr0Bah5.js → p-5OECjGHq.js} +3 -3
  59. package/dist/components/{p-Cqr0Bah5.js.map → p-5OECjGHq.js.map} +1 -1
  60. package/dist/components/{p-CvLFRlQU.js → p-BSBMBjhq.js} +3 -3
  61. package/dist/components/{p-CvLFRlQU.js.map → p-BSBMBjhq.js.map} +1 -1
  62. package/dist/components/{p-7_lwv0zQ.js → p-BuS7MM1j.js} +4 -4
  63. package/dist/components/{p-7_lwv0zQ.js.map → p-BuS7MM1j.js.map} +1 -1
  64. package/dist/components/{p-BixlbUD7.js → p-Cv4BGNPb.js} +6 -2
  65. package/dist/components/p-Cv4BGNPb.js.map +1 -0
  66. package/dist/components/{p-dMCB4tJA.js → p-D1YAsWrL.js} +3 -3
  67. package/dist/components/{p-dMCB4tJA.js.map → p-D1YAsWrL.js.map} +1 -1
  68. package/dist/components/{p-CDteBYm9.js → p-D8L0t-Ro.js} +3 -3
  69. package/dist/components/{p-CDteBYm9.js.map → p-D8L0t-Ro.js.map} +1 -1
  70. package/dist/components/{p-DZ7kxJUx.js → p-DguzZn_x.js} +3 -3
  71. package/dist/components/{p-DZ7kxJUx.js.map → p-DguzZn_x.js.map} +1 -1
  72. package/dist/components/{p-sokRZ7Vn.js → p-Dz2XHHqa.js} +145 -5
  73. package/dist/components/p-Dz2XHHqa.js.map +1 -0
  74. package/dist/components/{p-CuhOrcET.js → p-DzUUppVL.js} +837 -21
  75. package/dist/components/p-DzUUppVL.js.map +1 -0
  76. package/dist/components/{p-CkD1PQQX.js → p-I3iPEDpx.js} +5 -5
  77. package/dist/components/{p-CkD1PQQX.js.map → p-I3iPEDpx.js.map} +1 -1
  78. package/dist/components/{p-DKwJJuFb.js → p-tp96UZ0l.js} +83 -19
  79. package/dist/components/p-tp96UZ0l.js.map +1 -0
  80. package/dist/esm/{default-line-tool.config-C35m-d1Y.js → default-line-tool.config-C35P3XfD.js} +332 -10
  81. package/dist/esm/default-line-tool.config-C35P3XfD.js.map +1 -0
  82. package/dist/esm/index.js +2 -2
  83. package/dist/esm/kritzel-color_22.entry.js +760 -27
  84. package/dist/esm/loader.js +1 -1
  85. package/dist/esm/stencil.js +1 -1
  86. package/dist/stencil/index.esm.js +1 -1
  87. package/dist/stencil/p-3e2b5c42.entry.js +10 -0
  88. package/dist/stencil/p-3e2b5c42.entry.js.map +1 -0
  89. package/dist/stencil/p-C35P3XfD.js +2 -0
  90. package/dist/stencil/p-C35P3XfD.js.map +1 -0
  91. package/dist/stencil/stencil.esm.js +1 -1
  92. package/dist/types/classes/core/core.class.d.ts +1 -0
  93. package/dist/types/classes/core/store.class.d.ts +2 -0
  94. package/dist/types/classes/core/viewport.class.d.ts +6 -0
  95. package/dist/types/classes/managers/anchor.manager.d.ts +20 -0
  96. package/dist/types/classes/objects/path.class.d.ts +7 -0
  97. package/dist/types/classes/objects/shape.class.d.ts +116 -0
  98. package/dist/types/classes/tools/shape-tool.class.d.ts +37 -0
  99. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -2
  100. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +16 -1
  101. package/dist/types/components.d.ts +5 -5
  102. package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
  103. package/dist/types/enums/shape-type.enum.d.ts +5 -0
  104. package/dist/types/helpers/geometry.helper.d.ts +21 -0
  105. package/dist/types/interfaces/toolbar-control.interface.d.ts +21 -3
  106. package/package.json +1 -1
  107. package/dist/cjs/default-line-tool.config-D1Ns0NmM.js.map +0 -1
  108. package/dist/components/p-BixlbUD7.js.map +0 -1
  109. package/dist/components/p-CuhOrcET.js.map +0 -1
  110. package/dist/components/p-DKwJJuFb.js.map +0 -1
  111. package/dist/components/p-sokRZ7Vn.js.map +0 -1
  112. package/dist/esm/default-line-tool.config-C35m-d1Y.js.map +0 -1
  113. package/dist/stencil/p-C35m-d1Y.js +0 -2
  114. package/dist/stencil/p-C35m-d1Y.js.map +0 -1
  115. package/dist/stencil/p-d142ef46.entry.js +0 -10
  116. package/dist/stencil/p-d142ef46.entry.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-Cj__YTlG.js');
4
- var defaultLineTool_config = require('./default-line-tool.config-D1Ns0NmM.js');
4
+ var defaultLineTool_config = require('./default-line-tool.config-DJMYrkSu.js');
5
5
 
6
6
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
7
7
 
@@ -249,7 +249,7 @@ const KritzelControlTextConfig = class {
249
249
  };
250
250
  KritzelControlTextConfig.style = kritzelControlTextConfigCss;
251
251
 
252
- const kritzelControlsCss = ":host{display:flex;flex-direction:column;user-select:none}: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}.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-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-divider{width:var(--kritzel-controls-divider-width, 1px);height:var(--kritzel-controls-divider-height, 24px);background-color:var(--kritzel-controls-divider-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;width:40px;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-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-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-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{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);z-index:10001}";
252
+ const kritzelControlsCss = ":host{display:flex;flex-direction:column;user-select:none}: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}.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-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-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-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-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{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);display:flex;flex-direction:column;background:var(--kritzel-controls-background-color, #ffffff);border-radius:12px;padding:6px;box-shadow:0 4px 12px rgba(0, 0, 0, 0.15);border:1px solid #ebebeb;z-index:10001;min-width:140px}.kritzel-submenu-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:none;background:none;cursor:var(--kritzel-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;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}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-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-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-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{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);z-index:10001}";
253
253
 
254
254
  const KritzelControls = class {
255
255
  constructor(hostRef) {
@@ -265,17 +265,24 @@ const KritzelControls = class {
265
265
  firstConfig = null;
266
266
  isTooltipVisible = false;
267
267
  isTouchDevice = defaultLineTool_config.KritzelDevicesHelper.isTouchDevice();
268
+ selectedSubOptions = new Map();
269
+ openSubMenuControl = null;
268
270
  handleDocumentClick(event) {
269
271
  const element = event.target;
270
272
  if (!this.kritzelEngine || element.closest('.kritzel-tooltip')) {
271
273
  return;
272
274
  }
273
275
  this.isTooltipVisible = false;
276
+ // Close submenu when clicking outside
277
+ if (!element.closest('.kritzel-control-split') && !element.closest('.kritzel-submenu')) {
278
+ this.openSubMenuControl = null;
279
+ }
274
280
  }
275
281
  handleKeyDown(event) {
276
282
  if (event.key === 'Escape') {
277
283
  event.preventDefault();
278
284
  this.closeTooltip();
285
+ this.openSubMenuControl = null;
279
286
  this.kritzelEngine?.enable();
280
287
  }
281
288
  }
@@ -351,36 +358,91 @@ const KritzelControls = class {
351
358
  this.isTooltipVisible = false;
352
359
  this.kritzelEngine?.enable();
353
360
  }
361
+ /**
362
+ * Get the currently selected sub-option for a control.
363
+ * Returns the first sub-option as default if none is selected.
364
+ */
365
+ getSelectedSubOption(control) {
366
+ if (!control.subOptions?.length)
367
+ return undefined;
368
+ return this.selectedSubOptions.get(control.name) || control.subOptions[0];
369
+ }
370
+ /**
371
+ * Toggle the submenu for a split-button control
372
+ */
373
+ toggleSubMenu(event, control) {
374
+ event.stopPropagation();
375
+ if (this.openSubMenuControl?.name === control.name) {
376
+ this.openSubMenuControl = null;
377
+ }
378
+ else {
379
+ this.openSubMenuControl = control;
380
+ }
381
+ }
382
+ /**
383
+ * Select a sub-option and update the tool property
384
+ */
385
+ async selectSubOption(control, option) {
386
+ // Update the selected sub-options map (create new Map for reactivity)
387
+ const newMap = new Map(this.selectedSubOptions);
388
+ newMap.set(control.name, option);
389
+ this.selectedSubOptions = newMap;
390
+ // Update the tool property if the tool is instantiated
391
+ if (control.tool && typeof control.tool !== 'function') {
392
+ control.tool[option.toolProperty] = option.value;
393
+ }
394
+ // Close the submenu
395
+ this.openSubMenuControl = null;
396
+ // Activate this control
397
+ await this.handleControlClick(control);
398
+ }
354
399
  render() {
355
- const hasNoConfig = this.activeControl?.config === undefined || this.activeControl?.config === null;
356
- return (index.h(index.Host, { key: 'c01351cbf438f2e36249b2ef3ef8725edcabd57b', class: {
400
+ const hasConfigUI = this.activeControl?.tool instanceof defaultLineTool_config.KritzelBrushTool ||
401
+ this.activeControl?.tool instanceof defaultLineTool_config.KritzelTextTool;
402
+ return (index.h(index.Host, { key: '34a8a81224f1714a30a0d6e03fb81ed031fe36a0', class: {
357
403
  mobile: this.isTouchDevice,
358
- } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '3c14cf25dd51f123dc8d33be92992e2f2c18ac40', style: {
404
+ } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '8ddfe7b4872d59b08b0561dbd61c67b9c245dcc9', style: {
359
405
  position: 'absolute',
360
406
  bottom: '56px',
361
407
  left: '12px',
362
- }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '05719acfe12d1770bf49fb7d9989619f2e27ee0f', class: "kritzel-controls" }, this.controls.map(control => {
408
+ }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '370229830b9a6c0ae5704d9fb0ce35d130fcf049', class: "kritzel-controls" }, this.controls.map(control => {
363
409
  if (control.type === 'tool') {
410
+ // Check if this control has sub-options (split-button)
411
+ if (control.subOptions?.length) {
412
+ const selectedSubOption = this.getSelectedSubOption(control);
413
+ const isActive = this.activeControl?.name === control.name;
414
+ const isSubMenuOpen = this.openSubMenuControl?.name === control.name;
415
+ return (index.h("div", { class: {
416
+ 'kritzel-control-split': true,
417
+ 'selected': isActive,
418
+ }, key: control.name }, index.h("button", { class: "kritzel-control-main", onClick: () => this.handleControlClick(control), title: selectedSubOption?.label }, index.h("kritzel-icon", { name: selectedSubOption?.icon || control.icon })), index.h("button", { class: {
419
+ 'kritzel-control-dropdown': true,
420
+ 'visible': isActive,
421
+ }, onClick: (e) => this.toggleSubMenu(e, control), "aria-label": "Select shape type", "aria-expanded": isSubMenuOpen ? 'true' : 'false', tabIndex: isActive ? 0 : -1 }, index.h("kritzel-icon", { name: "chevron-down", size: 12 })), isSubMenuOpen && (index.h("div", { class: "kritzel-submenu" }, control.subOptions.map(option => (index.h("button", { class: {
422
+ 'kritzel-submenu-item': true,
423
+ 'active': option.id === selectedSubOption?.id,
424
+ }, key: option.id, onClick: () => this.selectSubOption(control, option) }, index.h("kritzel-icon", { name: option.icon, size: 20 }), index.h("span", null, option.label))))))));
425
+ }
426
+ // Regular tool control (no sub-options)
364
427
  return (index.h("button", { class: {
365
428
  'kritzel-control': true,
366
429
  'selected': this.activeControl?.name === control?.name,
367
430
  }, key: control.name, onClick: _event => this.handleControlClick?.(control) }, index.h("kritzel-icon", { name: control.icon })));
368
431
  }
369
- if (control.type === 'divider') {
370
- return index.h("div", { class: "kritzel-divider", key: control.name });
371
- }
372
432
  if (control.type === 'config' && control.name === this.firstConfig?.name && this.activeControl) {
373
- return (index.h("div", { class: "kritzel-config-container", key: control.name }, index.h("kritzel-tooltip", { ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, index.h("div", { style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (index.h("kritzel-control-brush-config", { tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (index.h("kritzel-control-text-config", { tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), index.h("div", { tabIndex: 0, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
433
+ return (index.h("div", { class: {
434
+ 'kritzel-config-container': true,
435
+ 'visible': hasConfigUI,
436
+ }, key: control.name }, index.h("kritzel-tooltip", { ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, index.h("div", { style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (index.h("kritzel-control-brush-config", { tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (index.h("kritzel-control-text-config", { tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), index.h("div", { tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
374
437
  if (event.key === 'Enter') {
375
438
  this.handleConfigClick?.(event);
376
439
  }
377
440
  }, style: {
378
- cursor: this.activeControl.config ? 'pointer' : 'default',
379
- pointerEvents: hasNoConfig ? 'none' : 'auto',
441
+ cursor: 'pointer',
380
442
  } }, this.activeControl.tool instanceof defaultLineTool_config.KritzelBrushTool && (index.h("div", { class: "color-container" }, index.h("kritzel-color", { value: this.activeToolAsBrushTool?.color, size: this.activeToolAsBrushTool?.size, style: {
381
443
  borderRadius: '50%',
382
444
  border: 'none',
383
- } }))), this.activeControl.tool instanceof defaultLineTool_config.KritzelTextTool && (index.h("div", { class: "font-container" }, index.h("kritzel-font", { fontFamily: this.activeToolAsTextTool?.fontFamily, size: this.activeToolAsTextTool?.fontSize, color: this.activeToolAsTextTool?.fontColor }))), hasNoConfig && index.h("div", { class: "no-config" }))));
445
+ } }))), this.activeControl.tool instanceof defaultLineTool_config.KritzelTextTool && (index.h("div", { class: "font-container" }, index.h("kritzel-font", { fontFamily: this.activeToolAsTextTool?.fontFamily, size: this.activeToolAsTextTool?.fontSize, color: this.activeToolAsTextTool?.fontColor }))))));
384
446
  }
385
447
  }))));
386
448
  }
@@ -575,6 +637,596 @@ const KritzelDropdown = class {
575
637
  };
576
638
  KritzelDropdown.style = kritzelDropdownCss;
577
639
 
640
+ var ShapeType;
641
+ (function (ShapeType) {
642
+ ShapeType["Rectangle"] = "rectangle";
643
+ ShapeType["Ellipse"] = "ellipse";
644
+ ShapeType["Triangle"] = "triangle";
645
+ })(ShapeType || (ShapeType = {}));
646
+
647
+ class KritzelShape extends defaultLineTool_config.KritzelBaseObject {
648
+ __class__ = 'KritzelShape';
649
+ shapeType = ShapeType.Rectangle;
650
+ fillColor = 'transparent';
651
+ strokeColor = '#000000';
652
+ strokeWidth = 4;
653
+ fontFamily = 'Arial';
654
+ fontSize = 16;
655
+ fontColor = '#000000';
656
+ /** Screen-space x coordinate of the shape's top-left corner (like Path.x) */
657
+ x = 0;
658
+ /** Screen-space y coordinate of the shape's top-left corner (like Path.y) */
659
+ y = 0;
660
+ scale = 1;
661
+ scaleFactor = 1;
662
+ isDebugInfoVisible = true;
663
+ isEditable = true;
664
+ isEditing = false;
665
+ editor = null;
666
+ content = null;
667
+ _schema = new defaultLineTool_config.Schema({
668
+ nodes: defaultLineTool_config.addListNodes(defaultLineTool_config.schema.spec.nodes, 'paragraph block*', 'block'),
669
+ marks: defaultLineTool_config.schema.spec.marks,
670
+ });
671
+ uneditedObject = null;
672
+ /**
673
+ * Returns the viewBox for the shape's SVG, using screen-space coordinates.
674
+ * This follows the same pattern as KritzelPath.viewBox.
675
+ */
676
+ get viewBox() {
677
+ return `${this.x} ${this.y} ${this.width} ${this.height}`;
678
+ }
679
+ constructor(config) {
680
+ super();
681
+ if (config) {
682
+ this.x = config.x ?? 0;
683
+ this.y = config.y ?? 0;
684
+ this.translateX = config.translateX ?? 0;
685
+ this.translateY = config.translateY ?? 0;
686
+ this.width = config.width ?? 100;
687
+ this.height = config.height ?? 100;
688
+ this.shapeType = config.shapeType ?? ShapeType.Rectangle;
689
+ this.fillColor = config.fillColor ?? 'transparent';
690
+ this.strokeColor = config.strokeColor ?? '#000000';
691
+ this.strokeWidth = config.strokeWidth ?? 4;
692
+ this.fontSize = config.fontSize ?? 16;
693
+ this.fontFamily = config.fontFamily ?? 'Arial';
694
+ this.fontColor = config.fontColor ?? '#000000';
695
+ this.scale = config.scale ?? 1;
696
+ this.scaleFactor = config.scaleX ?? 1;
697
+ }
698
+ }
699
+ /**
700
+ * Creates a new KritzelShape with screen-space coordinates.
701
+ * Following the same pattern as KritzelPath.create():
702
+ * - x, y are screen-space coordinates of the shape's top-left corner
703
+ * - translateX, translateY should be set to -viewportTranslateX, -viewportTranslateY
704
+ * - width, height are in screen-space
705
+ * - scale is the viewport scale at creation time
706
+ */
707
+ static create(core, config) {
708
+ const object = new KritzelShape();
709
+ object._core = core;
710
+ object.id = object.generateId();
711
+ object.workspaceId = core.store.state.activeWorkspace.id;
712
+ object.x = config?.x ?? 0;
713
+ object.y = config?.y ?? 0;
714
+ object.translateX = config?.translateX ?? 0;
715
+ object.translateY = config?.translateY ?? 0;
716
+ object.width = config?.width ?? 100;
717
+ object.height = config?.height ?? 100;
718
+ object.shapeType = config?.shapeType ?? ShapeType.Rectangle;
719
+ object.fillColor = config?.fillColor ?? 'transparent';
720
+ object.strokeColor = config?.strokeColor ?? '#000000';
721
+ object.strokeWidth = config?.strokeWidth ?? 4;
722
+ object.fontSize = config?.fontSize ?? 16;
723
+ object.fontFamily = config?.fontFamily ?? 'Arial';
724
+ object.fontColor = config?.fontColor ?? '#000000';
725
+ object.backgroundColor = 'transparent';
726
+ object.scaleFactor = 1;
727
+ object.scale = core.store.state.scale;
728
+ object.zIndex = core.store.currentZIndex;
729
+ object.editor = object.createEditor();
730
+ // Compute world-space translateX/Y from screen-space coordinates
731
+ // This follows the same pattern as KritzelPath.updateDimensions()
732
+ object.updateDimensions();
733
+ return object;
734
+ }
735
+ /**
736
+ * Updates the translateX/Y to world coordinates based on screen-space x, y.
737
+ * This follows the same pattern as KritzelPath.updateDimensions().
738
+ *
739
+ * The formula: translateX = (x + initialTranslateX) / scale
740
+ * where initialTranslateX was -viewportTranslateX
741
+ *
742
+ * This converts screen-space position to world coordinates.
743
+ */
744
+ updateDimensions() {
745
+ this.translateX = (this.x + this.translateX) / this.scale;
746
+ this.translateY = (this.y + this.translateY) / this.scale;
747
+ }
748
+ mount(element) {
749
+ if (element === null || this.isInViewport() === false) {
750
+ return;
751
+ }
752
+ if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
753
+ return;
754
+ }
755
+ this.elementRef = element;
756
+ this.isMounted = true;
757
+ }
758
+ mountTextEditor(element) {
759
+ if (element === null) {
760
+ return;
761
+ }
762
+ if (this.editor.dom.parentElement === element) {
763
+ return;
764
+ }
765
+ element.style.fontFamily = this.fontFamily;
766
+ element.style.fontSize = `${this.fontSize}pt`;
767
+ element.style.color = this.fontColor;
768
+ element.style.whiteSpace = 'pre-wrap';
769
+ element.style.wordWrap = 'break-word';
770
+ element.innerHTML = '';
771
+ element.appendChild(this.editor.dom);
772
+ }
773
+ createEditor() {
774
+ const doc = this._schema.node('doc', null, [this._schema.node('paragraph')]);
775
+ return new defaultLineTool_config.EditorView(null, {
776
+ state: defaultLineTool_config.EditorState.create({
777
+ doc: doc,
778
+ plugins: [defaultLineTool_config.keymap(defaultLineTool_config.baseKeymap)],
779
+ }),
780
+ editable: () => false,
781
+ dispatchTransaction: transaction => {
782
+ const newState = this.editor.state.apply(transaction);
783
+ this.editor.updateState(newState);
784
+ if (transaction.docChanged) {
785
+ this.content = newState.doc.toJSON();
786
+ if (!transaction.getMeta('fromRemote')) {
787
+ this._core.store.state.objects.update(this, { temporary: true });
788
+ }
789
+ }
790
+ },
791
+ });
792
+ }
793
+ setContent(content) {
794
+ this.content = content;
795
+ if (this.editor && content) {
796
+ const newDoc = this.editor.state.schema.nodeFromJSON(content);
797
+ const tr = this.editor.state.tr.replaceWith(0, this.editor.state.doc.content.size, newDoc.content);
798
+ tr.setMeta('fromRemote', true);
799
+ this.editor.dispatch(tr);
800
+ }
801
+ }
802
+ resize(x, y, width, height) {
803
+ if (width <= 1 || height <= 1) {
804
+ return;
805
+ }
806
+ this.width = width;
807
+ this.height = height;
808
+ this.translateX = x;
809
+ this.translateY = y;
810
+ this._core.store.state.objects.update(this);
811
+ }
812
+ focus(coords) {
813
+ if (this.editor) {
814
+ const doc = this.editor.state.doc;
815
+ if (coords?.x && coords?.y) {
816
+ const pos = this.editor.posAtCoords({ left: coords.x, top: coords.y });
817
+ if (pos) {
818
+ this.editor.dispatch(this.editor.state.tr.setSelection(defaultLineTool_config.TextSelection.create(doc, pos.pos)));
819
+ this.editor.focus();
820
+ if (defaultLineTool_config.KritzelDevicesHelper.isIOS()) {
821
+ this.scrollIntoViewOnIOS();
822
+ }
823
+ return;
824
+ }
825
+ }
826
+ const end = Math.max(1, doc.content.size - 1);
827
+ this.editor.dispatch(this.editor.state.tr.setSelection(defaultLineTool_config.TextSelection.create(doc, end)));
828
+ this.editor.focus();
829
+ if (defaultLineTool_config.KritzelDevicesHelper.isIOS()) {
830
+ this.scrollIntoViewOnIOS();
831
+ }
832
+ }
833
+ }
834
+ scrollIntoViewOnIOS() {
835
+ setTimeout(() => {
836
+ if (this.editor && this.editor.dom) {
837
+ this.editor.dom.scrollIntoView({
838
+ behavior: 'smooth',
839
+ block: 'center',
840
+ inline: 'nearest',
841
+ });
842
+ }
843
+ }, 300);
844
+ }
845
+ edit(event) {
846
+ defaultLineTool_config.KritzelKeyboardHelper.disableInteractiveWidget();
847
+ this.uneditedObject = this.clone();
848
+ this._core.store.setState('activeTool', defaultLineTool_config.KritzelToolRegistry.getTool('shape'));
849
+ this.editor.setProps({ editable: () => true });
850
+ this.isEditing = true;
851
+ this._core.rerender();
852
+ this.focus({ x: event?.clientX, y: event?.clientY });
853
+ defaultLineTool_config.KritzelKeyboardHelper.enableInteractiveWidget();
854
+ }
855
+ save() {
856
+ this.content = this.editor.state.doc.toJSON();
857
+ this.editor.setProps({ editable: () => false });
858
+ this.editor.dom.blur();
859
+ this.isEditing = false;
860
+ this._core.store.state.objects.consolidateTemporaryItems();
861
+ this._core.store.state.objects.update(this);
862
+ this._core.engine.emitObjectsChange();
863
+ }
864
+ handlePointerDown(event) {
865
+ if (!this.isEditing) {
866
+ return;
867
+ }
868
+ event.stopPropagation();
869
+ }
870
+ handlePointerMove(event) {
871
+ if (!this.isEditing) {
872
+ return;
873
+ }
874
+ event.stopPropagation();
875
+ }
876
+ handlePointerUp(event) {
877
+ if (!this.isEditing) {
878
+ return;
879
+ }
880
+ event.stopPropagation();
881
+ }
882
+ copy() {
883
+ const copiedObject = super.copy();
884
+ copiedObject.editor = copiedObject.createEditor();
885
+ if (this.content) {
886
+ copiedObject.setContent(this.content);
887
+ }
888
+ return copiedObject;
889
+ }
890
+ serialize() {
891
+ const { _core, _elementRef, _schema, element, totalWidth, totalHeight, editor, uneditedObject, ...remainingProps } = this;
892
+ const clonedProps = structuredClone(remainingProps);
893
+ if (element && typeof element === 'object' && 'nodeType' in element && element.nodeType === 1) {
894
+ clonedProps.element = element.cloneNode(true);
895
+ }
896
+ return clonedProps;
897
+ }
898
+ deserialize(object) {
899
+ super.deserialize(object);
900
+ if (object.content) {
901
+ this.setContent(object.content);
902
+ }
903
+ return this;
904
+ }
905
+ /**
906
+ * Returns the clipping polygon for arrow intersection.
907
+ * For ellipse: returns a many-sided polygon approximation
908
+ * For triangle: returns the 3 corners
909
+ * For rectangle: returns null (uses default rotatedPolygon)
910
+ *
911
+ * Includes padding for half the stroke width so arrow heads don't overlap the stroke.
912
+ */
913
+ getClipPolygon() {
914
+ // Calculate world-space center and dimensions
915
+ const worldWidth = this.totalWidth / this.scale;
916
+ const worldHeight = this.totalHeight / this.scale;
917
+ const centerX = this.translateX + worldWidth / 2;
918
+ const centerY = this.translateY + worldHeight / 2;
919
+ // Add padding for stroke width so arrows don't overlap the stroke
920
+ const strokePadding = (this.strokeWidth / this.scale) / 2;
921
+ switch (this.shapeType) {
922
+ case ShapeType.Ellipse:
923
+ // Return a 32-segment polygon approximation of the ellipse
924
+ // Add stroke padding to radii
925
+ return defaultLineTool_config.KritzelGeometryHelper.getEllipsePolygonApproximation(centerX, centerY, worldWidth / 2 + strokePadding, worldHeight / 2 + strokePadding, 32, this.rotation);
926
+ case ShapeType.Triangle:
927
+ // Return the 3 corners of the triangle in world coordinates
928
+ // Triangle: top-center, bottom-right, bottom-left
929
+ // Expand each vertex outward from center by strokePadding
930
+ const expandVertex = (vx, vy) => {
931
+ const dx = vx - centerX;
932
+ const dy = vy - centerY;
933
+ const dist = Math.sqrt(dx * dx + dy * dy);
934
+ if (dist === 0)
935
+ return { x: vx, y: vy };
936
+ const scale = (dist + strokePadding) / dist;
937
+ return {
938
+ x: centerX + dx * scale,
939
+ y: centerY + dy * scale
940
+ };
941
+ };
942
+ const topX = this.translateX + worldWidth / 2;
943
+ const topY = this.translateY;
944
+ const bottomLeftX = this.translateX;
945
+ const bottomLeftY = this.translateY + worldHeight;
946
+ const bottomRightX = this.translateX + worldWidth;
947
+ const bottomRightY = this.translateY + worldHeight;
948
+ const expandedTop = expandVertex(topX, topY);
949
+ const expandedBottomRight = expandVertex(bottomRightX, bottomRightY);
950
+ const expandedBottomLeft = expandVertex(bottomLeftX, bottomLeftY);
951
+ // Apply rotation around center if rotated
952
+ if (this.rotation !== 0) {
953
+ const cos = Math.cos(this.rotation);
954
+ const sin = Math.sin(this.rotation);
955
+ const rotate = (p) => {
956
+ const dx = p.x - centerX;
957
+ const dy = p.y - centerY;
958
+ return {
959
+ x: centerX + dx * cos - dy * sin,
960
+ y: centerY + dx * sin + dy * cos
961
+ };
962
+ };
963
+ return [
964
+ rotate(expandedTop),
965
+ rotate(expandedBottomRight),
966
+ rotate(expandedBottomLeft)
967
+ ];
968
+ }
969
+ return [expandedTop, expandedBottomRight, expandedBottomLeft];
970
+ case ShapeType.Rectangle:
971
+ default:
972
+ // For rectangles, return null to use the default rotatedPolygon
973
+ return null;
974
+ }
975
+ }
976
+ /**
977
+ * Returns the SVG path for rendering the shape.
978
+ * The path uses screen-space coordinates relative to (x, y).
979
+ */
980
+ getSvgPath() {
981
+ const w = this.width;
982
+ const h = this.height;
983
+ switch (this.shapeType) {
984
+ case ShapeType.Rectangle:
985
+ return `M ${this.x} ${this.y} L ${this.x + w} ${this.y} L ${this.x + w} ${this.y + h} L ${this.x} ${this.y + h} Z`;
986
+ case ShapeType.Ellipse:
987
+ const cx = this.x + w / 2;
988
+ const cy = this.y + h / 2;
989
+ const rx = w / 2;
990
+ const ry = h / 2;
991
+ return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy}`;
992
+ case ShapeType.Triangle:
993
+ const topX = this.x + w / 2;
994
+ const topY = this.y;
995
+ const bottomLeftX = this.x;
996
+ const bottomLeftY = this.y + h;
997
+ const bottomRightX = this.x + w;
998
+ const bottomRightY = this.y + h;
999
+ return `M ${topX} ${topY} L ${bottomRightX} ${bottomRightY} L ${bottomLeftX} ${bottomLeftY} Z`;
1000
+ default:
1001
+ return `M ${this.x} ${this.y} L ${this.x + w} ${this.y} L ${this.x + w} ${this.y + h} L ${this.x} ${this.y + h} Z`;
1002
+ }
1003
+ }
1004
+ }
1005
+
1006
+ class KritzelShapeTool extends defaultLineTool_config.KritzelBaseTool {
1007
+ shapeType = ShapeType.Rectangle;
1008
+ fillColor = 'transparent';
1009
+ strokeColor = '#000000';
1010
+ strokeWidth = 4;
1011
+ fontFamily = 'Arial';
1012
+ fontSize = 16;
1013
+ fontColor = '#000000';
1014
+ palette = [
1015
+ '#000000',
1016
+ '#FFFFFF',
1017
+ '#FF0000',
1018
+ '#00FF00',
1019
+ '#0000FF',
1020
+ '#FFFF00',
1021
+ '#FF00FF',
1022
+ '#00FFFF',
1023
+ '#808080',
1024
+ '#C0C0C0',
1025
+ '#800000',
1026
+ '#008000',
1027
+ '#000080',
1028
+ '#808000',
1029
+ '#800080',
1030
+ ];
1031
+ startX = 0;
1032
+ startY = 0;
1033
+ isDrawing = false;
1034
+ currentShape = null;
1035
+ constructor(core) {
1036
+ super(core);
1037
+ }
1038
+ handlePointerDown(event) {
1039
+ if (event.cancelable) {
1040
+ event.preventDefault();
1041
+ }
1042
+ if (event.pointerType === 'mouse') {
1043
+ const path = event.composedPath().slice(1);
1044
+ const objectElement = path.find(element => element.classList && element.classList.contains('object'));
1045
+ const object = this._core.findObjectById(objectElement?.id);
1046
+ const activeShape = this._core.store.activeShape;
1047
+ if (activeShape === null && object instanceof KritzelShape) {
1048
+ object.edit(event);
1049
+ return;
1050
+ }
1051
+ if (activeShape !== null && object instanceof KritzelShape) {
1052
+ activeShape.save();
1053
+ object.edit(event);
1054
+ return;
1055
+ }
1056
+ if (activeShape !== null && object instanceof KritzelShape === false) {
1057
+ this._core.resetActiveShape();
1058
+ this._core.store.setState('activeTool', defaultLineTool_config.KritzelToolRegistry.getTool('selection'));
1059
+ return;
1060
+ }
1061
+ if (defaultLineTool_config.KritzelEventHelper.isLeftClick(event) === false) {
1062
+ return;
1063
+ }
1064
+ this.startDrawing(event.clientX, event.clientY);
1065
+ }
1066
+ if (event.pointerType === 'touch') {
1067
+ const activePointers = Array.from(this._core.store.state.pointers.values());
1068
+ const path = event.composedPath().slice(1);
1069
+ const objectElement = path.find(element => element.classList && element.classList.contains('object'));
1070
+ const object = this._core.findObjectById(objectElement?.id);
1071
+ const activeShape = this._core.store.activeShape;
1072
+ if (activeShape === null && object instanceof KritzelShape) {
1073
+ object.edit(event);
1074
+ return;
1075
+ }
1076
+ if (activeShape !== null && object instanceof KritzelShape) {
1077
+ activeShape.save();
1078
+ object.edit(event);
1079
+ return;
1080
+ }
1081
+ if (activeShape !== null && object instanceof KritzelShape === false) {
1082
+ this._core.resetActiveShape();
1083
+ this._core.store.setState('activeTool', defaultLineTool_config.KritzelToolRegistry.getTool('selection'));
1084
+ return;
1085
+ }
1086
+ if (activePointers.length > 1) {
1087
+ return;
1088
+ }
1089
+ const clientX = Math.round(activePointers[0].clientX);
1090
+ const clientY = Math.round(activePointers[0].clientY);
1091
+ this.startDrawing(clientX, clientY);
1092
+ }
1093
+ }
1094
+ handlePointerMove(event) {
1095
+ if (event.cancelable) {
1096
+ event.preventDefault();
1097
+ }
1098
+ if (!this.isDrawing || !this.currentShape) {
1099
+ return;
1100
+ }
1101
+ if (event.pointerType === 'mouse') {
1102
+ this.updateShapeSize(event.clientX, event.clientY);
1103
+ }
1104
+ if (event.pointerType === 'touch') {
1105
+ const activePointers = Array.from(this._core.store.state.pointers.values());
1106
+ if (activePointers.length === 1) {
1107
+ const clientX = Math.round(activePointers[0].clientX);
1108
+ const clientY = Math.round(activePointers[0].clientY);
1109
+ this.updateShapeSize(clientX, clientY);
1110
+ }
1111
+ }
1112
+ }
1113
+ handlePointerUp(event) {
1114
+ if (event.cancelable) {
1115
+ event.preventDefault();
1116
+ }
1117
+ if (!this.isDrawing || !this.currentShape) {
1118
+ return;
1119
+ }
1120
+ this.finishDrawing();
1121
+ }
1122
+ /**
1123
+ * Start drawing a shape. Following the same pattern as LineTool/BrushTool:
1124
+ * - Store screen coordinates for startX, startY
1125
+ * - Set translateX/Y to -viewportTranslateX/Y (viewport offset)
1126
+ * - Set x, y to the actual screen position
1127
+ * - Let updateDimensions() convert to world coordinates
1128
+ */
1129
+ startDrawing(clientX, clientY) {
1130
+ // Store screen coordinates (relative to host element)
1131
+ this.startX = clientX - this._core.store.offsetX;
1132
+ this.startY = clientY - this._core.store.offsetY;
1133
+ this.isDrawing = true;
1134
+ // Create shape using screen coordinates, following Path/Line pattern
1135
+ this.currentShape = KritzelShape.create(this._core, {
1136
+ x: this.startX,
1137
+ y: this.startY,
1138
+ translateX: -this._core.store.state.translateX,
1139
+ translateY: -this._core.store.state.translateY,
1140
+ width: 1,
1141
+ height: 1,
1142
+ shapeType: this.shapeType,
1143
+ fillColor: this.fillColor,
1144
+ strokeColor: this.strokeColor,
1145
+ strokeWidth: this.strokeWidth,
1146
+ fontSize: this.fontSize,
1147
+ fontFamily: this.fontFamily,
1148
+ fontColor: this.fontColor,
1149
+ });
1150
+ this._core.store.state.objects.insert(this.currentShape);
1151
+ this._core.rerender();
1152
+ }
1153
+ /**
1154
+ * Update shape size during drawing. Following the same pattern as LineTool:
1155
+ * - Use screen coordinates directly
1156
+ * - The shape's x, y, width, height are all in screen space
1157
+ * - updateDimensions() handles conversion to world coordinates
1158
+ */
1159
+ updateShapeSize(clientX, clientY) {
1160
+ if (!this.currentShape) {
1161
+ return;
1162
+ }
1163
+ const currentX = clientX - this._core.store.offsetX;
1164
+ const currentY = clientY - this._core.store.offsetY;
1165
+ // Calculate bounding box in screen coordinates
1166
+ const minX = Math.min(this.startX, currentX);
1167
+ const minY = Math.min(this.startY, currentY);
1168
+ const width = Math.abs(currentX - this.startX);
1169
+ const height = Math.abs(currentY - this.startY);
1170
+ // Update shape with screen coordinates
1171
+ this.currentShape.x = minX;
1172
+ this.currentShape.y = minY;
1173
+ this.currentShape.width = Math.max(1, width);
1174
+ this.currentShape.height = Math.max(1, height);
1175
+ // Recalculate world-space translateX/Y
1176
+ // Reset translateX/Y to initial value before updateDimensions
1177
+ this.currentShape.translateX = -this._core.store.state.translateX;
1178
+ this.currentShape.translateY = -this._core.store.state.translateY;
1179
+ this.currentShape.updateDimensions();
1180
+ this._core.store.state.objects.update(this.currentShape);
1181
+ }
1182
+ finishDrawing() {
1183
+ if (!this.currentShape) {
1184
+ return;
1185
+ }
1186
+ // Remove shape if it's too small (likely an accidental click)
1187
+ // Compare in screen space
1188
+ if (this.currentShape.width < 10 && this.currentShape.height < 10) {
1189
+ const shapeId = this.currentShape.id;
1190
+ this._core.store.state.objects.remove(o => o.id === shapeId);
1191
+ }
1192
+ else {
1193
+ this.currentShape.zIndex = this._core.store.currentZIndex;
1194
+ this._core.store.state.objects.update(this.currentShape);
1195
+ this._core.engine.emitObjectsChange();
1196
+ this._core.selectObjects([this.currentShape]);
1197
+ this._core.store.setState('activeTool', defaultLineTool_config.KritzelToolRegistry.getTool('selection'));
1198
+ }
1199
+ this.isDrawing = false;
1200
+ this.currentShape = null;
1201
+ this._core.rerender();
1202
+ }
1203
+ }
1204
+
1205
+ const DEFAULT_SHAPE_CONFIG = {
1206
+ shapeType: ShapeType.Rectangle,
1207
+ fillColor: 'transparent',
1208
+ strokeColor: '#000000',
1209
+ strokeWidth: 4,
1210
+ fontColor: '#000000',
1211
+ fontSize: 16,
1212
+ fontFamily: 'Arial',
1213
+ palette: [
1214
+ '#000000',
1215
+ '#ff5252',
1216
+ '#ffbc00',
1217
+ '#00c853',
1218
+ '#0000FF',
1219
+ '#d500f9',
1220
+ '#fafafa',
1221
+ '#a52714',
1222
+ '#ee8100',
1223
+ '#558b2f',
1224
+ '#01579b',
1225
+ '#8e24aa',
1226
+ '#90a4ae',
1227
+ ],
1228
+ };
1229
+
578
1230
  const ABSOLUTE_SCALE_MAX = 1000;
579
1231
  const ABSOLUTE_SCALE_MIN = 0.0001;
580
1232
 
@@ -625,16 +1277,24 @@ const KritzelEditor = class {
625
1277
  icon: 'type',
626
1278
  config: defaultLineTool_config.DEFAULT_TEXT_CONFIG,
627
1279
  },
1280
+ {
1281
+ name: 'shape',
1282
+ type: 'tool',
1283
+ tool: KritzelShapeTool,
1284
+ icon: 'shape-rectangle',
1285
+ config: DEFAULT_SHAPE_CONFIG,
1286
+ subOptions: [
1287
+ { id: 'rectangle', icon: 'shape-rectangle', label: 'Rectangle', value: ShapeType.Rectangle, toolProperty: 'shapeType' },
1288
+ { id: 'ellipse', icon: 'shape-ellipse', label: 'Ellipse', value: ShapeType.Ellipse, toolProperty: 'shapeType' },
1289
+ { id: 'triangle', icon: 'shape-triangle', label: 'Triangle', value: ShapeType.Triangle, toolProperty: 'shapeType' },
1290
+ ],
1291
+ },
628
1292
  {
629
1293
  name: 'image',
630
1294
  type: 'tool',
631
1295
  tool: defaultLineTool_config.KritzelImageTool,
632
1296
  icon: 'image',
633
1297
  },
634
- {
635
- name: 'divider',
636
- type: 'divider',
637
- },
638
1298
  {
639
1299
  name: 'config',
640
1300
  type: 'config',
@@ -811,7 +1471,7 @@ const KritzelEditor = class {
811
1471
  }
812
1472
  }
813
1473
  render() {
814
- return (index.h(index.Host, { key: 'f107cce23625f36978736ef948a51cd91d84c3f1' }, index.h("kritzel-workspace-manager", { key: 'a924de174ac5226c3ac5507c35e162b35490a5dd', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-engine", { key: '48b6c14ca2c1e1a2c745ec81294a331a463219a1', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, syncConfig: this.syncConfig, scaleMax: this.scaleMax, scaleMin: this.scaleMin, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onObjectsChange: event => this.handleObjectsChange(event), onUndoStateChange: event => this.handleUndoStateChange(event) }), index.h("kritzel-controls", { key: '2ec26e1444f4ba642c4fdc4ef2da1a62dc0256a6', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, onIsControlsReady: () => (this.isControlsReady = true) })));
1474
+ return (index.h(index.Host, { key: 'a39268fb2722bc9e1627a46a3430a574322dfdfb' }, index.h("kritzel-workspace-manager", { key: 'b0c08f2cab64347c0ee14a87ed0ab769a2e95733', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-engine", { key: 'c0efb9b0cdfdf3a9ba945e71e37c60ebfc45e981', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, syncConfig: this.syncConfig, scaleMax: this.scaleMax, scaleMin: this.scaleMin, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onObjectsChange: event => this.handleObjectsChange(event), onUndoStateChange: event => this.handleUndoStateChange(event) }), index.h("kritzel-controls", { key: '5a275fb94e2f55a1f79d6d5b5f518305cd739f24', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, onIsControlsReady: () => (this.isControlsReady = true) })));
815
1475
  }
816
1476
  static get watchers() { return {
817
1477
  "isEngineReady": ["onIsEngineReady"],
@@ -18056,6 +18716,14 @@ class KritzelViewport {
18056
18716
  this._core.rerender();
18057
18717
  }, 100);
18058
18718
  }
18719
+ /**
18720
+ * Cancels any pending debounced viewport updates.
18721
+ * Should be called before switching workspaces to prevent the old workspace's
18722
+ * viewport state from being saved to the new workspace.
18723
+ */
18724
+ cancelPendingUpdates() {
18725
+ this._debounceUpdate.cancel();
18726
+ }
18059
18727
  handleResize() {
18060
18728
  this._core.store.state.viewportWidth = this._core.store.state.host.clientWidth;
18061
18729
  this._core.store.state.viewportHeight = this._core.store.state.host.clientHeight;
@@ -18477,6 +19145,17 @@ class KritzelReviver {
18477
19145
  case 'KritzelText':
18478
19146
  revivedObj = defaultLineTool_config.KritzelText.create(this._core, obj.fontSize, obj.fontFamily).deserialize(obj);
18479
19147
  break;
19148
+ case 'KritzelShape':
19149
+ revivedObj = KritzelShape.create(this._core, {
19150
+ shapeType: obj.shapeType,
19151
+ fillColor: obj.fillColor,
19152
+ strokeColor: obj.strokeColor,
19153
+ strokeWidth: obj.strokeWidth,
19154
+ fontSize: obj.fontSize,
19155
+ fontFamily: obj.fontFamily,
19156
+ fontColor: obj.fontColor,
19157
+ }).deserialize(obj);
19158
+ break;
18480
19159
  case 'KritzelImage':
18481
19160
  revivedObj = defaultLineTool_config.KritzelImage.create(this._core).deserialize(obj);
18482
19161
  break;
@@ -18507,6 +19186,9 @@ class KritzelReviver {
18507
19186
  case 'KritzelLineTool':
18508
19187
  revivedObj = new defaultLineTool_config.KritzelLineTool(this._core);
18509
19188
  break;
19189
+ case 'KritzelShapeTool':
19190
+ revivedObj = new KritzelShapeTool(this._core);
19191
+ break;
18510
19192
  default:
18511
19193
  revivedObj = obj;
18512
19194
  }
@@ -18982,6 +19664,10 @@ class KritzelStore {
18982
19664
  const activeTexts = this._state.objects.filter(o => o instanceof defaultLineTool_config.KritzelText && o.isEditing);
18983
19665
  return activeTexts.length > 0 ? activeTexts[0] : null;
18984
19666
  }
19667
+ get activeShape() {
19668
+ const activeShapes = this._state.objects.filter(o => o instanceof KritzelShape && o.isEditing);
19669
+ return activeShapes.length > 0 ? activeShapes[0] : null;
19670
+ }
18985
19671
  get currentPath() {
18986
19672
  const drawingPaths = this._state.objects.filter(o => o instanceof defaultLineTool_config.KritzelPath && o.isCompleted === false);
18987
19673
  return drawingPaths.length > 0 ? drawingPaths[0] : null;
@@ -19230,6 +19916,11 @@ class KritzelCore {
19230
19916
  if (this._store.state.objects && this._store.state.objects.isReady) {
19231
19917
  this._store.state.objects.destroy();
19232
19918
  }
19919
+ // Create new ObjectMap with its own Y.Doc for this workspace
19920
+ const objectsMap = new KritzelObjectMap();
19921
+ // Assign immediately so the UI shows an empty state while loading,
19922
+ // instead of showing the old workspace's objects with the new workspace's viewport
19923
+ this._store.state.objects = objectsMap;
19233
19924
  // Set active workspace
19234
19925
  this._store.state.activeWorkspace = activeWorkspace;
19235
19926
  this._store.state.workspaces = this.loadWorkspacesFromAppState();
@@ -19238,10 +19929,7 @@ class KritzelCore {
19238
19929
  this._store.state.translateX = viewport.translateX ?? 0;
19239
19930
  this._store.state.translateY = viewport.translateY ?? 0;
19240
19931
  this._store.state.scale = viewport.scale ?? 1;
19241
- // Create new ObjectMap with its own Y.Doc for this workspace
19242
- const objectsMap = new KritzelObjectMap();
19243
19932
  await objectsMap.initialize(this, activeWorkspace.id, this._syncConfig);
19244
- this._store.state.objects = objectsMap;
19245
19933
  // Rebuild anchor index after loading objects
19246
19934
  this._anchorManager.rebuildIndex();
19247
19935
  this.engine.emitObjectsChange();
@@ -19618,6 +20306,12 @@ class KritzelCore {
19618
20306
  }
19619
20307
  }
19620
20308
  }
20309
+ resetActiveShape() {
20310
+ const activeShape = this._store.activeShape;
20311
+ if (activeShape) {
20312
+ activeShape.save();
20313
+ }
20314
+ }
19621
20315
  getObjectFromPointerEvent(event, selector = '.object') {
19622
20316
  const shadowRoot = this._store.state.host?.shadowRoot;
19623
20317
  if (!shadowRoot)
@@ -19690,6 +20384,14 @@ class KritzelCore {
19690
20384
  return { x: worldX, y: worldY };
19691
20385
  }
19692
20386
  beforeWorkspaceChange() {
20387
+ // Cancel any pending debounced viewport updates to prevent them from
20388
+ // saving the old workspace's viewport to the new workspace
20389
+ this._kritzelEngine.viewport?.cancelPendingUpdates();
20390
+ // Immediately save the current workspace's viewport before switching
20391
+ const currentWorkspace = this._store.state.activeWorkspace;
20392
+ if (currentWorkspace) {
20393
+ this.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
20394
+ }
19693
20395
  this.resetActiveText();
19694
20396
  this.clearSelection();
19695
20397
  this._store.setState('activeTool', defaultLineTool_config.KritzelToolRegistry.getTool('selection'));
@@ -20115,9 +20817,9 @@ const KritzelEngine = class {
20115
20817
  height: this.core.store.state.viewportHeight / this.core.store.state.scale,
20116
20818
  depth: 100,
20117
20819
  };
20118
- const visibleObjects = this.core.store.state.objects.query(viewportBounds);
20820
+ const visibleObjects = this.core.store.state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
20119
20821
  this.core.cursorManager.applyCursor();
20120
- return (index.h(index.Host, { key: '4a7e8c72ad1f80c3c31aa37eff33e78634cb37d1' }, this.core.store.state.debugInfo.showViewportInfo && (index.h("div", { key: '3c8981ce6cafbc49f4f04189d27809c511bf45c4', class: "debug-panel" }, index.h("div", { key: '428d483a87b98cde24446a0a26ba790ec2a6358b' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), index.h("div", { key: '3ec597c219109c026f78e5018a885e88e51aa5c4' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), index.h("div", { key: '803c0d009b19fdc7c465ef14f3b5f278a954a912' }, "TranslateX: ", this.core.store.state?.translateX), index.h("div", { key: '8b1aef0ae845cdf4b93afe59d8c78c84dd181a2d' }, "TranslateY: ", this.core.store.state?.translateY), index.h("div", { key: '137ead0c39a2fba55b4c4dde53fb09d0832439e1' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), index.h("div", { key: 'b19f710385e4306620176551853eb2645b96ca7a' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), index.h("div", { key: '943b55daada95aa37b759e45a15ffcfca76fba72' }, "PointerCount: ", this.core.store.state.pointers.size), index.h("div", { key: 'd001782dd4bc48c84c08477b26e5f3fce8df0b47' }, "Scale: ", this.core.store.state?.scale), index.h("div", { key: 'ed640d3905b39a995ba40a1cbf38f10a4aa1b400' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), index.h("div", { key: '154888aabbb56365aaf4584b0b991be848629e3e' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), index.h("div", { key: 'c0c39e988940baf20137de8a0eeda2c085da2810' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), index.h("div", { key: 'abd5a79b27bc75e898877d33097597c057dc3f2b' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), index.h("div", { key: '9c49bf3246525c9a755bb293bec8a143ade97158' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), index.h("div", { key: '88ff8ab48af31bf036719f72a5a3726780ab9720' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), index.h("div", { key: '9650075f855fcf91b7303d3ace14242075fc523d' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), index.h("div", { key: '911acb1f90f9812d30dc0aebceb207aecf9b4248' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), index.h("div", { key: 'b65db638d3cefbd74e2d03b639ee5fe86a2a858b' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), index.h("div", { key: 'c53ca259dadc656762733119b4086c1f82235a7e' }, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), index.h("div", { key: 'ae2d7a8917af450eb3bfd8e171a87530f337c0c2' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), index.h("div", { key: '5633cd9901ec028e4f5433c84b07321932beea66' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), index.h("div", { key: '82232a8eec470562e5658dee9713c855e78ca6a3' }, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), index.h("div", { key: '5b6b04b323a21ef37ddb144721ea01dccc7aec8b' }, "PointerX: ", this.core.store.state?.pointerX), index.h("div", { key: '3287f804515cfa31eaa755332e2043fce4feb7a9' }, "PointerY: ", this.core.store.state?.pointerY), index.h("div", { key: '3a59fd4db60f6f05d419de39149ea10e482875d4' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), index.h("div", { key: 'f91a8ea9dfc50e5f1ae89d66c7609a103e3263a4' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), index.h("div", { key: '40ba8fb5530243c18e0b0c3ad68dadb2cbc615a1', id: "origin", class: "origin", style: {
20822
+ return (index.h(index.Host, { key: '209ccf8414c635c9e04ca4807c95a29c629071ec' }, this.core.store.state.debugInfo.showViewportInfo && (index.h("div", { key: 'df6a03d1341887960bb91cbaa0a5dca6880a9293', class: "debug-panel" }, index.h("div", { key: '65157757ec6549ad2af311085a9618ab661f5ac0' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), index.h("div", { key: '20137b6c651a9aa8df15bce66d5bfe870a7af139' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), index.h("div", { key: '49dd30286641236ae428c731bb181cb06269852e' }, "TranslateX: ", this.core.store.state?.translateX), index.h("div", { key: 'd8ee431a10335e99aec40a596817765d7ee3f67b' }, "TranslateY: ", this.core.store.state?.translateY), index.h("div", { key: '34b1f31146080780433d6c1718d13bbfe397cb9b' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), index.h("div", { key: '4c279a106101cf808c91a2be4987569b21ae52b3' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), index.h("div", { key: '6ebd7ad3c803ef45d58a74180c52e8be8af8bca3' }, "PointerCount: ", this.core.store.state.pointers.size), index.h("div", { key: '345970c8b2b54f3a0d8fe1d9bb1b7b33023db386' }, "Scale: ", this.core.store.state?.scale), index.h("div", { key: 'fc265ae0e71cf22311cab3006dfc29b9d24397d2' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), index.h("div", { key: '9f921032a58b55e60f82d11a76f269051357d3e1' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), index.h("div", { key: '6d197e06cc362a9ecb8bfe00d272aecfec2b49e1' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), index.h("div", { key: '5313589ba2a509c95a5730dcf29c4003d9884cbf' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), index.h("div", { key: '8af9f9d6e33a2897c20962048bbf2a058f9d4a45' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), index.h("div", { key: '81aec0050d3e2122643b61fd725e71b25d97bc27' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), index.h("div", { key: 'c9956f05c01b74ee1666d9395a2715c3463fe401' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), index.h("div", { key: 'ae0a01c8f8aafc08326b136720c6a75b6aec6299' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), index.h("div", { key: '7816d40d73248a55120440e6d721325e1894178e' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), index.h("div", { key: 'c22383bacca0ada584f2e8a8577523c905d74ae2' }, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), index.h("div", { key: '8185a7318c6cdfde558cc372b79582d58b706f9e' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), index.h("div", { key: '2d56b05377693ef032ab2316fa753ecedf264b9c' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), index.h("div", { key: '2e2bf9fd321ef04dc0ac6dc21539eb0117c9fb23' }, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), index.h("div", { key: '3118ab970d5d37e01405c42308fc051d675d4bfa' }, "PointerX: ", this.core.store.state?.pointerX), index.h("div", { key: 'd8a31065843f89552f2d9c03dcbca960a716fa6c' }, "PointerY: ", this.core.store.state?.pointerY), index.h("div", { key: 'cb8d28b6ea63cbb6572f761011fccb847b748227' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), index.h("div", { key: 'd112a7e833c265085246817423557bfdc5b30b74' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), index.h("div", { key: 'df4f302192a8fc9644b7f883618b0a0f8a600dc8', id: "origin", class: "origin", style: {
20121
20823
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
20122
20824
  } }, visibleObjects?.map(object => {
20123
20825
  return (index.h("div", { key: object.id, style: {
@@ -20163,7 +20865,32 @@ const KritzelEngine = class {
20163
20865
  backgroundColor: object.backgroundColor,
20164
20866
  overflow: 'visible',
20165
20867
  textRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'optimizeSpeed' : 'auto',
20166
- } })), defaultLineTool_config.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (index.h("div", { ref: el => object.mount(el), style: {
20868
+ } })), defaultLineTool_config.KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (index.h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
20869
+ width: '100%',
20870
+ height: '100%',
20871
+ position: 'relative',
20872
+ overflow: 'visible',
20873
+ } }, index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
20874
+ position: 'absolute',
20875
+ top: '0',
20876
+ left: '0',
20877
+ width: '100%',
20878
+ height: '100%',
20879
+ overflow: 'visible',
20880
+ pointerEvents: 'none',
20881
+ }, viewBox: object.viewBox, preserveAspectRatio: "none" }, index.h("path", { d: object.getSvgPath(), fill: object.fillColor, stroke: object.strokeColor, "stroke-width": object.strokeWidth })), index.h("div", { ref: el => object.mountTextEditor(el), style: {
20882
+ position: 'absolute',
20883
+ top: '0',
20884
+ left: '0',
20885
+ width: '100%',
20886
+ height: '100%',
20887
+ display: 'flex',
20888
+ alignItems: 'center',
20889
+ justifyContent: 'center',
20890
+ textAlign: 'center',
20891
+ overflow: 'hidden',
20892
+ pointerEvents: object.isEditing ? 'auto' : 'none',
20893
+ } }))), defaultLineTool_config.KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (index.h("div", { ref: el => object.mount(el), style: {
20167
20894
  width: '100%',
20168
20895
  height: '100%',
20169
20896
  pointerEvents: 'auto',
@@ -20179,7 +20906,13 @@ const KritzelEngine = class {
20179
20906
  borderWidth: defaultLineTool_config.KritzelDevicesHelper.isFirefox() ? object.borderWidth + 'px' : '0',
20180
20907
  borderStyle: defaultLineTool_config.KritzelDevicesHelper.isFirefox() ? 'solid' : 'none',
20181
20908
  borderColor: defaultLineTool_config.KritzelDevicesHelper.isFirefox() ? object.borderColor : 'transparent',
20182
- } }))), this.core.store.state.debugInfo.showObjectInfo && object.isDebugInfoVisible && (index.h("g", { style: { pointerEvents: 'none' } }, index.h("foreignObject", { x: object.totalWidth.toString(), y: "0", width: "400px", height: "160px", style: { minHeight: '0', minWidth: '0' } }, index.h("div", { style: { width: '100%', height: '100%' } }, index.h("div", { style: { whiteSpace: 'nowrap' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap' } }, "rotationDegrees: ", object.rotationDegrees)))))), index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
20909
+ } })))), this.core.store.state.debugInfo.showObjectInfo && object.isDebugInfoVisible && (index.h("div", { style: {
20910
+ pointerEvents: 'none',
20911
+ position: 'absolute',
20912
+ left: `${object.totalWidth}px`,
20913
+ top: '0',
20914
+ zIndex: (object.zIndex + 2).toString(),
20915
+ } }, index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), index.h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), index.h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
20183
20916
  zIndex: (object.zIndex + 1).toString(),
20184
20917
  height: object?.totalHeight.toString(),
20185
20918
  width: object?.totalWidth.toString(),
@@ -20335,7 +21068,7 @@ const KritzelEngine = class {
20335
21068
  stroke: 'var(--kritzel-snap-indicator-stroke, #3b82f6)',
20336
21069
  strokeWidth: data.indicatorStrokeWidth,
20337
21070
  } }))));
20338
- })()), this.core.store.state.isContextMenuVisible && (index.h("kritzel-context-menu", { key: '7e350c48da76c54a223f23ead9dea8018b0bc36c', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
21071
+ })()), this.core.store.state.isContextMenuVisible && (index.h("kritzel-context-menu", { key: '81b44614c23f4016a1daa914ef8ea73eda0869eb', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
20339
21072
  position: 'fixed',
20340
21073
  left: `${this.core.store.state.contextMenuX}px`,
20341
21074
  top: `${this.core.store.state.contextMenuY}px`,
@@ -20346,7 +21079,7 @@ const KritzelEngine = class {
20346
21079
  y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
20347
21080
  }, this.core.store.selectionGroup?.objects);
20348
21081
  this.hideContextMenu();
20349
- }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof defaultLineTool_config.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { key: '7923a3f6a92fa71911c971166171317b5bc421bf', core: this.core })));
21082
+ }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof defaultLineTool_config.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { key: 'f748cd15c916d9fcb5fbf445167c69c1cc8aea63', core: this.core })));
20350
21083
  }
20351
21084
  static get watchers() { return {
20352
21085
  "workspace": ["onWorkspaceChange"],