kritzel-stencil 0.3.22 → 0.3.23

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 (104) hide show
  1. package/dist/cjs/index.cjs.js +3 -1
  2. package/dist/cjs/kritzel-active-users_45.cjs.entry.js +507 -288
  3. package/dist/cjs/{schema.constants-IBG5VW_J.js → schema.constants-Lr_zNkox.js} +713 -47
  4. package/dist/collection/classes/core/core.class.js +83 -5
  5. package/dist/collection/classes/core/store.class.js +9 -0
  6. package/dist/collection/classes/handlers/key.handler.js +1 -1
  7. package/dist/collection/classes/handlers/selection.handler.js +13 -9
  8. package/dist/collection/classes/objects/base-object.class.js +20 -8
  9. package/dist/collection/classes/objects/custom-element.class.js +330 -8
  10. package/dist/collection/classes/objects/image.class.js +0 -1
  11. package/dist/collection/classes/objects/selection-group.class.js +12 -0
  12. package/dist/collection/classes/providers/assets/asset-resolver.class.js +24 -14
  13. package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +0 -8
  14. package/dist/collection/classes/registries/custom-element-renderer.registry.js +52 -0
  15. package/dist/collection/classes/structures/app-state-map.structure.js +17 -3
  16. package/dist/collection/classes/structures/object-map.structure.js +17 -3
  17. package/dist/collection/classes/tools/selection-tool.class.js +34 -6
  18. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +9 -8
  19. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +211 -78
  20. package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +2 -1
  21. package/dist/collection/configs/default-engine-config.js +3 -2
  22. package/dist/collection/constants/version.js +1 -1
  23. package/dist/collection/helpers/html.helper.js +52 -0
  24. package/dist/collection/helpers/object.helper.js +3 -0
  25. package/dist/collection/helpers/svg-export.helper.js +35 -0
  26. package/dist/collection/helpers/wheel.helper.js +113 -0
  27. package/dist/collection/index.js +3 -0
  28. package/dist/collection/interfaces/custom-element-renderer.interface.js +1 -0
  29. package/dist/components/index.js +1 -1
  30. package/dist/components/kritzel-awareness-cursors.js +1 -1
  31. package/dist/components/kritzel-controls.js +1 -1
  32. package/dist/components/kritzel-current-user-dialog.js +1 -1
  33. package/dist/components/kritzel-current-user.js +1 -1
  34. package/dist/components/kritzel-dialog.js +1 -1
  35. package/dist/components/kritzel-editor.js +1 -1
  36. package/dist/components/kritzel-engine.js +1 -1
  37. package/dist/components/kritzel-export.js +1 -1
  38. package/dist/components/kritzel-login-dialog.js +1 -1
  39. package/dist/components/kritzel-menu-item.js +1 -1
  40. package/dist/components/kritzel-menu.js +1 -1
  41. package/dist/components/kritzel-more-menu.js +1 -1
  42. package/dist/components/kritzel-portal.js +1 -1
  43. package/dist/components/kritzel-settings.js +1 -1
  44. package/dist/components/kritzel-share-dialog.js +1 -1
  45. package/dist/components/kritzel-split-button.js +1 -1
  46. package/dist/components/kritzel-tool-config.js +1 -1
  47. package/dist/components/kritzel-tooltip.js +1 -1
  48. package/dist/components/kritzel-workspace-manager.js +1 -1
  49. package/dist/components/{p-BwuemYET.js → p-B4WfPDj0.js} +1 -1
  50. package/dist/components/p-BNu3Akp5.js +1 -0
  51. package/dist/components/p-BYveczcb.js +1 -0
  52. package/dist/components/{p-D28ZylHn.js → p-BixEMVtW.js} +1 -1
  53. package/dist/components/{p-Ndib1Jb3.js → p-BntMEYss.js} +1 -1
  54. package/dist/components/p-C48bv_0f.js +9 -0
  55. package/dist/components/{p-BO1CnEOT.js → p-CPMpf9ku.js} +1 -1
  56. package/dist/components/{p-BhODnvMO.js → p-CZQz_mul.js} +1 -1
  57. package/dist/components/{p-COj8EVzL.js → p-Ckpa5tHF.js} +1 -1
  58. package/dist/components/{p-BPoDE87Q.js → p-DJ3KI725.js} +1 -1
  59. package/dist/components/{p-DRsD38Nl.js → p-DPlEzPKO.js} +1 -1
  60. package/dist/components/{p-C-RiEw9X.js → p-DSd5xTAH.js} +1 -1
  61. package/dist/components/{p-CbMLbDou.js → p-DTqMF94b.js} +1 -1
  62. package/dist/components/{p-CHrSFOSI.js → p-DX2nriaq.js} +1 -1
  63. package/dist/components/{p-BAN5dnHX.js → p-Dd-pMvlr.js} +1 -1
  64. package/dist/components/{p-C5TZjIE1.js → p-M9m9-OEY.js} +1 -1
  65. package/dist/components/p-WUdQqYnu.js +1 -0
  66. package/dist/components/{p-YFR180v-.js → p-XDNjFYRB.js} +1 -1
  67. package/dist/components/{p-CJEIUs0x.js → p-X_pyPCe8.js} +1 -1
  68. package/dist/components/{p-CpR9lc-o.js → p-meY80XnF.js} +1 -1
  69. package/dist/components/{p-6Ca7Eolf.js → p-y5T0_Wvi.js} +1 -1
  70. package/dist/esm/index.js +2 -2
  71. package/dist/esm/kritzel-active-users_45.entry.js +500 -281
  72. package/dist/esm/{schema.constants-D35cwCYd.js → schema.constants-DMPBDrZh.js} +711 -47
  73. package/dist/stencil/index.esm.js +1 -1
  74. package/dist/stencil/p-27d41f6f.entry.js +9 -0
  75. package/dist/stencil/p-DMPBDrZh.js +1 -0
  76. package/dist/stencil/stencil.esm.js +1 -1
  77. package/dist/types/classes/core/core.class.d.ts +15 -0
  78. package/dist/types/classes/core/store.class.d.ts +6 -0
  79. package/dist/types/classes/objects/base-object.class.d.ts +3 -2
  80. package/dist/types/classes/objects/custom-element.class.d.ts +87 -21
  81. package/dist/types/classes/objects/image.class.d.ts +0 -1
  82. package/dist/types/classes/objects/selection-group.class.d.ts +1 -0
  83. package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +3 -0
  84. package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +0 -1
  85. package/dist/types/classes/registries/custom-element-renderer.registry.d.ts +32 -0
  86. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +7 -1
  87. package/dist/types/components.d.ts +2 -2
  88. package/dist/types/constants/version.d.ts +1 -1
  89. package/dist/types/helpers/html.helper.d.ts +2 -0
  90. package/dist/types/helpers/object.helper.d.ts +1 -0
  91. package/dist/types/helpers/svg-export.helper.d.ts +9 -0
  92. package/dist/types/helpers/wheel.helper.d.ts +9 -0
  93. package/dist/types/index.d.ts +3 -0
  94. package/dist/types/interfaces/asset-storage-config.interface.d.ts +0 -4
  95. package/dist/types/interfaces/custom-element-renderer.interface.d.ts +40 -0
  96. package/dist/types/interfaces/debug-info.interface.d.ts +1 -0
  97. package/dist/types/interfaces/object.interface.d.ts +0 -1
  98. package/package.json +1 -1
  99. package/dist/components/p-BML28BJR.js +0 -1
  100. package/dist/components/p-CVV-HzFR.js +0 -1
  101. package/dist/components/p-DWhWFDcC.js +0 -9
  102. package/dist/components/p-Dd_EODkk.js +0 -1
  103. package/dist/stencil/p-D35cwCYd.js +0 -1
  104. package/dist/stencil/p-fcbf7965.entry.js +0 -9
@@ -20,6 +20,7 @@ import { KritzelColorHelper } from "../../../helpers/color.helper";
20
20
  import { KritzelSvgExportHelper } from "../../../helpers/svg-export.helper";
21
21
  import { toPng, toSvg } from "html-to-image";
22
22
  import { ObjectHelper } from "../../../helpers/object.helper";
23
+ import { KritzelWheelHelper } from "../../../helpers/wheel.helper";
23
24
  export class KritzelEngine {
24
25
  host;
25
26
  /** The workspace to load and display. Changing this prop switches the active workspace. */
@@ -206,6 +207,7 @@ export class KritzelEngine {
206
207
  onDebugInfoChange(newValue) {
207
208
  if (newValue) {
208
209
  this.core.store.state.debugInfo = newValue;
210
+ this.core.assetResolver.setShowInfo(newValue.showAssetResolverInfo);
209
211
  }
210
212
  }
211
213
  /** When false, non-modified wheel events do not pan the viewport. */
@@ -259,6 +261,12 @@ export class KritzelEngine {
259
261
  if (this.core.store.state.isContextMenuVisible) {
260
262
  this.hideContextMenu();
261
263
  }
264
+ const hoveredObject = this.core.getObjectFromPointerEvent(ev);
265
+ if (hoveredObject &&
266
+ ObjectHelper.isClass(hoveredObject, 'KritzelCustomElement') &&
267
+ KritzelWheelHelper.shouldKeepWheelInCustomElement(ev, hoveredObject)) {
268
+ return;
269
+ }
262
270
  if (ev.ctrlKey) {
263
271
  if (this.isZoomingEnabled) {
264
272
  this.viewport.handleWheel(ev);
@@ -275,6 +283,11 @@ export class KritzelEngine {
275
283
  if (this.core.store.isDisabled) {
276
284
  return;
277
285
  }
286
+ // Interactive custom-element content should receive native pointer events
287
+ // whenever the object is marked interactive.
288
+ if (this.isEmbeddedCustomElementInteraction(ev)) {
289
+ return;
290
+ }
278
291
  if (KritzelDevicesHelper.isTouchDevice()) {
279
292
  KritzelEventHelper.onLongPress(ev, (event) => this.longpress.emit(event));
280
293
  }
@@ -291,6 +304,10 @@ export class KritzelEngine {
291
304
  if (this.core.store.isDisabled) {
292
305
  return;
293
306
  }
307
+ // Ignore drag/move sequences when their pointerdown was intentionally bypassed.
308
+ if (ev.buttons > 0 && !this.core.store.state.pointers.has(ev.pointerId)) {
309
+ return;
310
+ }
294
311
  if (this.core.store.state.pointers.has(ev.pointerId)) {
295
312
  this.core.store.state.pointers.set(ev.pointerId, ev);
296
313
  }
@@ -339,6 +356,56 @@ export class KritzelEngine {
339
356
  this.viewport.handlePointerUp(ev);
340
357
  this.core.store.state?.activeTool?.handlePointerUp(ev);
341
358
  }
359
+ isEmbeddedCustomElementInteraction(event) {
360
+ const path = event.composedPath();
361
+ const objectElement = path.find((entry) => {
362
+ return entry instanceof HTMLElement && entry.classList.contains('object');
363
+ });
364
+ if (!objectElement?.id) {
365
+ return false;
366
+ }
367
+ const object = this.core.store.objects.findById(objectElement.id);
368
+ if (!object || !KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
369
+ return false;
370
+ }
371
+ const isSelected = !!this.core.store.selectionGroup?.objects?.some(selectedObject => selectedObject.id === object.id);
372
+ if (!isSelected) {
373
+ return false;
374
+ }
375
+ if (object.isInteractive !== true) {
376
+ return false;
377
+ }
378
+ const potentialRoots = [];
379
+ if (object.element instanceof HTMLElement) {
380
+ potentialRoots.push(object.element);
381
+ }
382
+ if (object.elementRef instanceof HTMLElement) {
383
+ potentialRoots.push(object.elementRef);
384
+ }
385
+ if (potentialRoots.length === 0) {
386
+ return false;
387
+ }
388
+ // Only bypass canvas tool handling when the pointer event came from an
389
+ // actually interactive descendant inside the custom element subtree.
390
+ return potentialRoots.some(root => this.isNativeInteractiveEmbeddedTarget(path, root));
391
+ }
392
+ isNativeInteractiveEmbeddedTarget(path, customElementRoot) {
393
+ const interactiveSelector = 'input, button, textarea, select, a[href], [contenteditable="true"], [contenteditable=""]';
394
+ const rootIndex = path.findIndex(entry => entry === customElementRoot);
395
+ if (rootIndex === -1) {
396
+ return false;
397
+ }
398
+ for (const entry of path.slice(0, rootIndex)) {
399
+ if (!(entry instanceof HTMLElement)) {
400
+ continue;
401
+ }
402
+ const interactiveEntry = entry;
403
+ if (interactiveEntry.matches(interactiveSelector)) {
404
+ return true;
405
+ }
406
+ }
407
+ return false;
408
+ }
342
409
  handlePointerLeave() {
343
410
  this.core.store.objects?.clearCursorPosition();
344
411
  }
@@ -410,7 +477,7 @@ export class KritzelEngine {
410
477
  void this.core.clipboardManager.paste(undefined, undefined, ev);
411
478
  }
412
479
  /**
413
- * Determines if the engine should handle a keyboard/clipboard shortcut event.
480
+ * Determines if the engine should handle a keyboard/clipboard shortcut event.
414
481
  * Returns true only if:
415
482
  * - The event originates from within the engine component, OR
416
483
  * - The event target is not an interactive element that needs keyboard input
@@ -1624,6 +1691,8 @@ export class KritzelEngine {
1624
1691
  _syncConfigRevision = 0;
1625
1692
  _assetStorageConfigRevision = 0;
1626
1693
  _isWorkspaceLoading = false;
1694
+ _hasLoggedUnlicensedWelcomeBanner = false;
1695
+ _previousVisibleCustomElements = new Set();
1627
1696
  _defaultUndoState = {
1628
1697
  canUndo: false,
1629
1698
  canRedo: false,
@@ -1671,6 +1740,14 @@ export class KritzelEngine {
1671
1740
  }
1672
1741
  disconnectedCallback() {
1673
1742
  this.throttledPointerMoveMulti.cancel();
1743
+ // Unmount all remaining custom elements
1744
+ if (this.core.store.allObjects) {
1745
+ this.core.store.allObjects.forEach(object => {
1746
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
1747
+ object.unmount();
1748
+ }
1749
+ });
1750
+ }
1674
1751
  // Clear cursor position in awareness before destroying
1675
1752
  this.core.store.objects?.clearCursorPosition();
1676
1753
  // Clean up current workspace's ObjectMap
@@ -1727,6 +1804,7 @@ export class KritzelEngine {
1727
1804
  await this.initializeSyncAndWorkspace();
1728
1805
  if (this.core.store.state.isReady === false) {
1729
1806
  this.core.store.state.isReady = true;
1807
+ this.logUnlicensedWelcomeBanner();
1730
1808
  this.isEngineReady.emit(this.core.store.state);
1731
1809
  }
1732
1810
  }, 50);
@@ -1766,6 +1844,14 @@ export class KritzelEngine {
1766
1844
  }
1767
1845
  this._isAssetStorageInitialized = true;
1768
1846
  }
1847
+ logUnlicensedWelcomeBanner() {
1848
+ if (this.core.licenseManager.isLicensed || this._hasLoggedUnlicensedWelcomeBanner) {
1849
+ return;
1850
+ }
1851
+ this._hasLoggedUnlicensedWelcomeBanner = true;
1852
+ console.info('%c👋 Welcome to Kritzel', 'color: #007AFF; font-weight: 700;');
1853
+ console.info(`This version of Kritzel is not licensed. Get a license at: https://kritzel.io`);
1854
+ }
1769
1855
  async doInitializeSyncAndWorkspace() {
1770
1856
  // Capture sync config revision to detect prop updates that happen while
1771
1857
  // initialization is in-flight.
@@ -1969,8 +2055,7 @@ export class KritzelEngine {
1969
2055
  if (normalizedScale <= this._objectDistanceFadeFarScale) {
1970
2056
  return this._objectDistanceFadeMinOpacity;
1971
2057
  }
1972
- const progress = (this._objectDistanceFadeNearScale - normalizedScale) /
1973
- (this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
2058
+ const progress = (this._objectDistanceFadeNearScale - normalizedScale) / (this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
1974
2059
  const smooth = progress * progress * (3 - 2 * progress);
1975
2060
  return 1 - smooth * (1 - this._objectDistanceFadeMinOpacity);
1976
2061
  }
@@ -1981,8 +2066,7 @@ export class KritzelEngine {
1981
2066
  if (normalizedScale >= this._objectDistanceFadeCloseMaxScale) {
1982
2067
  return this._objectDistanceFadeCloseMinOpacity;
1983
2068
  }
1984
- const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) /
1985
- (this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
2069
+ const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) / (this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
1986
2070
  const smooth = progress * progress * (3 - 2 * progress);
1987
2071
  return 1 - smooth * (1 - this._objectDistanceFadeCloseMinOpacity);
1988
2072
  }
@@ -1992,13 +2076,18 @@ export class KritzelEngine {
1992
2076
  }
1993
2077
  getObjectEffectiveOpacity(object, viewportScale) {
1994
2078
  const safeObjectOpacity = Number.isFinite(object.opacity) ? object.opacity : 1;
1995
- const distanceFadeMultiplier = this.shouldApplyDistanceFade(object)
1996
- ? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale)
1997
- : 1;
2079
+ const distanceFadeMultiplier = this.shouldApplyDistanceFade(object) ? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale) : 1;
1998
2080
  const multiplied = (object.markedForRemoval ? 0.5 : 1) * safeObjectOpacity * distanceFadeMultiplier;
1999
2081
  const overridden = ((object.markedForRemoval ? 0.5 : safeObjectOpacity) * distanceFadeMultiplier).toString();
2000
2082
  return { multiplied, overridden };
2001
2083
  }
2084
+ getSelectionHandleCapabilities(object) {
2085
+ const selectedObjects = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') ? object.objects : [object];
2086
+ return {
2087
+ canRenderResizeHandles: selectedObjects.every(selectedObject => selectedObject.isResizable !== false),
2088
+ canRenderRotationHandle: selectedObjects.every(selectedObject => selectedObject.isRotatable !== false),
2089
+ };
2090
+ }
2002
2091
  render() {
2003
2092
  if (!this.viewport) {
2004
2093
  return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), this.core.localizationManager.translate('engine.loading')))));
@@ -2012,6 +2101,45 @@ export class KritzelEngine {
2012
2101
  const viewportCenterX = this.core.store.state.viewportWidth / 2 + this.core.store.state.translateX;
2013
2102
  const viewportCenterY = this.core.store.state.viewportHeight / 2 + this.core.store.state.translateY;
2014
2103
  const visibleObjects = this.core.store.objectsInViewport;
2104
+ const getObjectWrapperPointerEvents = (object) => {
2105
+ if (this.core.store.state.isScaling) {
2106
+ return 'none';
2107
+ }
2108
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
2109
+ return 'none';
2110
+ }
2111
+ return 'auto';
2112
+ };
2113
+ const getSelectionGroupOverlayPointerEvents = (object) => {
2114
+ if (object.markedForRemoval) {
2115
+ return 'none';
2116
+ }
2117
+ if (!KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
2118
+ return 'auto';
2119
+ }
2120
+ if (object.objects.length === 1 && KritzelClassHelper.isInstanceOf(object.objects[0], 'KritzelCustomElement')) {
2121
+ return 'none';
2122
+ }
2123
+ return 'auto';
2124
+ };
2125
+ // Track visible custom elements and unmount culled ones
2126
+ const currentVisibleCustomElements = new Set();
2127
+ visibleObjects.forEach(object => {
2128
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
2129
+ currentVisibleCustomElements.add(object.id);
2130
+ }
2131
+ });
2132
+ // Unmount custom elements that left the viewport
2133
+ this._previousVisibleCustomElements.forEach(id => {
2134
+ if (!currentVisibleCustomElements.has(id)) {
2135
+ const object = this.core.store.objects.findById(id);
2136
+ if (object && KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
2137
+ object.unmount();
2138
+ }
2139
+ }
2140
+ });
2141
+ // Update tracking set for next render
2142
+ this._previousVisibleCustomElements = currentVisibleCustomElements;
2015
2143
  this.core.cursorManager.applyCursor();
2016
2144
  if (this.core.store.state.hasViewportChanged) {
2017
2145
  this.viewportChange.emit(this.viewport.getViewport());
@@ -2028,7 +2156,7 @@ export class KritzelEngine {
2028
2156
  transformOrigin: 'top left',
2029
2157
  position: 'absolute',
2030
2158
  zIndex: object.zIndex.toString(),
2031
- pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
2159
+ pointerEvents: getObjectWrapperPointerEvents(object),
2032
2160
  } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
2033
2161
  height: object?.totalHeight + 'px',
2034
2162
  width: object?.totalWidth + 'px',
@@ -2117,7 +2245,7 @@ export class KritzelEngine {
2117
2245
  transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
2118
2246
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
2119
2247
  opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
2120
- pointerEvents: object.markedForRemoval ? 'none' : 'auto',
2248
+ pointerEvents: getSelectionGroupOverlayPointerEvents(object),
2121
2249
  } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => el && object.mount(el), style: {
2122
2250
  position: 'absolute',
2123
2251
  left: '0',
@@ -2152,60 +2280,65 @@ export class KritzelEngine {
2152
2280
  transform: `scale(${object.scaleFactor})`,
2153
2281
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
2154
2282
  overflow: 'visible',
2155
- } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (() => {
2156
- const fillResolved = KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme);
2157
- const strokeResolved = KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme);
2158
- const isFilled = !!fillResolved && fillResolved !== 'transparent';
2159
- const strokeMatchesFill = isFilled && strokeResolved === fillResolved;
2160
- return (h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
2161
- position: 'absolute',
2162
- left: '0',
2163
- top: '0',
2164
- width: object.totalWidth + 'px',
2165
- height: object.totalHeight + 'px',
2166
- transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
2167
- transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
2168
- pointerEvents: object.markedForRemoval ? 'none' : 'auto',
2169
- overflow: 'visible',
2170
- } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
2171
- position: 'absolute',
2172
- top: '0',
2173
- left: '0',
2174
- width: '100%',
2175
- height: '100%',
2176
- overflow: 'visible',
2177
- pointerEvents: 'none',
2178
- }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.applyOpacity(object.fillColor, effectiveOpacity, currentTheme), stroke: strokeMatchesFill ? 'none' : KritzelColorHelper.applyOpacity(object.strokeColor, effectiveOpacity, currentTheme), "stroke-width": strokeMatchesFill ? 0 : object.strokeWidth })), h("div", { ref: el => el && object.mountTextEditor(el), style: {
2179
- position: 'absolute',
2180
- top: '0',
2181
- left: '0',
2182
- width: '100%',
2183
- height: '100%',
2184
- display: 'flex',
2185
- alignItems: 'center',
2186
- justifyContent: 'center',
2187
- textAlign: 'center',
2188
- overflow: 'hidden',
2189
- pointerEvents: object.isEditing ? 'auto' : 'none',
2190
- } })));
2191
- })(), this.core.store.state.debugInfo.showObjectInfo && object.isDebugInfoVisible && (h("div", { style: {
2283
+ } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') &&
2284
+ (() => {
2285
+ const fillResolved = KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme);
2286
+ const strokeResolved = KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme);
2287
+ const isFilled = !!fillResolved && fillResolved !== 'transparent';
2288
+ const strokeMatchesFill = isFilled && strokeResolved === fillResolved;
2289
+ return (h("div", { ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
2290
+ position: 'absolute',
2291
+ left: '0',
2292
+ top: '0',
2293
+ width: object.totalWidth + 'px',
2294
+ height: object.totalHeight + 'px',
2295
+ transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
2296
+ transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
2297
+ pointerEvents: object.markedForRemoval ? 'none' : 'auto',
2298
+ overflow: 'visible',
2299
+ } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
2300
+ position: 'absolute',
2301
+ top: '0',
2302
+ left: '0',
2303
+ width: '100%',
2304
+ height: '100%',
2305
+ overflow: 'visible',
2306
+ pointerEvents: 'none',
2307
+ }, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: KritzelColorHelper.applyOpacity(object.fillColor, effectiveOpacity, currentTheme), stroke: strokeMatchesFill ? 'none' : KritzelColorHelper.applyOpacity(object.strokeColor, effectiveOpacity, currentTheme), "stroke-width": strokeMatchesFill ? 0 : object.strokeWidth })), h("div", { ref: el => el && object.mountTextEditor(el), style: {
2308
+ position: 'absolute',
2309
+ top: '0',
2310
+ left: '0',
2311
+ width: '100%',
2312
+ height: '100%',
2313
+ display: 'flex',
2314
+ alignItems: 'center',
2315
+ justifyContent: 'center',
2316
+ textAlign: 'center',
2317
+ overflow: 'hidden',
2318
+ pointerEvents: object.isEditing ? 'auto' : 'none',
2319
+ } })));
2320
+ })(), this.core.store.state.debugInfo.showObjectInfo && (h("div", { style: {
2192
2321
  pointerEvents: 'none',
2193
2322
  position: 'absolute',
2194
2323
  left: `${object.totalWidth}px`,
2195
2324
  top: '0',
2196
2325
  zIndex: (object.zIndex + 2).toString(),
2197
- } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
2326
+ } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isSelected: ", object.isSelected ? 'true' : 'false'), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isInteractive: ", object.isInteractive ? 'true' : 'false'))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
2198
2327
  (() => {
2199
2328
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
2200
2329
  const localClientId = this.core.store.objects?.localClientId;
2201
2330
  const awarenessStates = this.core.store.objects?.awareness?.getStates();
2202
- const isRemoteSelection = isSelectionGroup && (
2203
- // Different user
2204
- (object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
2205
- // Same user but different client that is still actively connected (e.g. same account on another device)
2206
- (object.userId != null && this.core.user?.id != null && object.userId === this.core.user.id &&
2207
- object.clientId != null && localClientId != null && object.clientId !== localClientId &&
2208
- awarenessStates?.has(object.clientId) === true));
2331
+ const isRemoteSelection = isSelectionGroup &&
2332
+ // Different user
2333
+ ((object.userId != null && this.core.user?.id != null && object.userId !== this.core.user.id) ||
2334
+ // Same user but different client that is still actively connected (e.g. same account on another device)
2335
+ (object.userId != null &&
2336
+ this.core.user?.id != null &&
2337
+ object.userId === this.core.user.id &&
2338
+ object.clientId != null &&
2339
+ localClientId != null &&
2340
+ object.clientId !== localClientId &&
2341
+ awarenessStates?.has(object.clientId) === true));
2209
2342
  let remoteUserColor;
2210
2343
  if (isRemoteSelection) {
2211
2344
  if (awarenessStates) {
@@ -2224,10 +2357,10 @@ export class KritzelEngine {
2224
2357
  }
2225
2358
  }
2226
2359
  }
2227
- const selectionBorderColor = remoteUserColor
2228
- ?? (KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme) || 'var(--kritzel-selection-border-color, #007AFF)');
2229
- const selectionHandleStrokeColor = remoteUserColor
2230
- ?? 'var(--kritzel-selection-handle-stroke-color, #007AFF)';
2360
+ const selectionBorderColor = remoteUserColor ?? (KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme) || 'var(--kritzel-selection-border-color, #007AFF)');
2361
+ const selectionHandleStrokeColor = remoteUserColor ?? 'var(--kritzel-selection-handle-stroke-color, #007AFF)';
2362
+ const handleScale = object.scale ?? 1;
2363
+ const { canRenderResizeHandles, canRenderRotationHandle } = this.getSelectionHandleCapabilities(object);
2231
2364
  return (h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
2232
2365
  zIndex: (object.zIndex + 1).toString(),
2233
2366
  height: object?.totalHeight.toString(),
@@ -2271,50 +2404,50 @@ export class KritzelEngine {
2271
2404
  strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2272
2405
  strokeLinecap: 'square',
2273
2406
  } })));
2274
- })(), !this.isSelecting && !isRemoteSelection && (h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2407
+ })(), !this.isSelecting && !isRemoteSelection && (h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, canRenderResizeHandles && (h("g", null, h("rect", { class: "resize-handle top-left", x: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2275
2408
  fill: 'var(--kritzel-selection-handle-color, #ffffff)',
2276
2409
  stroke: selectionHandleStrokeColor,
2277
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
2410
+ strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
2278
2411
  paintOrder: 'fill',
2279
- } }), h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2412
+ } }), h("rect", { class: "resize-handle-overlay top-left", x: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2280
2413
  fill: 'transparent',
2281
2414
  paintOrder: 'fill',
2282
- } }), h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2415
+ } }), h("rect", { class: "resize-handle top-right", x: `${object.totalWidth - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2283
2416
  fill: 'var(--kritzel-selection-handle-color, #ffffff)',
2284
2417
  stroke: selectionHandleStrokeColor,
2285
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
2418
+ strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
2286
2419
  paintOrder: 'fill',
2287
- } }), h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2420
+ } }), h("rect", { class: "resize-handle-overlay top-right", x: `${object.totalWidth - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2288
2421
  fill: 'transparent',
2289
2422
  paintOrder: 'fill',
2290
- } }), h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2423
+ } }), h("rect", { class: "resize-handle bottom-left", x: `${(-(baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2291
2424
  fill: 'var(--kritzel-selection-handle-color, #ffffff)',
2292
2425
  stroke: selectionHandleStrokeColor,
2293
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
2426
+ strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
2294
2427
  paintOrder: 'fill',
2295
- } }), h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2428
+ } }), h("rect", { class: "resize-handle-overlay bottom-left", x: `${(-baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2296
2429
  fill: 'transparent',
2297
2430
  paintOrder: 'fill',
2298
- } }), h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2431
+ } }), h("rect", { class: "resize-handle bottom-right", x: `${object.totalWidth - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - ((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, width: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, height: `${((baseHandleSize - 1) * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2299
2432
  fill: 'var(--kritzel-selection-handle-color, #ffffff)',
2300
2433
  stroke: selectionHandleStrokeColor,
2301
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
2434
+ strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
2302
2435
  paintOrder: 'fill',
2303
- } }), h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * object.scale) / this.core.store.state?.scale}`, style: {
2436
+ } }), h("rect", { class: "resize-handle-overlay bottom-right", x: `${object.totalWidth - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, y: `${object.totalHeight - (baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, width: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, height: `${(baseHandleTouchSize * 2 * handleScale) / this.core.store.state?.scale}`, style: {
2304
2437
  fill: 'transparent',
2305
2438
  paintOrder: 'fill',
2306
- } }), h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.core.store.state?.scale), style: {
2439
+ } }))), canRenderRotationHandle && (h("g", null, h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * handleScale) / this.core.store.state?.scale), style: {
2307
2440
  stroke: selectionBorderColor,
2308
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2309
- } }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${((baseHandleSize - 1) * object.scale) / this.core.store.state?.scale}`, style: {
2441
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${handleScale} / ${this.core.store.state?.scale})`,
2442
+ } }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * handleScale) / this.core.store.state?.scale), r: `${((baseHandleSize - 1) * handleScale) / this.core.store.state?.scale}`, style: {
2310
2443
  fill: 'var(--kritzel-selection-handle-color, #ffffff)',
2311
2444
  stroke: selectionHandleStrokeColor,
2312
- strokeWidth: `calc(2px * ${object.scale} / ${this.core.store.state?.scale})`,
2445
+ strokeWidth: `calc(2px * ${handleScale} / ${this.core.store.state?.scale})`,
2313
2446
  paintOrder: 'fill',
2314
- } }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2447
+ } }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * handleScale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * handleScale) / this.core.store.state?.scale}`, style: {
2315
2448
  fill: 'transparent',
2316
2449
  paintOrder: 'fill',
2317
- } }))))), this.core.displaySelectionLineUI(object) && KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-line-borders" }, h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
2450
+ } }))))))), this.core.displaySelectionLineUI(object) && KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-line-borders" }, h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
2318
2451
  stroke: selectionBorderColor,
2319
2452
  strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2320
2453
  strokeLinecap: 'round',
@@ -2439,7 +2572,7 @@ export class KritzelEngine {
2439
2572
  }, this.core.store.selectionGroup?.objects || []);
2440
2573
  }
2441
2574
  this.hideContextMenu();
2442
- }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && (h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') }))));
2575
+ }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
2443
2576
  }
2444
2577
  static get is() { return "kritzel-engine"; }
2445
2578
  static get encapsulation() { return "shadow"; }
@@ -13,6 +13,7 @@ const DEFAULT_DEBUG_INFO = {
13
13
  showObjectInfo: false,
14
14
  showSyncProviderInfo: true,
15
15
  showMigrationInfo: true,
16
+ showAssetResolverInfo: false,
16
17
  };
17
18
  const SETTINGS_CATEGORY_IDS = ['general', 'viewport', 'shortcuts', 'developer', 'about'];
18
19
  export class KritzelSettings {
@@ -217,7 +218,7 @@ export class KritzelSettings {
217
218
  }
218
219
  }
219
220
  render() {
220
- return (h(Host, { key: '6f26bd23bf7bb51653f09b96bafef221c51c2bfa' }, h("kritzel-dialog", { key: '49ffda0a422ae1c2c9c8e6e608bce532e7d4099e', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: 'ab5dc7952e555cae6f841ef4de2ab50d7039279b', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
221
+ return (h(Host, { key: '8b96261465efeabb2eb0cf724d29699de5e230a8' }, h("kritzel-dialog", { key: '273a9df290bb97d59000a97f91821e7bad3f3896', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: '64d17dfaa2a0baf2d4a5d00fe5fc65ad40c96ec6', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
221
222
  }
222
223
  static get is() { return "kritzel-settings"; }
223
224
  static get encapsulation() { return "shadow"; }
@@ -36,8 +36,9 @@ export const DEFAULT_ENGINE_CONFIG = {
36
36
  debugInfo: {
37
37
  showObjectInfo: false,
38
38
  showViewportInfo: false,
39
- showSyncProviderInfo: true,
40
- showMigrationInfo: true
39
+ showSyncProviderInfo: false,
40
+ showAssetResolverInfo: false,
41
+ showMigrationInfo: false,
41
42
  },
42
43
  host: null,
43
44
  pointerX: 0,
@@ -3,4 +3,4 @@
3
3
  * This file is auto-generated by the version bump scripts.
4
4
  * Do not modify manually.
5
5
  */
6
- export const KRITZEL_VERSION = '0.3.22';
6
+ export const KRITZEL_VERSION = '0.3.23';
@@ -3,6 +3,58 @@ export class KritzelHTMLHelper {
3
3
  const value = window.getComputedStyle(element).getPropertyValue(property);
4
4
  return parseFloat(value) || 0;
5
5
  }
6
+ static isScrollableElement(element) {
7
+ if (!(element instanceof HTMLElement)) {
8
+ return false;
9
+ }
10
+ const style = window.getComputedStyle(element);
11
+ const overflowX = style.overflowX;
12
+ const overflowY = style.overflowY;
13
+ const overflow = style.overflow;
14
+ const canScrollX = (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'overlay') && element.scrollWidth > element.clientWidth;
15
+ const canScrollY = (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') && element.scrollHeight > element.clientHeight;
16
+ const canScroll = overflow === 'auto' || overflow === 'scroll' || overflow === 'overlay';
17
+ return canScrollX || canScrollY || (canScroll && (element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight));
18
+ }
19
+ static findScrollableElement(root) {
20
+ if (!root) {
21
+ return null;
22
+ }
23
+ const visited = new Set();
24
+ const walk = (element) => {
25
+ if (visited.has(element)) {
26
+ return null;
27
+ }
28
+ visited.add(element);
29
+ if (this.isScrollableElement(element)) {
30
+ return element;
31
+ }
32
+ if (element.shadowRoot) {
33
+ for (const child of Array.from(element.shadowRoot.children)) {
34
+ const scrollable = walk(child);
35
+ if (scrollable) {
36
+ return scrollable;
37
+ }
38
+ }
39
+ }
40
+ if (element.tagName === 'SLOT') {
41
+ for (const assignedElement of element.assignedElements({ flatten: true })) {
42
+ const scrollable = walk(assignedElement);
43
+ if (scrollable) {
44
+ return scrollable;
45
+ }
46
+ }
47
+ }
48
+ for (const child of Array.from(element.children)) {
49
+ const scrollable = walk(child);
50
+ if (scrollable) {
51
+ return scrollable;
52
+ }
53
+ }
54
+ return null;
55
+ };
56
+ return walk(root);
57
+ }
6
58
  static getScrollableParent(element) {
7
59
  if (!element) {
8
60
  return window;
@@ -12,4 +12,7 @@ export class ObjectHelper {
12
12
  }
13
13
  return Object?.keys(obj).length === 0 && obj?.constructor === Object;
14
14
  }
15
+ static isClass(object, className) {
16
+ return !!object && object.__class__ === className;
17
+ }
15
18
  }