kritzel-stencil 0.3.12 → 0.3.14

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 (169) hide show
  1. package/dist/cjs/{index-CFnj_FXt.js → index-Xav9JFHg.js} +1 -1
  2. package/dist/cjs/index.cjs.js +41 -3
  3. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +281 -113
  4. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  5. package/dist/cjs/loader.cjs.js +2 -2
  6. package/dist/cjs/{schema.constants-CzfoUWxF.js → schema.constants-DJQTjcy7.js} +84 -42
  7. package/dist/cjs/stencil.cjs.js +3 -3
  8. package/dist/collection/classes/core/viewport.class.js +97 -8
  9. package/dist/collection/classes/objects/image.class.js +62 -0
  10. package/dist/collection/classes/objects/shape.class.js +2 -1
  11. package/dist/collection/classes/tools/base-tool.class.js +2 -0
  12. package/dist/collection/classes/tools/brush-tool.class.js +1 -0
  13. package/dist/collection/classes/tools/eraser-tool.class.js +1 -0
  14. package/dist/collection/classes/tools/image-tool.class.js +1 -0
  15. package/dist/collection/classes/tools/line-tool.class.js +1 -0
  16. package/dist/collection/classes/tools/selection-tool.class.js +1 -0
  17. package/dist/collection/classes/tools/shape-tool.class.js +1 -0
  18. package/dist/collection/classes/tools/text-tool.class.js +1 -0
  19. package/dist/collection/collection-manifest.json +1 -1
  20. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +156 -33
  21. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +270 -19
  22. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.css +3 -3
  23. package/dist/collection/components/shared/kritzel-input/kritzel-input.css +1 -1
  24. package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.css +2 -2
  25. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.css +7 -0
  26. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +7 -1
  27. package/dist/collection/components/ui/kritzel-export/kritzel-export.css +1 -1
  28. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +2 -2
  29. package/dist/collection/configs/default-asset-storage.config.js +1 -2
  30. package/dist/collection/configs/default-sync.config.js +2 -5
  31. package/dist/collection/constants/version.js +1 -1
  32. package/dist/collection/helpers/tool-config.helper.js +58 -65
  33. package/dist/collection/interfaces/tool-type.interface.js +1 -0
  34. package/dist/collection/themes/dark-theme.js +5 -0
  35. package/dist/collection/themes/light-theme.js +5 -0
  36. package/dist/components/index.js +1 -1
  37. package/dist/components/kritzel-active-users.js +1 -1
  38. package/dist/components/kritzel-avatar.js +1 -1
  39. package/dist/components/kritzel-awareness-cursors.js +1 -1
  40. package/dist/components/kritzel-back-to-content.js +1 -1
  41. package/dist/components/kritzel-brush-style.js +1 -1
  42. package/dist/components/kritzel-button.js +1 -1
  43. package/dist/components/kritzel-color-palette.js +1 -1
  44. package/dist/components/kritzel-color.js +1 -1
  45. package/dist/components/kritzel-context-menu.js +1 -1
  46. package/dist/components/kritzel-controls.js +1 -1
  47. package/dist/components/kritzel-current-user-dialog.js +1 -1
  48. package/dist/components/kritzel-current-user.js +1 -1
  49. package/dist/components/kritzel-cursor-trail.js +1 -1
  50. package/dist/components/kritzel-dialog.js +1 -1
  51. package/dist/components/kritzel-dropdown.js +1 -1
  52. package/dist/components/kritzel-editor.js +1 -1
  53. package/dist/components/kritzel-engine.js +1 -1
  54. package/dist/components/kritzel-export.js +1 -1
  55. package/dist/components/kritzel-font-family.js +1 -1
  56. package/dist/components/kritzel-font-size.js +1 -1
  57. package/dist/components/kritzel-font.js +1 -1
  58. package/dist/components/kritzel-icon.js +1 -1
  59. package/dist/components/kritzel-input.js +1 -1
  60. package/dist/components/kritzel-line-endings.js +1 -1
  61. package/dist/components/kritzel-login-dialog.js +1 -1
  62. package/dist/components/kritzel-master-detail.js +1 -1
  63. package/dist/components/kritzel-menu-item.js +1 -1
  64. package/dist/components/kritzel-menu.js +1 -1
  65. package/dist/components/kritzel-more-menu.js +1 -1
  66. package/dist/components/kritzel-numeric-input.js +1 -1
  67. package/dist/components/kritzel-opacity-slider.js +1 -1
  68. package/dist/components/kritzel-pill-tabs.js +1 -1
  69. package/dist/components/kritzel-portal.js +1 -1
  70. package/dist/components/kritzel-settings.js +1 -1
  71. package/dist/components/kritzel-shape-fill.js +1 -1
  72. package/dist/components/kritzel-share-dialog.js +1 -1
  73. package/dist/components/kritzel-slide-toggle.js +1 -1
  74. package/dist/components/kritzel-split-button.js +1 -1
  75. package/dist/components/kritzel-stroke-size.js +1 -1
  76. package/dist/components/kritzel-tool-config.js +1 -1
  77. package/dist/components/kritzel-tooltip.js +1 -1
  78. package/dist/components/kritzel-utility-panel.js +1 -1
  79. package/dist/components/kritzel-workspace-manager.js +1 -1
  80. package/dist/components/p-2xYAGd0I.js +1 -0
  81. package/dist/components/{p-DdmJquQr.js → p-B2Os1ya_.js} +1 -1
  82. package/dist/components/p-B2w8X7vn.js +1 -0
  83. package/dist/components/{p-DRB3TZzI.js → p-B4b6TDxp.js} +1 -1
  84. package/dist/components/p-B5xxfwKF.js +1 -0
  85. package/dist/components/{p-D0aom7Yu.js → p-BFYtCsZu.js} +1 -1
  86. package/dist/components/{p-CARNM9pf.js → p-BFoK4W--.js} +1 -1
  87. package/dist/components/p-BTEV1WwT.js +1 -0
  88. package/dist/components/{p-x38RbGJA.js → p-BYmp9Ovv.js} +1 -1
  89. package/dist/components/{p-KVG5rztB.js → p-BbactVA0.js} +1 -1
  90. package/dist/components/{p-B_JH91jB.js → p-BfNHpqQ8.js} +1 -1
  91. package/dist/components/{p-DXgUuzXW.js → p-BiG1dxPS.js} +1 -1
  92. package/dist/components/{p-Dov3qOAR.js → p-Bj2laX89.js} +1 -1
  93. package/dist/components/{p-Cr7xOsIZ.js → p-BqwqGFQY.js} +1 -1
  94. package/dist/components/{p-DmTG0Y5h.js → p-BzYU3-MJ.js} +1 -1
  95. package/dist/components/p-C0TN5IAi.js +1 -0
  96. package/dist/components/{p-RnuCSIt-.js → p-C2SX-XRr.js} +1 -1
  97. package/dist/components/{p-guqEWGgV.js → p-CFgkUYoO.js} +1 -1
  98. package/dist/components/{p-BTSOqHMI.js → p-CHrSFOSI.js} +1 -1
  99. package/dist/components/p-CJOhfMU5.js +1 -0
  100. package/dist/components/p-CLLbE_z8.js +9 -0
  101. package/dist/components/{p-DJLJfKY2.js → p-COLHjboZ.js} +1 -1
  102. package/dist/components/{p-CKY7AvGR.js → p-COgo9OWy.js} +1 -1
  103. package/dist/components/p-CUPYGT8c.js +1 -0
  104. package/dist/components/{p-DhAM4qeQ.js → p-CXpv9Rxe.js} +1 -1
  105. package/dist/components/{p-Bp3kdH4l.js → p-CcyIAi9S.js} +1 -1
  106. package/dist/components/{p-COIxq81R.js → p-CmuNn1Tc.js} +1 -1
  107. package/dist/components/{p-DfH7YY2C.js → p-D-sRVAbQ.js} +1 -1
  108. package/dist/components/{p-ZgZqbJ58.js → p-DDYoDSrm.js} +1 -1
  109. package/dist/components/{p-u0b2RJAn.js → p-DEy7zJCe.js} +1 -1
  110. package/dist/components/{p-BPEn0_hr.js → p-DM11KXUT.js} +1 -1
  111. package/dist/components/{p-CJERvHdy.js → p-DbB730vO.js} +1 -1
  112. package/dist/components/{p-C8ggg-5h.js → p-Df3BwVGy.js} +1 -1
  113. package/dist/components/{p-EFyZdR89.js → p-DkaiWg1V.js} +1 -1
  114. package/dist/components/{p-Dx_xz_El.js → p-DlwYHzSj.js} +1 -1
  115. package/dist/components/{p-CJ2V42sz.js → p-FK7b3BGt.js} +1 -1
  116. package/dist/components/{p-Do4UlU4e.js → p-J9_SwObO.js} +1 -1
  117. package/dist/components/{p-CxtTuKCy.js → p-JhOYwUOj.js} +1 -1
  118. package/dist/components/{p-Dw9sKOsb.js → p-SptaSMno.js} +1 -1
  119. package/dist/components/{p-KjtNlFTl.js → p-UoPj5QjH.js} +1 -1
  120. package/dist/components/{p-CYR9wbJg.js → p-dcAernE1.js} +1 -1
  121. package/dist/components/{p-BI_UUiTr.js → p-skWUIStn.js} +1 -1
  122. package/dist/components/{p-DgtrNOWm.js → p-x6doYeiI.js} +1 -1
  123. package/dist/esm/{index-D9HaikfQ.js → index-Dhio9uis.js} +1 -1
  124. package/dist/esm/index.js +42 -4
  125. package/dist/esm/kritzel-active-users_42.entry.js +281 -113
  126. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  127. package/dist/esm/loader.js +3 -3
  128. package/dist/esm/{schema.constants-BcT1vV4J.js → schema.constants-DiCnmIYK.js} +85 -42
  129. package/dist/esm/stencil.js +4 -4
  130. package/dist/stencil/index.esm.js +1 -1
  131. package/dist/stencil/p-DiCnmIYK.js +1 -0
  132. package/dist/stencil/p-ea76b21f.entry.js +9 -0
  133. package/dist/stencil/{p-69298b5f.entry.js → p-fb32cd8f.entry.js} +1 -1
  134. package/dist/stencil/stencil.esm.js +1 -1
  135. package/dist/types/classes/core/viewport.class.d.ts +38 -0
  136. package/dist/types/classes/objects/image.class.d.ts +15 -0
  137. package/dist/types/classes/tools/base-tool.class.d.ts +3 -0
  138. package/dist/types/classes/tools/brush-tool.class.d.ts +1 -0
  139. package/dist/types/classes/tools/eraser-tool.class.d.ts +1 -0
  140. package/dist/types/classes/tools/image-tool.class.d.ts +1 -0
  141. package/dist/types/classes/tools/line-tool.class.d.ts +1 -0
  142. package/dist/types/classes/tools/selection-tool.class.d.ts +1 -0
  143. package/dist/types/classes/tools/shape-tool.class.d.ts +1 -0
  144. package/dist/types/classes/tools/text-tool.class.d.ts +1 -0
  145. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +13 -3
  146. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +49 -5
  147. package/dist/types/components/ui/kritzel-context-menu/kritzel-context-menu.d.ts +1 -0
  148. package/dist/types/components.d.ts +54 -20
  149. package/dist/types/configs/default-asset-storage.config.d.ts +1 -1
  150. package/dist/types/configs/default-sync.config.d.ts +1 -1
  151. package/dist/types/constants/version.d.ts +1 -1
  152. package/dist/types/interfaces/theme.interface.d.ts +8 -3
  153. package/dist/types/interfaces/tool-config.interface.d.ts +3 -6
  154. package/dist/types/interfaces/tool-type.interface.d.ts +1 -0
  155. package/dist/types/interfaces/tool.interface.d.ts +1 -0
  156. package/dist/types/stencil-public-runtime.d.ts +1 -0
  157. package/package.json +1 -1
  158. package/dist/components/p-C0wFAtT_.js +0 -1
  159. package/dist/components/p-CWgI1dA0.js +0 -1
  160. package/dist/components/p-DH-H7om7.js +0 -1
  161. package/dist/components/p-DIiGd0LS.js +0 -1
  162. package/dist/components/p-DLh8x1jK.js +0 -9
  163. package/dist/components/p-Dqjil3Hm.js +0 -1
  164. package/dist/components/p-IiG44Unz.js +0 -1
  165. package/dist/components/p-K7ySy791.js +0 -1
  166. package/dist/stencil/p-0c95e585.entry.js +0 -9
  167. package/dist/stencil/p-BcT1vV4J.js +0 -1
  168. /package/dist/components/{p-BWj1eE2b.js → p-B43upypT.js} +0 -0
  169. /package/dist/stencil/{p-D9HaikfQ.js → p-Dhio9uis.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CFnj_FXt.js');
4
- var schema_constants = require('./schema.constants-CzfoUWxF.js');
3
+ var index = require('./index-Xav9JFHg.js');
4
+ var schema_constants = require('./schema.constants-DJQTjcy7.js');
5
5
  var Y = require('yjs');
6
6
  require('y-indexeddb');
7
7
  require('y-websocket');
@@ -629,7 +629,7 @@ const KritzelColorPalette = class {
629
629
  };
630
630
  KritzelColorPalette.style = kritzelColorPaletteCss();
631
631
 
632
- const kritzelContextMenuCss = () => `:host{display:block}.menu-container{display:flex;flex-direction:column;gap:var(--kritzel-context-menu-item-spacing, 2px);background-color:var(--kritzel-context-menu-background-color, #ffffff);border-radius:var(--kritzel-context-menu-border-radius, 12px);box-shadow:var(--kritzel-context-menu-box-shadow, 0 1px 6px rgba(0, 0, 0, 0.12));border:var(--kritzel-context-menu-border, 1px solid #ebebeb);padding:var(--kritzel-context-menu-padding, 4px);min-width:var(--kritzel-context-menu-min-width, 140px)}.menu-item-wrapper{position:relative}.menu-item{display:flex;align-items:center;gap:var(--kritzel-context-menu-item-gap, 8px);background:none;border:none;text-align:left;padding:var(--kritzel-context-menu-item-padding, 8px);border-radius:var(--kritzel-context-menu-item-border-radius, 12px);cursor:var(--kritzel-global-pointer-cursor, pointer);font-size:var(--kritzel-context-menu-item-font-size, 14px);color:var(--kritzel-context-menu-item-color, #333333);white-space:nowrap;-webkit-tap-highlight-color:transparent;width:100%}.menu-item:not(.disabled):hover,.menu-item.submenu-open{background-color:var(--kritzel-context-menu-item-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.menu-item:not(.disabled):active{background-color:var(--kritzel-context-menu-item-active-background-color, hsl(0, 0%, 0%, 8.6%))}.menu-item.disabled{color:var(--kritzel-context-menu-item-disabled-color, #aaaaaa)}.menu-item.has-children.disabled{cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-context-menu-item-color, #333333)}.menu-item kritzel-icon{opacity:0.8;flex-shrink:0}.menu-item.disabled kritzel-icon{opacity:0.4}.menu-item.has-children.disabled kritzel-icon{opacity:0.8}.label{flex-grow:1}.submenu-arrow{margin-left:auto;opacity:0.5}.menu-divider{height:1px;background-color:var(--kritzel-context-menu-divider-color, rgba(0, 0, 0, 0.1));margin:var(--kritzel-context-menu-divider-margin, 4px 8px)}.submenu-container{position:absolute;top:0;left:100%;margin-left:4px;display:flex;flex-direction:column;gap:var(--kritzel-context-menu-item-spacing, 2px);background-color:var(--kritzel-context-menu-background-color, #ffffff);border-radius:var(--kritzel-context-menu-border-radius, 12px);box-shadow:var(--kritzel-context-menu-box-shadow, 0 1px 6px rgba(0, 0, 0, 0.12));border:var(--kritzel-context-menu-border, 1px solid #ebebeb);padding:var(--kritzel-context-menu-padding, 4px);min-width:120px}.submenu-container.position-left{left:auto;right:100%;margin-left:0;margin-right:4px}`;
632
+ const kritzelContextMenuCss = () => `:host{display:block}.menu-container{position:relative;z-index:1;display:flex;flex-direction:column;gap:var(--kritzel-context-menu-item-spacing, 2px);background-color:var(--kritzel-context-menu-background-color, #ffffff);border-radius:var(--kritzel-context-menu-border-radius, 12px);box-shadow:var(--kritzel-context-menu-box-shadow, 0 1px 6px rgba(0, 0, 0, 0.12));border:var(--kritzel-context-menu-border, 1px solid #ebebeb);padding:var(--kritzel-context-menu-padding, 4px);min-width:var(--kritzel-context-menu-min-width, 140px)}.menu-item-wrapper{position:relative}.menu-item{display:flex;align-items:center;gap:var(--kritzel-context-menu-item-gap, 8px);background:none;border:none;text-align:left;padding:var(--kritzel-context-menu-item-padding, 8px);border-radius:var(--kritzel-context-menu-item-border-radius, 12px);cursor:var(--kritzel-global-pointer-cursor, pointer);font-size:var(--kritzel-context-menu-item-font-size, 14px);color:var(--kritzel-context-menu-item-color, #333333);white-space:nowrap;-webkit-tap-highlight-color:transparent;width:100%;min-width:0}.menu-item:not(.disabled):hover,.menu-item.submenu-open{background-color:var(--kritzel-context-menu-item-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.menu-item:not(.disabled):active{background-color:var(--kritzel-context-menu-item-active-background-color, hsl(0, 0%, 0%, 8.6%))}.menu-item.disabled{color:var(--kritzel-context-menu-item-disabled-color, #aaaaaa)}.menu-item.has-children.disabled{cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-context-menu-item-color, #333333)}.menu-item kritzel-icon{opacity:0.8;flex-shrink:0}.menu-item.disabled kritzel-icon{opacity:0.4}.menu-item.has-children.disabled kritzel-icon{opacity:0.8}.label{flex-grow:1;min-width:0;overflow:hidden;text-overflow:ellipsis}.submenu-arrow{margin-left:auto;opacity:0.5}.menu-divider{height:1px;background-color:var(--kritzel-context-menu-divider-color, rgba(0, 0, 0, 0.1));margin:var(--kritzel-context-menu-divider-margin, 4px 8px)}.submenu-container{position:absolute;top:0;left:100%;z-index:2;margin-left:4px;display:flex;flex-direction:column;gap:var(--kritzel-context-menu-item-spacing, 2px);background-color:var(--kritzel-context-menu-background-color, #ffffff);border-radius:var(--kritzel-context-menu-border-radius, 12px);box-shadow:var(--kritzel-context-menu-box-shadow, 0 1px 6px rgba(0, 0, 0, 0.12));border:var(--kritzel-context-menu-border, 1px solid #ebebeb);padding:var(--kritzel-context-menu-padding, 4px);min-width:120px}.submenu-container.position-left{left:auto;right:100%;margin-left:0;margin-right:4px}`;
633
633
 
634
634
  const VIEWPORT_PADDING = 8;
635
635
  const SUBMENU_DELAY = 150;
@@ -750,6 +750,11 @@ const KritzelContextMenu = class {
750
750
  const idx = path.lastIndexOf('.');
751
751
  return idx === -1 ? '' : path.substring(0, idx);
752
752
  }
753
+ getMenuDepth(path) {
754
+ if (!path)
755
+ return 0;
756
+ return path.split('.').length;
757
+ }
753
758
  pruneStaleRefs() {
754
759
  const openPaths = new Set(this.getOpenSubmenuPaths());
755
760
  for (const key of Array.from(this.submenuRefs.keys())) {
@@ -861,7 +866,8 @@ const KritzelContextMenu = class {
861
866
  }
862
867
  renderSubmenu(processedChildren, path) {
863
868
  const position = this.submenuPositions[path] === 'left' ? 'left' : 'right';
864
- return (index.h("div", { class: { 'submenu-container': true, 'position-left': position === 'left' }, key: `submenu-${path}`, ref: el => el && this.submenuRefs.set(path, el), onMouseEnter: () => this.handleSubmenuMouseEnter(), onMouseLeave: () => this.handleSubmenuMouseLeave(path) }, this.renderItems(processedChildren, path)));
869
+ const zIndex = this.getMenuDepth(path) + 1;
870
+ return (index.h("div", { class: { 'submenu-container': true, 'position-left': position === 'left' }, key: `submenu-${path}`, style: { zIndex: String(zIndex) }, ref: el => el && this.submenuRefs.set(path, el), onMouseEnter: () => this.handleSubmenuMouseEnter(), onMouseLeave: () => this.handleSubmenuMouseLeave(path) }, this.renderItems(processedChildren, path)));
865
871
  }
866
872
  render() {
867
873
  if (!this.processedItems || this.processedItems.length === 0) {
@@ -879,67 +885,65 @@ KritzelContextMenu.style = kritzelContextMenuCss();
879
885
 
880
886
  class KritzelToolConfigHelper {
881
887
  static getToolConfig(tool) {
882
- const toolConstructorName = tool?.constructor?.name;
883
- if (tool instanceof schema_constants.KritzelSelectionTool || toolConstructorName === 'KritzelSelectionTool') {
884
- return tool.getToolConfig();
885
- }
886
- if (tool instanceof schema_constants.KritzelBrushTool || toolConstructorName === 'KritzelBrushTool') {
887
- return {
888
- type: 'brush',
889
- colorProperty: 'color',
890
- sizeProperty: 'size',
891
- opacityProperty: 'opacity',
892
- paletteSource: 'palette',
893
- sizesSource: 'sizes',
894
- controls: [
895
- { type: 'stroke-size', propertyName: 'size' },
896
- ],
897
- };
898
- }
899
- if (tool instanceof schema_constants.KritzelLineTool || toolConstructorName === 'KritzelLineTool') {
900
- return {
901
- type: 'line',
902
- colorProperty: 'color',
903
- sizeProperty: 'size',
904
- opacityProperty: 'opacity',
905
- paletteSource: 'palette',
906
- sizesSource: 'sizes',
907
- controls: [
908
- { type: 'stroke-size', propertyName: 'size' },
909
- { type: 'line-endings', propertyName: 'arrows', additionalProps: {} },
910
- ],
911
- };
912
- }
913
- if (tool instanceof schema_constants.KritzelShapeTool || toolConstructorName === 'KritzelShapeTool') {
914
- return {
915
- type: 'shape',
916
- colorProperty: 'strokeColor',
917
- sizeProperty: 'strokeWidth',
918
- opacityProperty: 'opacity',
919
- paletteSource: 'palette',
920
- sizesSource: 'sizes',
921
- controls: [
922
- { type: 'stroke-size', propertyName: 'strokeWidth' },
923
- { type: 'shape-fill', propertyName: 'fillColor', additionalProps: {} },
924
- ],
925
- };
926
- }
927
- if (tool instanceof schema_constants.KritzelTextTool || toolConstructorName === 'KritzelTextTool') {
928
- return {
929
- type: 'text',
930
- colorProperty: 'fontColor',
931
- sizeProperty: 'fontSize',
932
- opacityProperty: 'opacity',
933
- paletteSource: 'palette',
934
- sizesSource: 'sizes',
935
- controls: [
936
- { type: 'font-size', propertyName: 'fontSize', additionalProps: {} },
937
- { type: 'font-family', propertyName: 'fontFamily' },
938
- ],
939
- };
888
+ switch (tool?.toolType) {
889
+ case 'selection':
890
+ return 'getToolConfig' in tool && typeof tool.getToolConfig === 'function'
891
+ ? tool.getToolConfig()
892
+ : null;
893
+ case 'brush':
894
+ return {
895
+ type: 'brush',
896
+ colorProperty: 'color',
897
+ sizeProperty: 'size',
898
+ opacityProperty: 'opacity',
899
+ paletteSource: 'palette',
900
+ sizesSource: 'sizes',
901
+ controls: [
902
+ { type: 'stroke-size', propertyName: 'size' },
903
+ ],
904
+ };
905
+ case 'line':
906
+ return {
907
+ type: 'line',
908
+ colorProperty: 'color',
909
+ sizeProperty: 'size',
910
+ opacityProperty: 'opacity',
911
+ paletteSource: 'palette',
912
+ sizesSource: 'sizes',
913
+ controls: [
914
+ { type: 'stroke-size', propertyName: 'size' },
915
+ { type: 'line-endings', propertyName: 'arrows', additionalProps: {} },
916
+ ],
917
+ };
918
+ case 'shape':
919
+ return {
920
+ type: 'shape',
921
+ colorProperty: 'strokeColor',
922
+ sizeProperty: 'strokeWidth',
923
+ opacityProperty: 'opacity',
924
+ paletteSource: 'palette',
925
+ sizesSource: 'sizes',
926
+ controls: [
927
+ { type: 'stroke-size', propertyName: 'strokeWidth' },
928
+ { type: 'shape-fill', propertyName: 'fillColor', additionalProps: {} },
929
+ ],
930
+ };
931
+ case 'text':
932
+ return {
933
+ type: 'text',
934
+ colorProperty: 'fontColor',
935
+ sizeProperty: 'fontSize',
936
+ opacityProperty: 'opacity',
937
+ paletteSource: 'palette',
938
+ sizesSource: 'sizes',
939
+ controls: [
940
+ { type: 'font-size', propertyName: 'fontSize', additionalProps: {} },
941
+ { type: 'font-family', propertyName: 'fontFamily' },
942
+ ],
943
+ };
944
+ default:
945
+ return null;
940
946
  }
941
- // Tool is not configurable (e.g., selection, eraser, image)
942
- return null;
943
947
  }
944
948
  }
945
949
 
@@ -1898,7 +1902,7 @@ const KritzelDialog = class {
1898
1902
  };
1899
1903
  KritzelDialog.style = kritzelDialogCss();
1900
1904
 
1901
- const kritzelDropdownCss = () => `:host{display:inline-flex;vertical-align:middle;width:100%;position:relative}.dropdown-wrapper{display:flex;align-items:center;border:1px solid var(--kritzel-dropdown-border-color, #ebebeb);border-radius:6px;overflow:visible;height:38px;width:100%;position:relative}.dropdown-wrapper:hover:not(:focus-within){border-color:var(--kritzel-dropdown-hover-border-color, #cccccc)}.dropdown-container{flex:1;height:100%;min-width:0}.dropdown-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 8px;height:100%;width:100%;box-sizing:border-box;border-radius:6px;border:none;background-color:var(--kritzel-dropdown-background, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);outline:none;font-size:inherit;font-family:inherit;color:var(--kritzel-dropdown-text-color, #333333);-webkit-tap-highlight-color:transparent;text-align:left}.dropdown-trigger:focus-visible{outline:revert}.dropdown-trigger.has-suffix-border{border-right:1px solid var(--kritzel-global-border-color, #ebebeb);border-top-right-radius:0;border-bottom-right-radius:0}.dropdown-trigger.has-prefix-border{border-left:1px solid var(--kritzel-global-border-color, #ebebeb);border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-trigger-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.dropdown-trigger-arrow{display:flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;transition:transform 0.2s ease}.dropdown-trigger-arrow svg{width:100%;height:100%}.dropdown-trigger.is-open .dropdown-trigger-arrow{transform:rotate(180deg)}.dropdown-trigger.is-open.open-up .dropdown-trigger-arrow{transform:rotate(0deg)}.dropdown-menu{position:absolute;left:0;right:0;margin:0;padding:4px 0;list-style:none;background-color:var(--kritzel-dropdown-background, #ffffff);border:1px solid var(--kritzel-global-border-color, #ebebeb);border-radius:6px;box-shadow:var(--kritzel-controls-box-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));z-index:1000;max-height:240px;overflow-y:auto;opacity:0;visibility:hidden;transition:opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;outline:none}.dropdown-menu.open-down{top:calc(100% + 4px);bottom:auto;transform:translateY(-8px)}.dropdown-menu.open-up{bottom:calc(100% + 4px);top:auto;transform:translateY(8px)}.dropdown-menu.is-open{opacity:1;visibility:inherit;transform:translateY(0)}.dropdown-menu.open-up{box-shadow:var(--kritzel-controls-box-shadow, 0 -4px 12px rgba(0, 0, 0, 0.15))}.dropdown-option{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 12px;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-dropdown-text-color, #333333);transition:background-color 0.1s ease;-webkit-tap-highlight-color:transparent}.dropdown-option.is-focused{background-color:var(--kritzel-dropdown-hover-background-color, #f0f0f0)}.dropdown-option.is-selected{font-weight:600;background-color:var(--kritzel-dropdown-selected-background-color, #007bff1a)}.dropdown-option-check{display:flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;color:var(--kritzel-dropdown-accent-color, #007bff)}.dropdown-option-check svg{width:100%;height:100%}.dropdown-menu{scrollbar-color:var(--kritzel-global-scrollbar-thumb-color, #ebebeb) transparent;scrollbar-width:thin}::slotted(*){height:100%;box-sizing:border-box}`;
1905
+ const kritzelDropdownCss = () => `:host{display:inline-flex;vertical-align:middle;width:100%;position:relative}.dropdown-wrapper{display:flex;align-items:center;border:1px solid var(--kritzel-dropdown-border-color, #ebebeb);border-radius:var(--kritzel-dropdown-border-radius, 6px);overflow:visible;height:38px;width:100%;position:relative}.dropdown-wrapper:hover:not(:focus-within){border-color:var(--kritzel-dropdown-hover-border-color, #cccccc)}.dropdown-container{flex:1;height:100%;min-width:0}.dropdown-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 8px;height:100%;width:100%;box-sizing:border-box;border-radius:var(--kritzel-dropdown-border-radius, 6px);border:none;background-color:var(--kritzel-dropdown-background, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);outline:none;font-size:inherit;font-family:inherit;color:var(--kritzel-dropdown-text-color, #333333);-webkit-tap-highlight-color:transparent;text-align:left}.dropdown-trigger:focus-visible{outline:revert}.dropdown-trigger.has-suffix-border{border-right:1px solid var(--kritzel-global-border-color, #ebebeb);border-top-right-radius:0;border-bottom-right-radius:0}.dropdown-trigger.has-prefix-border{border-left:1px solid var(--kritzel-global-border-color, #ebebeb);border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-trigger-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.dropdown-trigger-arrow{display:flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;transition:transform 0.2s ease}.dropdown-trigger-arrow svg{width:100%;height:100%}.dropdown-trigger.is-open .dropdown-trigger-arrow{transform:rotate(180deg)}.dropdown-trigger.is-open.open-up .dropdown-trigger-arrow{transform:rotate(0deg)}.dropdown-menu{position:absolute;left:0;right:0;margin:0;padding:4px 0;list-style:none;background-color:var(--kritzel-dropdown-background, #ffffff);border:1px solid var(--kritzel-global-border-color, #ebebeb);border-radius:var(--kritzel-dropdown-menu-border-radius, var(--kritzel-dropdown-border-radius, 6px));box-shadow:var(--kritzel-controls-box-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));z-index:1000;max-height:240px;overflow-y:auto;opacity:0;visibility:hidden;transition:opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;outline:none}.dropdown-menu.open-down{top:calc(100% + 4px);bottom:auto;transform:translateY(-8px)}.dropdown-menu.open-up{bottom:calc(100% + 4px);top:auto;transform:translateY(8px)}.dropdown-menu.is-open{opacity:1;visibility:inherit;transform:translateY(0)}.dropdown-menu.open-up{box-shadow:var(--kritzel-controls-box-shadow, 0 -4px 12px rgba(0, 0, 0, 0.15))}.dropdown-option{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 12px;cursor:var(--kritzel-global-pointer-cursor, pointer);color:var(--kritzel-dropdown-text-color, #333333);transition:background-color 0.1s ease;-webkit-tap-highlight-color:transparent}.dropdown-option.is-focused{background-color:var(--kritzel-dropdown-hover-background-color, #f0f0f0)}.dropdown-option.is-selected{font-weight:600;background-color:var(--kritzel-dropdown-selected-background-color, #007bff1a)}.dropdown-option-check{display:flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;color:var(--kritzel-dropdown-accent-color, #007bff)}.dropdown-option-check svg{width:100%;height:100%}.dropdown-menu{scrollbar-color:var(--kritzel-global-scrollbar-thumb-color, #ebebeb) transparent;scrollbar-width:thin}::slotted(*){height:100%;box-sizing:border-box}`;
1902
1906
 
1903
1907
  const KritzelDropdown = class {
1904
1908
  constructor(hostRef) {
@@ -2175,12 +2179,10 @@ const ABSOLUTE_SCALE_MAX = 1000;
2175
2179
  const ABSOLUTE_SCALE_MIN = 0.0001;
2176
2180
 
2177
2181
  /**
2178
- * Default sync configuration - IndexedDB
2182
+ * Default sync configuration - None
2179
2183
  */
2180
2184
  const DEFAULT_SYNC_CONFIG = {
2181
- providers: [
2182
- schema_constants.IndexedDBSyncProvider
2183
- ],
2185
+ providers: [],
2184
2186
  };
2185
2187
 
2186
2188
  const kritzelEditorCss = () => `kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:start;line-height:normal}kritzel-controls{position:absolute;left:0;right:0;margin-inline:auto;width:max-content;max-width:calc(100% - 16px);bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}.top-left-buttons{position:absolute;top:var(--kritzel-editor-top-left-buttons-top, 14px);left:var(--kritzel-editor-top-left-buttons-left, 14px);display:flex;align-items:flex-start;gap:8px}.top-right-buttons{position:absolute;top:var(--kritzel-editor-top-right-buttons-top, 14px);right:var(--kritzel-editor-top-right-buttons-right, 14px);display:flex;align-items:center;gap:8px}.top-right-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;padding:0;border:var(--kritzel-split-button-border, 1px solid #ebebeb);border-radius:var(--kritzel-split-button-border-radius, 12px);background-color:var(--kritzel-split-button-background-color, #ffffff);cursor:var(--kritzel-global-pointer-cursor, pointer);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));transition:background-color 150ms ease;-webkit-tap-highlight-color:transparent}.top-right-button:hover{background-color:#f5f5f5}.top-right-button:active{background-color:#ebebeb}`;
@@ -2372,15 +2374,7 @@ const KritzelEditor = class {
2372
2374
  /** The element to use as the target for the cursor. Defaults to the editor container if not set. */
2373
2375
  cursorTarget;
2374
2376
  /** Optional login configuration. When provided, a "Sign in" button is shown that opens a login dialog with the configured providers. */
2375
- loginConfig = {
2376
- providers: [
2377
- {
2378
- label: 'Sign in with Google',
2379
- icon: 'google',
2380
- name: 'Google',
2381
- },
2382
- ],
2383
- };
2377
+ loginConfig;
2384
2378
  /** Whether the editor is in a loading state. When true, a loading overlay is displayed. */
2385
2379
  isLoading = false;
2386
2380
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
@@ -2509,12 +2503,18 @@ const KritzelEditor = class {
2509
2503
  async centerObjectInViewport(object) {
2510
2504
  return this.engineRef.centerObjectInViewport(object);
2511
2505
  }
2506
+ async panToObject(object) {
2507
+ return this.engineRef.panToObject(object);
2508
+ }
2512
2509
  async backToContent() {
2513
2510
  return this.engineRef.backToContent();
2514
2511
  }
2515
2512
  async centerAllObjects(animate = true) {
2516
2513
  return this.engineRef.centerAllObjects(animate);
2517
2514
  }
2515
+ async centerObjects(objects, animate = true) {
2516
+ return this.engineRef.centerObjects(objects, animate);
2517
+ }
2518
2518
  async setViewport(x, y, scale) {
2519
2519
  return this.engineRef.setViewport(x, y, scale);
2520
2520
  }
@@ -2524,6 +2524,12 @@ const KritzelEditor = class {
2524
2524
  async zoomTo(scale, worldX, worldY) {
2525
2525
  return this.engineRef.zoomTo(scale, worldX, worldY);
2526
2526
  }
2527
+ async zoomIn(factor = 1.6, duration = 200) {
2528
+ return this.engineRef.zoomIn(factor, duration);
2529
+ }
2530
+ async zoomOut(factor = 1.6, duration = 200) {
2531
+ return this.engineRef.zoomOut(factor, duration);
2532
+ }
2527
2533
  async getViewport() {
2528
2534
  return this.engineRef.getViewport();
2529
2535
  }
@@ -2609,14 +2615,14 @@ const KritzelEditor = class {
2609
2615
  async redo() {
2610
2616
  return this.engineRef.redo();
2611
2617
  }
2612
- async getScreenshot(format = 'png') {
2613
- return this.engineRef.getScreenshot(format);
2618
+ async getScreenshot(format = 'png', options) {
2619
+ return this.engineRef.getScreenshot(format, options);
2614
2620
  }
2615
- async exportViewportAsPng() {
2616
- return this.engineRef.exportViewportAsPng();
2621
+ async exportViewportAsPng(options) {
2622
+ return this.engineRef.exportViewportAsPng(options);
2617
2623
  }
2618
- async exportViewportAsSvg() {
2619
- return this.engineRef.exportViewportAsSvg();
2624
+ async exportViewportAsSvg(options) {
2625
+ return this.engineRef.exportViewportAsSvg(options);
2620
2626
  }
2621
2627
  async exportSelectedObjectsAsPng() {
2622
2628
  return this.engineRef.exportSelectedObjectsAsPng();
@@ -2968,31 +2974,31 @@ const KritzelEditor = class {
2968
2974
  const isLoggedIn = this.isLoggedIn;
2969
2975
  const shouldShowCurrentUser = isLoggedIn;
2970
2976
  const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
2971
- return (index.h(index.Host, { key: '440621eb23598732c63d4be92ae16785d84b3d6f', style: {
2977
+ return (index.h(index.Host, { key: 'ffacaea5d3df12a3a8b448d31db3c5949053156c', style: {
2972
2978
  opacity: this.isEditorVisible ? '1' : '0',
2973
2979
  visibility: this.isEditorVisible ? 'visible' : 'hidden',
2974
2980
  transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
2975
- } }, index.h("div", { key: 'b20c930c8094f7ab9db8fdb09428cf34a2cab024', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: 'a6ff7e54fb3d45f4a3b1d009b12d2f6229d14d87', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'a3cbb86082c2f0768b7457ec25740d27200e287b', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '82e611de33c40997943e1fd702f0b601fadbf591', ref: el => {
2981
+ } }, index.h("div", { key: '669eafee25b4f84c39469738a1337c21ab03e388', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: 'd6feb4a71c3286830fbe53a533f283c8af9a0385', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: '5bd0e6263d51119b197292b69879c1ae437f92fc', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), index.h("kritzel-engine", { key: '468f17137c51c90fd61c9179d13c449b1ac8feb9', ref: el => {
2976
2982
  if (el) {
2977
2983
  this.engineRef = el;
2978
2984
  }
2979
- }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.theme, themes: this.themes, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: 'eb48df395318bde3fc0bc48784510bf5139bc9e8', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
2985
+ }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, wheelEnabled: this.wheelEnabled, theme: this.theme, themes: this.themes, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event) }), index.h("kritzel-controls", { key: '848c30b27fb916c8480b41745bd6ec844e0b23a2', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
2980
2986
  if (el) {
2981
2987
  this.controlsRef = el;
2982
2988
  }
2983
- }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: '1259089ca70c634621f7e2db274868b12a3e5e8a', class: "top-right-buttons" }, index.h("kritzel-settings", { key: 'b38b01040714827a5d824694b481edb8094eafd8', ref: el => {
2989
+ }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'e998d60679c767d15617bd7ecde5ee77e781a92f', class: "top-right-buttons" }, index.h("kritzel-settings", { key: '43b9cdb2d10de789cc03d2a9ef5df870b8ca7bfe', ref: el => {
2984
2990
  if (el) {
2985
2991
  this.settingsRef = el;
2986
2992
  }
2987
- }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], settings: this.currentSettingsConfig, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: 'a678999cac4f3618c44d1340b6905ec2f3061dd5', ref: el => {
2993
+ }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], settings: this.currentSettingsConfig, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: '74669624a1e5177125ef00e1667c880ce47cbce4', ref: el => {
2988
2994
  if (el) {
2989
2995
  this.exportRef = el;
2990
2996
  }
2991
- }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '7d0b70c7347e7fda4e96a59b27b8fb6c2eb77f49', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: 'ed364648df937fb1e84d850953fee51f6e54e95e', user: this.user }), shouldShowLoginButton && (index.h("kritzel-button", { key: 'dd24afa0746a311ac4a27000281fef28bddf844a', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in")), index.h("kritzel-more-menu", { key: '713da1a5313809083470a8a23c0531e9e198c4bd', items: this.moreMenuItems, visible: this.isMoreMenuVisible }), index.h("kritzel-share-dialog", { key: '37f80fdb7b1087926b72ece7693f816c9f85f746', ref: el => {
2997
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '18d925f32d021ff6713accb22d0594d259d70f2e', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: 'bddd5c29c5f17cced47276c237c04cfdb711da38', user: this.user }), shouldShowLoginButton && (index.h("kritzel-button", { key: '4eb6c85459f59863d6e644ecf21c2295da71bafc', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in")), index.h("kritzel-more-menu", { key: 'a5a323ec248bebc7bc07898f344e0926fac8db17', items: this.moreMenuItems, visible: this.isMoreMenuVisible }), index.h("kritzel-share-dialog", { key: '8cb3ddad95d36f5b7ad59d8c4f057df93cb2bfe3', ref: el => {
2992
2998
  if (el) {
2993
2999
  this.shareDialogRef = el;
2994
3000
  }
2995
- }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'f5b59522082824bc236784a9083f1d425852d487', ref: el => {
3001
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: '35395d0faadcfeb021fba685aa46e180e47d2be2', ref: el => {
2996
3002
  if (el) {
2997
3003
  this.loginDialogRef = el;
2998
3004
  }
@@ -20679,6 +20685,87 @@ class KritzelViewport {
20679
20685
  this.setViewport(centerWorldX, centerWorldY, scale);
20680
20686
  }
20681
20687
  }
20688
+ /**
20689
+ * Zooms in by a fixed step, centered on the current viewport center,
20690
+ * with a smooth animation. The resulting scale is clamped to the allowed range.
20691
+ * @param factor - Multiplicative zoom-in step
20692
+ * @param duration - Animation duration in milliseconds
20693
+ */
20694
+ zoomIn(factor, duration) {
20695
+ this.animateZoomAroundViewportCenter(factor, duration);
20696
+ }
20697
+ /**
20698
+ * Zooms out by a fixed step, centered on the current viewport center,
20699
+ * with a smooth animation. The resulting scale is clamped to the allowed range.
20700
+ * @param factor - Multiplicative zoom-out step
20701
+ * @param duration - Animation duration in milliseconds
20702
+ */
20703
+ zoomOut(factor, duration) {
20704
+ this.animateZoomAroundViewportCenter(1 / factor, duration);
20705
+ }
20706
+ /**
20707
+ * Smoothly zooms around the viewport center, keeping the center world point
20708
+ * fixed for the entire animation. The translation is recomputed from the fixed
20709
+ * center point on every frame (rather than interpolated independently), which
20710
+ * guarantees the center never drifts and the viewport does not jump.
20711
+ * The resulting scale is clamped to the allowed range and the translation is
20712
+ * clamped to the viewport boundaries.
20713
+ * @param scaleFactor - Multiplicative scale factor (>1 zooms in, <1 zooms out)
20714
+ * @param duration - Animation duration in milliseconds
20715
+ */
20716
+ animateZoomAroundViewportCenter(scaleFactor, duration) {
20717
+ this.cancelViewportAnimation();
20718
+ const state = this._core.store.state;
20719
+ const startScale = state.scale;
20720
+ const effectiveMinScale = this.getEffectiveMinScale();
20721
+ const targetScale = Math.min(state.scaleMax, Math.max(effectiveMinScale, startScale * scaleFactor));
20722
+ // The world point currently under the viewport center stays fixed.
20723
+ const centerScreenX = state.viewportWidth / 2;
20724
+ const centerScreenY = state.viewportHeight / 2;
20725
+ const centerWorldX = (centerScreenX - state.translateX) / startScale;
20726
+ const centerWorldY = (centerScreenY - state.translateY) / startScale;
20727
+ if (targetScale === startScale || duration <= 0) {
20728
+ this.applyZoomAroundCenter(targetScale, centerScreenX, centerScreenY, centerWorldX, centerWorldY);
20729
+ state.isScaling = true;
20730
+ this._core.rerender();
20731
+ this._debounceUpdate();
20732
+ this._debounceEndScaling();
20733
+ return;
20734
+ }
20735
+ const startTime = performance.now();
20736
+ state.isScaling = true;
20737
+ const animate = (currentTime) => {
20738
+ const elapsed = currentTime - startTime;
20739
+ const progress = Math.min(elapsed / duration, 1);
20740
+ // easeInOutCubic for a smooth ramp in and out
20741
+ const eased = progress < 0.5 ? 4 * progress * progress * progress : 1 - Math.pow(-2 * progress + 2, 3) / 2;
20742
+ const frameScale = startScale + (targetScale - startScale) * eased;
20743
+ this.applyZoomAroundCenter(frameScale, centerScreenX, centerScreenY, centerWorldX, centerWorldY);
20744
+ this._core.rerender();
20745
+ if (progress < 1) {
20746
+ this._animationFrameId = requestAnimationFrame(animate);
20747
+ }
20748
+ else {
20749
+ this._animationFrameId = null;
20750
+ state.isScaling = false;
20751
+ this._core.rerender();
20752
+ this._debounceUpdate();
20753
+ }
20754
+ };
20755
+ this._animationFrameId = requestAnimationFrame(animate);
20756
+ }
20757
+ /**
20758
+ * Applies a single zoom step that keeps the given world point anchored to the
20759
+ * given screen point at the specified scale, clamped to the viewport boundaries.
20760
+ */
20761
+ applyZoomAroundCenter(scale, screenX, screenY, worldX, worldY) {
20762
+ const state = this._core.store.state;
20763
+ state.scale = scale;
20764
+ const clamped = this.clampTranslate(screenX - worldX * scale, screenY - worldY * scale);
20765
+ state.translateX = clamped.translateX;
20766
+ state.translateY = clamped.translateY;
20767
+ state.hasViewportChanged = true;
20768
+ }
20682
20769
  /**
20683
20770
  * Centers a given object in the viewport without changing the scale.
20684
20771
  * The object's center point will be positioned at the viewport center.
@@ -20935,22 +21022,21 @@ class KritzelViewport {
20935
21022
  return true;
20936
21023
  }
20937
21024
  /**
20938
- * Centers and fits ALL objects in the viewport, including objects not currently rendered.
20939
- * Calculates the combined bounding box of all objects and optionally animates the viewport to show them.
21025
+ * Centers and fits the provided objects in the viewport.
21026
+ * Calculates the combined bounding box of the provided objects and optionally animates the viewport to show them.
21027
+ * @param objects - Objects to include in the fit operation.
20940
21028
  * @param animate - Whether to animate the viewport transition (default: true)
20941
- * @returns true if objects were found and viewport was adjusted, false if no objects exist
21029
+ * @returns true if at least one object was provided and viewport was adjusted, false otherwise
20942
21030
  */
20943
- centerFitAllObjects(animate = true) {
20944
- const allObjects = this._core.store.allNonSelectionObjects;
20945
- if (allObjects.length === 0) {
21031
+ centerFitObjects(objects, animate = true) {
21032
+ if (objects.length === 0) {
20946
21033
  return false;
20947
21034
  }
20948
- // Calculate combined bounds of all objects
20949
21035
  let minX = Infinity;
20950
21036
  let minY = Infinity;
20951
21037
  let maxX = -Infinity;
20952
21038
  let maxY = -Infinity;
20953
- for (const obj of allObjects) {
21039
+ for (const obj of objects) {
20954
21040
  const bounds = obj.rotatedBoundingBox;
20955
21041
  minX = Math.min(minX, bounds.x);
20956
21042
  minY = Math.min(minY, bounds.y);
@@ -20973,6 +21059,15 @@ class KritzelViewport {
20973
21059
  this.animateViewportTo(targetTranslateX, targetTranslateY, clampedScale, animate ? 150 : 0);
20974
21060
  return true;
20975
21061
  }
21062
+ /**
21063
+ * Centers and fits ALL objects in the viewport, including objects not currently rendered.
21064
+ * Calculates the combined bounding box of all objects and optionally animates the viewport to show them.
21065
+ * @param animate - Whether to animate the viewport transition (default: true)
21066
+ * @returns true if objects were found and viewport was adjusted, false if no objects exist
21067
+ */
21068
+ centerFitAllObjects(animate = true) {
21069
+ return this.centerFitObjects(this._core.store.allNonSelectionObjects, animate);
21070
+ }
20976
21071
  }
20977
21072
 
20978
21073
  /** The amount of pixels to move an object when using arrow key nudging. */
@@ -26497,8 +26592,18 @@ const KritzelEngine = class {
26497
26592
  }
26498
26593
  /** Context menu items shown when right-clicking the canvas background. */
26499
26594
  globalContextMenuItems;
26595
+ onGlobalContextMenuItemsChange(newValue) {
26596
+ if (this.contextMenuHandler) {
26597
+ this.contextMenuHandler.globalContextMenuItems = newValue ?? [];
26598
+ }
26599
+ }
26500
26600
  /** Context menu items shown when right-clicking a selected object. */
26501
26601
  objectContextMenuItems;
26602
+ onObjectContextMenuItemsChange(newValue) {
26603
+ if (this.contextMenuHandler) {
26604
+ this.contextMenuHandler.objectContextMenuItems = newValue ?? [];
26605
+ }
26606
+ }
26502
26607
  /** Maximum zoom scale allowed. Clamped to the absolute maximum defined by the engine. */
26503
26608
  scaleMax = ABSOLUTE_SCALE_MAX;
26504
26609
  validateScaleMax(newValue) {
@@ -26975,6 +27080,9 @@ const KritzelEngine = class {
26975
27080
  object.scale = object.scale ?? this.core.store.state.scale;
26976
27081
  object.zIndex = this.core.store.currentZIndex;
26977
27082
  object.workspaceId = this.core.store.state.activeWorkspace.id;
27083
+ if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
27084
+ await object.prepareForInsert();
27085
+ }
26978
27086
  // Handle KritzelText: recreate the editor now that _core is available
26979
27087
  // The editor's dispatchTransaction callback needs _core for persisting changes
26980
27088
  if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
@@ -27059,6 +27167,12 @@ const KritzelEngine = class {
27059
27167
  if (objects.length === 0) {
27060
27168
  return [];
27061
27169
  }
27170
+ for (const object of objects) {
27171
+ object._core = this.core;
27172
+ if (schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
27173
+ await object.prepareForInsert();
27174
+ }
27175
+ }
27062
27176
  this.core.store.objects.transaction(() => {
27063
27177
  for (const object of objects) {
27064
27178
  object.id = object.generateId();
@@ -27223,6 +27337,14 @@ const KritzelEngine = class {
27223
27337
  this.core.rerender();
27224
27338
  return object;
27225
27339
  }
27340
+ /**
27341
+ * Pans the viewport to center on the given object without changing the zoom level.
27342
+ * Unlike `centerObjectInViewport`, this moves the camera — not the object.
27343
+ * @param object - The object whose center the viewport should pan to.
27344
+ */
27345
+ async panToObject(object) {
27346
+ this.viewport.panTo(object.centerX, object.centerY);
27347
+ }
27226
27348
  /**
27227
27349
  * Pans and zooms the viewport to fit the nearest content, with padding.
27228
27350
  * Useful when the user has panned away from all objects.
@@ -27240,6 +27362,16 @@ const KritzelEngine = class {
27240
27362
  async centerAllObjects(animate = true) {
27241
27363
  return this.viewport.centerFitAllObjects(animate);
27242
27364
  }
27365
+ /**
27366
+ * Pans and zooms the viewport to fit the provided objects.
27367
+ * Calculates the combined bounding box of the given objects and centers the viewport to show them.
27368
+ * @param objects - The objects to center and fit in the viewport.
27369
+ * @param animate - Whether to animate the viewport transition (default: true).
27370
+ * @returns `true` if objects were provided and the viewport was adjusted, `false` otherwise.
27371
+ */
27372
+ async centerObjects(objects, animate = true) {
27373
+ return this.viewport.centerFitObjects(objects, animate);
27374
+ }
27243
27375
  /**
27244
27376
  * Sets the viewport to center on the given world coordinates at the specified scale.
27245
27377
  * @param x - X position in world coordinates to center on.
@@ -27267,6 +27399,22 @@ const KritzelEngine = class {
27267
27399
  async zoomTo(scale, worldX, worldY) {
27268
27400
  this.viewport.zoomTo(scale, worldX, worldY);
27269
27401
  }
27402
+ /**
27403
+ * Zooms in by a fixed step, centered on the current viewport center, with a smooth animation.
27404
+ * @param factor - Multiplicative zoom-in step.
27405
+ * @param duration - Animation duration in milliseconds.
27406
+ */
27407
+ async zoomIn(factor, duration) {
27408
+ this.viewport.zoomIn(factor, duration);
27409
+ }
27410
+ /**
27411
+ * Zooms out by a fixed step, centered on the current viewport center, with a smooth animation.
27412
+ * @param factor - Multiplicative zoom-out step.
27413
+ * @param duration - Animation duration in milliseconds.
27414
+ */
27415
+ async zoomOut(factor, duration) {
27416
+ this.viewport.zoomOut(factor, duration);
27417
+ }
27270
27418
  /**
27271
27419
  * Returns the current viewport state including position, scale, and dimensions.
27272
27420
  * @returns The current viewport state.
@@ -27303,11 +27451,14 @@ const KritzelEngine = class {
27303
27451
  /**
27304
27452
  * Captures a screenshot of the current viewport as a data URL.
27305
27453
  * @param format - The image format: `'png'` (default) or `'svg'`.
27454
+ * @param options - Optional screenshot settings.
27455
+ * @param options.includeBackground - Whether to include the canvas background in the export. Defaults to `true`. Set to `false` for a transparent background.
27306
27456
  * @returns A data URL string of the captured image.
27307
27457
  */
27308
- async getScreenshot(format = 'png') {
27458
+ async getScreenshot(format = 'png', options) {
27309
27459
  if (!this.host)
27310
27460
  return null;
27461
+ const includeBackground = options?.includeBackground ?? true;
27311
27462
  // Save critical state before screenshot to restore after
27312
27463
  const savedState = {
27313
27464
  objects: this.core.store.objects,
@@ -27319,7 +27470,7 @@ const KritzelEngine = class {
27319
27470
  translateY: this.core.store.state.translateY,
27320
27471
  scale: this.core.store.state.scale,
27321
27472
  };
27322
- const options = {
27473
+ const screenshotOptions = {
27323
27474
  filter: (node) => {
27324
27475
  // Exclude the context menu, debug panel, and awareness cursors from the screenshot
27325
27476
  if (node.tagName === 'KRITZEL-CONTEXT-MENU') {
@@ -27334,13 +27485,16 @@ const KritzelEngine = class {
27334
27485
  return true;
27335
27486
  },
27336
27487
  };
27488
+ if (!includeBackground) {
27489
+ screenshotOptions.backgroundColor = 'transparent';
27490
+ }
27337
27491
  let result;
27338
27492
  try {
27339
27493
  if (format === 'svg') {
27340
- result = await toSvg(this.host, options);
27494
+ result = await toSvg(this.host, screenshotOptions);
27341
27495
  }
27342
27496
  else {
27343
- result = await toPng(this.host, options);
27497
+ result = await toPng(this.host, screenshotOptions);
27344
27498
  }
27345
27499
  }
27346
27500
  finally {
@@ -27357,14 +27511,18 @@ const KritzelEngine = class {
27357
27511
  }
27358
27512
  return result;
27359
27513
  }
27360
- /** Exports the current viewport as a PNG file and triggers a browser download. */
27361
- async exportViewportAsPng() {
27514
+ /**
27515
+ * Exports the current viewport as a PNG file and triggers a browser download.
27516
+ * @param options - Optional export settings.
27517
+ * @param options.includeBackground - Whether to include the canvas background. Defaults to `true`.
27518
+ */
27519
+ async exportViewportAsPng(options) {
27362
27520
  try {
27363
27521
  const activeWorkspaceName = this.core.store.state?.activeWorkspace?.name || 'workspace';
27364
27522
  // timestamp format: YYYY-MM-DDTHH-mm-ss-sssZ, clearing colons/dots for safe filename
27365
27523
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
27366
27524
  const filename = `${activeWorkspaceName}-${timestamp}.png`;
27367
- const dataUrl = await this.getScreenshot('png');
27525
+ const dataUrl = await this.getScreenshot('png', options);
27368
27526
  if (!dataUrl) {
27369
27527
  console.error('Failed to export viewport as PNG: screenshot could not be generated');
27370
27528
  return;
@@ -27378,14 +27536,18 @@ const KritzelEngine = class {
27378
27536
  console.error('Failed to export viewport as PNG:', error);
27379
27537
  }
27380
27538
  }
27381
- /** Exports the current viewport as an SVG file and triggers a browser download. */
27382
- async exportViewportAsSvg() {
27539
+ /**
27540
+ * Exports the current viewport as an SVG file and triggers a browser download.
27541
+ * @param options - Optional export settings.
27542
+ * @param options.includeBackground - Whether to include the canvas background. Defaults to `true`.
27543
+ */
27544
+ async exportViewportAsSvg(options) {
27383
27545
  try {
27384
27546
  const activeWorkspaceName = this.core.store.state?.activeWorkspace?.name || 'workspace';
27385
27547
  // timestamp format: YYYY-MM-DDTHH-mm-ss-sssZ, clearing colons/dots for safe filename
27386
27548
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
27387
27549
  const filename = `${activeWorkspaceName}-${timestamp}.svg`;
27388
- const dataUrl = await this.getScreenshot('svg');
27550
+ const dataUrl = await this.getScreenshot('svg', options);
27389
27551
  if (!dataUrl) {
27390
27552
  console.error('Failed to export viewport as SVG: screenshot could not be generated');
27391
27553
  return;
@@ -28663,6 +28825,12 @@ const KritzelEngine = class {
28663
28825
  "user": [{
28664
28826
  "onUserChange": 0
28665
28827
  }],
28828
+ "globalContextMenuItems": [{
28829
+ "onGlobalContextMenuItemsChange": 0
28830
+ }],
28831
+ "objectContextMenuItems": [{
28832
+ "onObjectContextMenuItemsChange": 0
28833
+ }],
28666
28834
  "scaleMax": [{
28667
28835
  "validateScaleMax": 0
28668
28836
  }],
@@ -28706,7 +28874,7 @@ const KritzelEngine = class {
28706
28874
  };
28707
28875
  KritzelEngine.style = kritzelEngineCss();
28708
28876
 
28709
- const kritzelExportCss = () => `:host{display:flex;flex-direction:column;min-height:0}.export-content{display:flex;flex-direction:column;gap:16px;padding:0;flex:1}.export-content kritzel-pill-tabs{align-self:center}.export-tab-content{display:flex;flex-direction:column;gap:16px;min-height:330px}.format-selection{display:flex;flex-direction:column;gap:6px}.format-selection label{font-size:14px;font-weight:500;color:var(--kritzel-global-text-primary, #333)}.export-primary-button{width:100%;padding:12px 24px;background-color:var(--kritzel-global-primary-color, #007AFF);color:var(--kritzel-global-primary-text-color, #fff);border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color 0.2s ease;-webkit-tap-highlight-color:transparent}.export-primary-button:hover{background-color:var(--kritzel-global-primary-hover-color, #0066d6)}.export-primary-button:focus-visible{outline:revert;outline-offset:revert}.preview-container{width:100%;display:flex;justify-content:center;align-items:center;box-sizing:border-box;margin-bottom:8px}.preview-container img{max-width:100%;max-height:250px;object-fit:contain;box-shadow:0 4px 8px rgba(0, 0, 0, 0.15);border-radius:4px;border:1px solid var(--kritzel-global-border-color, #dbdbdb)}.export-content p{margin:0;color:var(--kritzel-global-text-secondary, #666)}@media (max-width: 576px){.export-tab-content{flex:1;min-height:0}}`;
28877
+ const kritzelExportCss = () => `:host{display:flex;flex-direction:column;min-height:0}.export-content{display:flex;flex-direction:column;gap:16px;padding:0;flex:1}.export-content kritzel-pill-tabs{align-self:center}.export-tab-content{display:flex;flex-direction:column;gap:16px;min-height:330px}.format-selection{display:flex;flex-direction:column;gap:6px}.format-selection label{font-size:14px;font-weight:500;color:var(--kritzel-global-text-primary, #333)}.export-primary-button{width:100%;padding:12px 24px;background-color:var(--kritzel-global-primary-color, #007AFF);color:var(--kritzel-global-primary-text-color, #fff);border:none;border-radius:var(--kritzel-button-border-radius, 8px);font-size:14px;font-weight:600;cursor:pointer;transition:background-color 0.2s ease;-webkit-tap-highlight-color:transparent}.export-primary-button:hover{background-color:var(--kritzel-global-primary-hover-color, #0066d6)}.export-primary-button:focus-visible{outline:revert;outline-offset:revert}.preview-container{width:100%;display:flex;justify-content:center;align-items:center;box-sizing:border-box;margin-bottom:8px}.preview-container img{max-width:100%;max-height:250px;object-fit:contain;box-shadow:0 4px 8px rgba(0, 0, 0, 0.15);border-radius:4px;border:1px solid var(--kritzel-global-border-color, #dbdbdb)}.export-content p{margin:0;color:var(--kritzel-global-text-secondary, #666)}@media (max-width: 576px){.export-tab-content{flex:1;min-height:0}}`;
28710
28878
 
28711
28879
  const KritzelExport = class {
28712
28880
  constructor(hostRef) {
@@ -28902,7 +29070,7 @@ const KritzelIcon = class {
28902
29070
  };
28903
29071
  KritzelIcon.style = kritzelIconCss();
28904
29072
 
28905
- const kritzelInputCss = () => `:host{display:block}.input-container{display:flex;flex-direction:column;gap:6px}.input-label{font-size:14px;font-weight:500;color:var(--kritzel-text-input-label-color, #333333)}.input-wrapper{display:flex;align-items:center;border:1px solid var(--kritzel-text-input-border-color, #ebebeb);border-radius:6px;overflow:hidden;background:var(--kritzel-text-input-background, #ffffff);transition:border-color 150ms ease}.input-wrapper:hover:not(:focus-within){border-color:var(--kritzel-text-input-hover-border-color, #cccccc)}.input-wrapper:focus-within{border-color:var(--kritzel-text-input-focus-border-color, #007AFF);border-width:2px}.text-input{flex:1;padding:10px 12px;border:none;outline:none;font-size:14px;font-family:inherit;background:transparent;color:var(--kritzel-text-input-text-color, #333333);box-sizing:border-box}.text-input::placeholder{color:var(--kritzel-text-input-placeholder-color, #999999)}.text-input::selection{background-color:var(--kritzel-text-input-selection-background, #007AFF);color:var(--kritzel-text-input-selection-color, #ffffff)}.text-input:disabled{cursor:not-allowed;opacity:0.6}.input-suffix{padding:10px 12px;background:var(--kritzel-text-input-suffix-background, #f5f5f5);color:var(--kritzel-text-input-suffix-color, #666666);font-size:14px;border-left:1px solid var(--kritzel-text-input-border-color, #ebebeb);flex-shrink:0}`;
29073
+ const kritzelInputCss = () => `:host{display:block}.input-container{display:flex;flex-direction:column;gap:6px}.input-label{font-size:14px;font-weight:500;color:var(--kritzel-text-input-label-color, #333333)}.input-wrapper{display:flex;align-items:center;border:1px solid var(--kritzel-text-input-border-color, #ebebeb);border-radius:var(--kritzel-text-input-border-radius, 6px);overflow:hidden;background:var(--kritzel-text-input-background, #ffffff);transition:border-color 150ms ease}.input-wrapper:hover:not(:focus-within){border-color:var(--kritzel-text-input-hover-border-color, #cccccc)}.input-wrapper:focus-within{border-color:var(--kritzel-text-input-focus-border-color, #007AFF);border-width:2px}.text-input{flex:1;padding:10px 12px;border:none;outline:none;font-size:14px;font-family:inherit;background:transparent;color:var(--kritzel-text-input-text-color, #333333);box-sizing:border-box}.text-input::placeholder{color:var(--kritzel-text-input-placeholder-color, #999999)}.text-input::selection{background-color:var(--kritzel-text-input-selection-background, #007AFF);color:var(--kritzel-text-input-selection-color, #ffffff)}.text-input:disabled{cursor:not-allowed;opacity:0.6}.input-suffix{padding:10px 12px;background:var(--kritzel-text-input-suffix-background, #f5f5f5);color:var(--kritzel-text-input-suffix-color, #666666);font-size:14px;border-left:1px solid var(--kritzel-text-input-border-color, #ebebeb);flex-shrink:0}`;
28906
29074
 
28907
29075
  const KritzelInput = class {
28908
29076
  constructor(hostRef) {
@@ -29450,7 +29618,7 @@ const KritzelMoreMenu = class {
29450
29618
  };
29451
29619
  KritzelMoreMenu.style = kritzelMoreMenuCss();
29452
29620
 
29453
- const kritzelNumericInputCss = () => `:host{display:block}.input-container{display:flex;flex-direction:column;gap:6px}.input-label{font-size:14px;font-weight:500;color:var(--kritzel-numeric-input-label-color, #333333)}.input-wrapper{display:flex;position:relative}.numeric-input{flex:1;padding:8px 36px 8px 12px;border:1px solid var(--kritzel-numeric-input-border-color, #ebebeb);border-radius:6px;font-size:14px;color:var(--kritzel-numeric-input-text-color, #333333);background-color:var(--kritzel-numeric-input-input-background, #ffffff);outline:none;transition:border-color 150ms ease;box-sizing:border-box}.numeric-input::-webkit-outer-spin-button,.numeric-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.numeric-input[type='number']{-moz-appearance:textfield}.numeric-input::selection{background-color:var(--kritzel-numeric-input-selection-background, #007AFF);color:var(--kritzel-numeric-input-selection-color, #ffffff)}.numeric-input:hover{border-color:var(--kritzel-numeric-input-hover-border-color, #cccccc)}.numeric-input:focus{border-color:var(--kritzel-numeric-input-focus-border-color, #0066ff);border-width:2px;padding:7px 35px 7px 11px}.spinner-buttons{position:absolute;right:1px;top:1px;bottom:1px;display:flex;flex-direction:column;border-left:1px solid var(--kritzel-numeric-input-border-color, #ebebeb);border-radius:0 5px 5px 0;overflow:hidden}.spinner-button{flex:1;display:flex;align-items:center;justify-content:center;width:24px;padding:0;border:none;background-color:var(--kritzel-numeric-input-spinner-background, #f5f5f5);color:var(--kritzel-numeric-input-spinner-color, #666666);cursor:pointer;transition:background-color 150ms ease}.spinner-button:hover{background-color:var(--kritzel-numeric-input-spinner-hover-background, #ebebeb)}.spinner-button:active{background-color:var(--kritzel-numeric-input-spinner-active-background, #dddddd)}.spinner-up{border-bottom:1px solid var(--kritzel-numeric-input-border-color, #ebebeb)}.spinner-icon{width:10px;height:6px}`;
29621
+ const kritzelNumericInputCss = () => `:host{display:block}.input-container{display:flex;flex-direction:column;gap:6px}.input-label{font-size:14px;font-weight:500;color:var(--kritzel-numeric-input-label-color, #333333)}.input-wrapper{display:flex;position:relative}.numeric-input{flex:1;padding:8px 36px 8px 12px;border:1px solid var(--kritzel-numeric-input-border-color, #ebebeb);border-radius:var(--kritzel-numeric-input-border-radius, 6px);font-size:14px;color:var(--kritzel-numeric-input-text-color, #333333);background-color:var(--kritzel-numeric-input-input-background, #ffffff);outline:none;transition:border-color 150ms ease;box-sizing:border-box}.numeric-input::-webkit-outer-spin-button,.numeric-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.numeric-input[type='number']{-moz-appearance:textfield}.numeric-input::selection{background-color:var(--kritzel-numeric-input-selection-background, #007AFF);color:var(--kritzel-numeric-input-selection-color, #ffffff)}.numeric-input:hover{border-color:var(--kritzel-numeric-input-hover-border-color, #cccccc)}.numeric-input:focus{border-color:var(--kritzel-numeric-input-focus-border-color, #0066ff);border-width:2px;padding:7px 35px 7px 11px}.spinner-buttons{position:absolute;right:1px;top:1px;bottom:1px;display:flex;flex-direction:column;border-left:1px solid var(--kritzel-numeric-input-border-color, #ebebeb);border-radius:0 var(--kritzel-numeric-input-spinner-border-radius, 5px) var(--kritzel-numeric-input-spinner-border-radius, 5px) 0;overflow:hidden}.spinner-button{flex:1;display:flex;align-items:center;justify-content:center;width:24px;padding:0;border:none;background-color:var(--kritzel-numeric-input-spinner-background, #f5f5f5);color:var(--kritzel-numeric-input-spinner-color, #666666);cursor:pointer;transition:background-color 150ms ease}.spinner-button:hover{background-color:var(--kritzel-numeric-input-spinner-hover-background, #ebebeb)}.spinner-button:active{background-color:var(--kritzel-numeric-input-spinner-active-background, #dddddd)}.spinner-up{border-bottom:1px solid var(--kritzel-numeric-input-border-color, #ebebeb)}.spinner-icon{width:10px;height:6px}`;
29454
29622
 
29455
29623
  const KritzelNumericInput = class {
29456
29624
  constructor(hostRef) {
@@ -29949,7 +30117,7 @@ const KritzelPortal = class {
29949
30117
  * This file is auto-generated by the version bump scripts.
29950
30118
  * Do not modify manually.
29951
30119
  */
29952
- const KRITZEL_VERSION = '0.3.12';
30120
+ const KRITZEL_VERSION = '0.3.14';
29953
30121
 
29954
30122
  const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
29955
30123