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,5 +1,5 @@
1
- import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-D9HaikfQ.js';
2
- import { c as KritzelPath, e as KritzelLine, J as KritzelColorHelper, o as KritzelSelectionTool, h as KritzelBrushTool, i as KritzelLineTool, m as KritzelShapeTool, l as KritzelTextTool, L as KritzelDevicesHelper, M as KritzelMouseButton, N as DEFAULT_STROKE_SIZES, O as DEFAULT_COLOR_PALETTE, S as ShapeType, I as IndexedDBSyncProvider, D as DEFAULT_BRUSH_CONFIG, j as KritzelEraserTool, v as DEFAULT_LINE_TOOL_CONFIG, u as DEFAULT_TEXT_CONFIG, k as KritzelImageTool, z as KritzelAlignment, w as DEFAULT_ASSET_STORAGE_CONFIG, T as ThemeHelper, y as darkTheme, x as lightTheme, P as KritzelSelectionGroup, Q as KritzelSelectionBox, R as KritzelIconRegistry, U as KritzelKeyboardHelper, V as KritzelBaseHandler, K as KritzelBaseObject, r as KritzelWorkspace, f as KritzelGroup, d as KritzelImage, g as KritzelShape, b as KritzelText, B as runMigrations, G as CURRENT_WORKSPACE_SCHEMA_VERSION, E as WORKSPACE_MIGRATIONS, F as CURRENT_APP_STATE_SCHEMA_VERSION, C as APP_STATE_MIGRATIONS, X as ObjectHelper, n as KritzelCursorHelper, s as KritzelAnchorManager, t as KritzelThemeManager, p as KritzelAssetResolver, Y as KritzelClassHelper, Z as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './schema.constants-BcT1vV4J.js';
1
+ import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-Dhio9uis.js';
2
+ import { c as KritzelPath, e as KritzelLine, G as KritzelColorHelper, J as KritzelDevicesHelper, o as KritzelSelectionTool, l as KritzelTextTool, L as KritzelMouseButton, M as DEFAULT_STROKE_SIZES, N as DEFAULT_COLOR_PALETTE, S as ShapeType, D as DEFAULT_BRUSH_CONFIG, h as KritzelBrushTool, j as KritzelEraserTool, u as DEFAULT_LINE_TOOL_CONFIG, i as KritzelLineTool, m as KritzelShapeTool, t as DEFAULT_TEXT_CONFIG, k as KritzelImageTool, y as KritzelAlignment, v as DEFAULT_ASSET_STORAGE_CONFIG, T as ThemeHelper, x as darkTheme, w as lightTheme, O as KritzelSelectionGroup, P as KritzelSelectionBox, Q as KritzelIconRegistry, R as KritzelKeyboardHelper, U as KritzelBaseHandler, K as KritzelBaseObject, q as KritzelWorkspace, f as KritzelGroup, d as KritzelImage, g as KritzelShape, b as KritzelText, z as runMigrations, F as CURRENT_WORKSPACE_SCHEMA_VERSION, C as WORKSPACE_MIGRATIONS, E as CURRENT_APP_STATE_SCHEMA_VERSION, B as APP_STATE_MIGRATIONS, V as ObjectHelper, n as KritzelCursorHelper, r as KritzelAnchorManager, s as KritzelThemeManager, p as KritzelAssetResolver, X as KritzelClassHelper, Y as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION } from './schema.constants-DiCnmIYK.js';
3
3
  import * as Y from 'yjs';
4
4
  import 'y-indexeddb';
5
5
  import 'y-websocket';
@@ -607,7 +607,7 @@ const KritzelColorPalette = class {
607
607
  };
608
608
  KritzelColorPalette.style = kritzelColorPaletteCss();
609
609
 
610
- 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}`;
610
+ 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}`;
611
611
 
612
612
  const VIEWPORT_PADDING = 8;
613
613
  const SUBMENU_DELAY = 150;
@@ -728,6 +728,11 @@ const KritzelContextMenu = class {
728
728
  const idx = path.lastIndexOf('.');
729
729
  return idx === -1 ? '' : path.substring(0, idx);
730
730
  }
731
+ getMenuDepth(path) {
732
+ if (!path)
733
+ return 0;
734
+ return path.split('.').length;
735
+ }
731
736
  pruneStaleRefs() {
732
737
  const openPaths = new Set(this.getOpenSubmenuPaths());
733
738
  for (const key of Array.from(this.submenuRefs.keys())) {
@@ -839,7 +844,8 @@ const KritzelContextMenu = class {
839
844
  }
840
845
  renderSubmenu(processedChildren, path) {
841
846
  const position = this.submenuPositions[path] === 'left' ? 'left' : 'right';
842
- return (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)));
847
+ const zIndex = this.getMenuDepth(path) + 1;
848
+ return (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)));
843
849
  }
844
850
  render() {
845
851
  if (!this.processedItems || this.processedItems.length === 0) {
@@ -857,67 +863,65 @@ KritzelContextMenu.style = kritzelContextMenuCss();
857
863
 
858
864
  class KritzelToolConfigHelper {
859
865
  static getToolConfig(tool) {
860
- const toolConstructorName = tool?.constructor?.name;
861
- if (tool instanceof KritzelSelectionTool || toolConstructorName === 'KritzelSelectionTool') {
862
- return tool.getToolConfig();
863
- }
864
- if (tool instanceof KritzelBrushTool || toolConstructorName === 'KritzelBrushTool') {
865
- return {
866
- type: 'brush',
867
- colorProperty: 'color',
868
- sizeProperty: 'size',
869
- opacityProperty: 'opacity',
870
- paletteSource: 'palette',
871
- sizesSource: 'sizes',
872
- controls: [
873
- { type: 'stroke-size', propertyName: 'size' },
874
- ],
875
- };
876
- }
877
- if (tool instanceof KritzelLineTool || toolConstructorName === 'KritzelLineTool') {
878
- return {
879
- type: 'line',
880
- colorProperty: 'color',
881
- sizeProperty: 'size',
882
- opacityProperty: 'opacity',
883
- paletteSource: 'palette',
884
- sizesSource: 'sizes',
885
- controls: [
886
- { type: 'stroke-size', propertyName: 'size' },
887
- { type: 'line-endings', propertyName: 'arrows', additionalProps: {} },
888
- ],
889
- };
890
- }
891
- if (tool instanceof KritzelShapeTool || toolConstructorName === 'KritzelShapeTool') {
892
- return {
893
- type: 'shape',
894
- colorProperty: 'strokeColor',
895
- sizeProperty: 'strokeWidth',
896
- opacityProperty: 'opacity',
897
- paletteSource: 'palette',
898
- sizesSource: 'sizes',
899
- controls: [
900
- { type: 'stroke-size', propertyName: 'strokeWidth' },
901
- { type: 'shape-fill', propertyName: 'fillColor', additionalProps: {} },
902
- ],
903
- };
904
- }
905
- if (tool instanceof KritzelTextTool || toolConstructorName === 'KritzelTextTool') {
906
- return {
907
- type: 'text',
908
- colorProperty: 'fontColor',
909
- sizeProperty: 'fontSize',
910
- opacityProperty: 'opacity',
911
- paletteSource: 'palette',
912
- sizesSource: 'sizes',
913
- controls: [
914
- { type: 'font-size', propertyName: 'fontSize', additionalProps: {} },
915
- { type: 'font-family', propertyName: 'fontFamily' },
916
- ],
917
- };
866
+ switch (tool?.toolType) {
867
+ case 'selection':
868
+ return 'getToolConfig' in tool && typeof tool.getToolConfig === 'function'
869
+ ? tool.getToolConfig()
870
+ : null;
871
+ case 'brush':
872
+ return {
873
+ type: 'brush',
874
+ colorProperty: 'color',
875
+ sizeProperty: 'size',
876
+ opacityProperty: 'opacity',
877
+ paletteSource: 'palette',
878
+ sizesSource: 'sizes',
879
+ controls: [
880
+ { type: 'stroke-size', propertyName: 'size' },
881
+ ],
882
+ };
883
+ case 'line':
884
+ return {
885
+ type: 'line',
886
+ colorProperty: 'color',
887
+ sizeProperty: 'size',
888
+ opacityProperty: 'opacity',
889
+ paletteSource: 'palette',
890
+ sizesSource: 'sizes',
891
+ controls: [
892
+ { type: 'stroke-size', propertyName: 'size' },
893
+ { type: 'line-endings', propertyName: 'arrows', additionalProps: {} },
894
+ ],
895
+ };
896
+ case 'shape':
897
+ return {
898
+ type: 'shape',
899
+ colorProperty: 'strokeColor',
900
+ sizeProperty: 'strokeWidth',
901
+ opacityProperty: 'opacity',
902
+ paletteSource: 'palette',
903
+ sizesSource: 'sizes',
904
+ controls: [
905
+ { type: 'stroke-size', propertyName: 'strokeWidth' },
906
+ { type: 'shape-fill', propertyName: 'fillColor', additionalProps: {} },
907
+ ],
908
+ };
909
+ case 'text':
910
+ return {
911
+ type: 'text',
912
+ colorProperty: 'fontColor',
913
+ sizeProperty: 'fontSize',
914
+ opacityProperty: 'opacity',
915
+ paletteSource: 'palette',
916
+ sizesSource: 'sizes',
917
+ controls: [
918
+ { type: 'font-size', propertyName: 'fontSize', additionalProps: {} },
919
+ { type: 'font-family', propertyName: 'fontFamily' },
920
+ ],
921
+ };
922
+ default:
923
+ return null;
918
924
  }
919
- // Tool is not configurable (e.g., selection, eraser, image)
920
- return null;
921
925
  }
922
926
  }
923
927
 
@@ -1876,7 +1880,7 @@ const KritzelDialog = class {
1876
1880
  };
1877
1881
  KritzelDialog.style = kritzelDialogCss();
1878
1882
 
1879
- 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}`;
1883
+ 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}`;
1880
1884
 
1881
1885
  const KritzelDropdown = class {
1882
1886
  constructor(hostRef) {
@@ -2153,12 +2157,10 @@ const ABSOLUTE_SCALE_MAX = 1000;
2153
2157
  const ABSOLUTE_SCALE_MIN = 0.0001;
2154
2158
 
2155
2159
  /**
2156
- * Default sync configuration - IndexedDB
2160
+ * Default sync configuration - None
2157
2161
  */
2158
2162
  const DEFAULT_SYNC_CONFIG = {
2159
- providers: [
2160
- IndexedDBSyncProvider
2161
- ],
2163
+ providers: [],
2162
2164
  };
2163
2165
 
2164
2166
  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}`;
@@ -2350,15 +2352,7 @@ const KritzelEditor = class {
2350
2352
  /** The element to use as the target for the cursor. Defaults to the editor container if not set. */
2351
2353
  cursorTarget;
2352
2354
  /** Optional login configuration. When provided, a "Sign in" button is shown that opens a login dialog with the configured providers. */
2353
- loginConfig = {
2354
- providers: [
2355
- {
2356
- label: 'Sign in with Google',
2357
- icon: 'google',
2358
- name: 'Google',
2359
- },
2360
- ],
2361
- };
2355
+ loginConfig;
2362
2356
  /** Whether the editor is in a loading state. When true, a loading overlay is displayed. */
2363
2357
  isLoading = false;
2364
2358
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
@@ -2487,12 +2481,18 @@ const KritzelEditor = class {
2487
2481
  async centerObjectInViewport(object) {
2488
2482
  return this.engineRef.centerObjectInViewport(object);
2489
2483
  }
2484
+ async panToObject(object) {
2485
+ return this.engineRef.panToObject(object);
2486
+ }
2490
2487
  async backToContent() {
2491
2488
  return this.engineRef.backToContent();
2492
2489
  }
2493
2490
  async centerAllObjects(animate = true) {
2494
2491
  return this.engineRef.centerAllObjects(animate);
2495
2492
  }
2493
+ async centerObjects(objects, animate = true) {
2494
+ return this.engineRef.centerObjects(objects, animate);
2495
+ }
2496
2496
  async setViewport(x, y, scale) {
2497
2497
  return this.engineRef.setViewport(x, y, scale);
2498
2498
  }
@@ -2502,6 +2502,12 @@ const KritzelEditor = class {
2502
2502
  async zoomTo(scale, worldX, worldY) {
2503
2503
  return this.engineRef.zoomTo(scale, worldX, worldY);
2504
2504
  }
2505
+ async zoomIn(factor = 1.6, duration = 200) {
2506
+ return this.engineRef.zoomIn(factor, duration);
2507
+ }
2508
+ async zoomOut(factor = 1.6, duration = 200) {
2509
+ return this.engineRef.zoomOut(factor, duration);
2510
+ }
2505
2511
  async getViewport() {
2506
2512
  return this.engineRef.getViewport();
2507
2513
  }
@@ -2587,14 +2593,14 @@ const KritzelEditor = class {
2587
2593
  async redo() {
2588
2594
  return this.engineRef.redo();
2589
2595
  }
2590
- async getScreenshot(format = 'png') {
2591
- return this.engineRef.getScreenshot(format);
2596
+ async getScreenshot(format = 'png', options) {
2597
+ return this.engineRef.getScreenshot(format, options);
2592
2598
  }
2593
- async exportViewportAsPng() {
2594
- return this.engineRef.exportViewportAsPng();
2599
+ async exportViewportAsPng(options) {
2600
+ return this.engineRef.exportViewportAsPng(options);
2595
2601
  }
2596
- async exportViewportAsSvg() {
2597
- return this.engineRef.exportViewportAsSvg();
2602
+ async exportViewportAsSvg(options) {
2603
+ return this.engineRef.exportViewportAsSvg(options);
2598
2604
  }
2599
2605
  async exportSelectedObjectsAsPng() {
2600
2606
  return this.engineRef.exportSelectedObjectsAsPng();
@@ -2946,31 +2952,31 @@ const KritzelEditor = class {
2946
2952
  const isLoggedIn = this.isLoggedIn;
2947
2953
  const shouldShowCurrentUser = isLoggedIn;
2948
2954
  const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
2949
- return (h(Host, { key: '440621eb23598732c63d4be92ae16785d84b3d6f', style: {
2955
+ return (h(Host, { key: 'ffacaea5d3df12a3a8b448d31db3c5949053156c', style: {
2950
2956
  opacity: this.isEditorVisible ? '1' : '0',
2951
2957
  visibility: this.isEditorVisible ? 'visible' : 'hidden',
2952
2958
  transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
2953
- } }, h("div", { key: 'b20c930c8094f7ab9db8fdb09428cf34a2cab024', class: "top-left-buttons" }, 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) }), h("kritzel-back-to-content", { key: 'a3cbb86082c2f0768b7457ec25740d27200e287b', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), h("kritzel-engine", { key: '82e611de33c40997943e1fd702f0b601fadbf591', ref: el => {
2959
+ } }, h("div", { key: '669eafee25b4f84c39469738a1337c21ab03e388', class: "top-left-buttons" }, 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) }), h("kritzel-back-to-content", { key: '5bd0e6263d51119b197292b69879c1ae437f92fc', visible: this.isBackToContentButtonVisible, onBackToContent: () => this.backToContent() })), h("kritzel-engine", { key: '468f17137c51c90fd61c9179d13c449b1ac8feb9', ref: el => {
2954
2960
  if (el) {
2955
2961
  this.engineRef = el;
2956
2962
  }
2957
- }, 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) }), h("kritzel-controls", { key: 'eb48df395318bde3fc0bc48784510bf5139bc9e8', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
2963
+ }, 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) }), h("kritzel-controls", { key: '848c30b27fb916c8480b41745bd6ec844e0b23a2', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
2958
2964
  if (el) {
2959
2965
  this.controlsRef = el;
2960
2966
  }
2961
- }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: '1259089ca70c634621f7e2db274868b12a3e5e8a', class: "top-right-buttons" }, h("kritzel-settings", { key: 'b38b01040714827a5d824694b481edb8094eafd8', ref: el => {
2967
+ }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, onIsControlsReady: () => (this.isControlsReady = true) }), h("div", { key: 'e998d60679c767d15617bd7ecde5ee77e781a92f', class: "top-right-buttons" }, h("kritzel-settings", { key: '43b9cdb2d10de789cc03d2a9ef5df870b8ca7bfe', ref: el => {
2962
2968
  if (el) {
2963
2969
  this.settingsRef = el;
2964
2970
  }
2965
- }, 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) }), h("kritzel-export", { key: 'a678999cac4f3618c44d1340b6905ec2f3061dd5', ref: el => {
2971
+ }, 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) }), h("kritzel-export", { key: '74669624a1e5177125ef00e1667c880ce47cbce4', ref: el => {
2966
2972
  if (el) {
2967
2973
  this.exportRef = el;
2968
2974
  }
2969
- }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '7d0b70c7347e7fda4e96a59b27b8fb6c2eb77f49', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: 'ed364648df937fb1e84d850953fee51f6e54e95e', user: this.user }), shouldShowLoginButton && (h("kritzel-button", { key: 'dd24afa0746a311ac4a27000281fef28bddf844a', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in")), h("kritzel-more-menu", { key: '713da1a5313809083470a8a23c0531e9e198c4bd', items: this.moreMenuItems, visible: this.isMoreMenuVisible }), h("kritzel-share-dialog", { key: '37f80fdb7b1087926b72ece7693f816c9f85f746', ref: el => {
2975
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), h("kritzel-active-users", { key: '18d925f32d021ff6713accb22d0594d259d70f2e', users: this.activeUsers }), shouldShowCurrentUser && h("kritzel-current-user", { key: 'bddd5c29c5f17cced47276c237c04cfdb711da38', user: this.user }), shouldShowLoginButton && (h("kritzel-button", { key: '4eb6c85459f59863d6e644ecf21c2295da71bafc', onButtonClick: () => this.loginDialogRef?.open() }, "Sign in")), h("kritzel-more-menu", { key: 'a5a323ec248bebc7bc07898f344e0926fac8db17', items: this.moreMenuItems, visible: this.isMoreMenuVisible }), h("kritzel-share-dialog", { key: '8cb3ddad95d36f5b7ad59d8c4f057df93cb2bfe3', ref: el => {
2970
2976
  if (el) {
2971
2977
  this.shareDialogRef = el;
2972
2978
  }
2973
- }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: 'f5b59522082824bc236784a9083f1d425852d487', ref: el => {
2979
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (h("kritzel-login-dialog", { key: '35395d0faadcfeb021fba685aa46e180e47d2be2', ref: el => {
2974
2980
  if (el) {
2975
2981
  this.loginDialogRef = el;
2976
2982
  }
@@ -20657,6 +20663,87 @@ class KritzelViewport {
20657
20663
  this.setViewport(centerWorldX, centerWorldY, scale);
20658
20664
  }
20659
20665
  }
20666
+ /**
20667
+ * Zooms in by a fixed step, centered on the current viewport center,
20668
+ * with a smooth animation. The resulting scale is clamped to the allowed range.
20669
+ * @param factor - Multiplicative zoom-in step
20670
+ * @param duration - Animation duration in milliseconds
20671
+ */
20672
+ zoomIn(factor, duration) {
20673
+ this.animateZoomAroundViewportCenter(factor, duration);
20674
+ }
20675
+ /**
20676
+ * Zooms out by a fixed step, centered on the current viewport center,
20677
+ * with a smooth animation. The resulting scale is clamped to the allowed range.
20678
+ * @param factor - Multiplicative zoom-out step
20679
+ * @param duration - Animation duration in milliseconds
20680
+ */
20681
+ zoomOut(factor, duration) {
20682
+ this.animateZoomAroundViewportCenter(1 / factor, duration);
20683
+ }
20684
+ /**
20685
+ * Smoothly zooms around the viewport center, keeping the center world point
20686
+ * fixed for the entire animation. The translation is recomputed from the fixed
20687
+ * center point on every frame (rather than interpolated independently), which
20688
+ * guarantees the center never drifts and the viewport does not jump.
20689
+ * The resulting scale is clamped to the allowed range and the translation is
20690
+ * clamped to the viewport boundaries.
20691
+ * @param scaleFactor - Multiplicative scale factor (>1 zooms in, <1 zooms out)
20692
+ * @param duration - Animation duration in milliseconds
20693
+ */
20694
+ animateZoomAroundViewportCenter(scaleFactor, duration) {
20695
+ this.cancelViewportAnimation();
20696
+ const state = this._core.store.state;
20697
+ const startScale = state.scale;
20698
+ const effectiveMinScale = this.getEffectiveMinScale();
20699
+ const targetScale = Math.min(state.scaleMax, Math.max(effectiveMinScale, startScale * scaleFactor));
20700
+ // The world point currently under the viewport center stays fixed.
20701
+ const centerScreenX = state.viewportWidth / 2;
20702
+ const centerScreenY = state.viewportHeight / 2;
20703
+ const centerWorldX = (centerScreenX - state.translateX) / startScale;
20704
+ const centerWorldY = (centerScreenY - state.translateY) / startScale;
20705
+ if (targetScale === startScale || duration <= 0) {
20706
+ this.applyZoomAroundCenter(targetScale, centerScreenX, centerScreenY, centerWorldX, centerWorldY);
20707
+ state.isScaling = true;
20708
+ this._core.rerender();
20709
+ this._debounceUpdate();
20710
+ this._debounceEndScaling();
20711
+ return;
20712
+ }
20713
+ const startTime = performance.now();
20714
+ state.isScaling = true;
20715
+ const animate = (currentTime) => {
20716
+ const elapsed = currentTime - startTime;
20717
+ const progress = Math.min(elapsed / duration, 1);
20718
+ // easeInOutCubic for a smooth ramp in and out
20719
+ const eased = progress < 0.5 ? 4 * progress * progress * progress : 1 - Math.pow(-2 * progress + 2, 3) / 2;
20720
+ const frameScale = startScale + (targetScale - startScale) * eased;
20721
+ this.applyZoomAroundCenter(frameScale, centerScreenX, centerScreenY, centerWorldX, centerWorldY);
20722
+ this._core.rerender();
20723
+ if (progress < 1) {
20724
+ this._animationFrameId = requestAnimationFrame(animate);
20725
+ }
20726
+ else {
20727
+ this._animationFrameId = null;
20728
+ state.isScaling = false;
20729
+ this._core.rerender();
20730
+ this._debounceUpdate();
20731
+ }
20732
+ };
20733
+ this._animationFrameId = requestAnimationFrame(animate);
20734
+ }
20735
+ /**
20736
+ * Applies a single zoom step that keeps the given world point anchored to the
20737
+ * given screen point at the specified scale, clamped to the viewport boundaries.
20738
+ */
20739
+ applyZoomAroundCenter(scale, screenX, screenY, worldX, worldY) {
20740
+ const state = this._core.store.state;
20741
+ state.scale = scale;
20742
+ const clamped = this.clampTranslate(screenX - worldX * scale, screenY - worldY * scale);
20743
+ state.translateX = clamped.translateX;
20744
+ state.translateY = clamped.translateY;
20745
+ state.hasViewportChanged = true;
20746
+ }
20660
20747
  /**
20661
20748
  * Centers a given object in the viewport without changing the scale.
20662
20749
  * The object's center point will be positioned at the viewport center.
@@ -20913,22 +21000,21 @@ class KritzelViewport {
20913
21000
  return true;
20914
21001
  }
20915
21002
  /**
20916
- * Centers and fits ALL objects in the viewport, including objects not currently rendered.
20917
- * Calculates the combined bounding box of all objects and optionally animates the viewport to show them.
21003
+ * Centers and fits the provided objects in the viewport.
21004
+ * Calculates the combined bounding box of the provided objects and optionally animates the viewport to show them.
21005
+ * @param objects - Objects to include in the fit operation.
20918
21006
  * @param animate - Whether to animate the viewport transition (default: true)
20919
- * @returns true if objects were found and viewport was adjusted, false if no objects exist
21007
+ * @returns true if at least one object was provided and viewport was adjusted, false otherwise
20920
21008
  */
20921
- centerFitAllObjects(animate = true) {
20922
- const allObjects = this._core.store.allNonSelectionObjects;
20923
- if (allObjects.length === 0) {
21009
+ centerFitObjects(objects, animate = true) {
21010
+ if (objects.length === 0) {
20924
21011
  return false;
20925
21012
  }
20926
- // Calculate combined bounds of all objects
20927
21013
  let minX = Infinity;
20928
21014
  let minY = Infinity;
20929
21015
  let maxX = -Infinity;
20930
21016
  let maxY = -Infinity;
20931
- for (const obj of allObjects) {
21017
+ for (const obj of objects) {
20932
21018
  const bounds = obj.rotatedBoundingBox;
20933
21019
  minX = Math.min(minX, bounds.x);
20934
21020
  minY = Math.min(minY, bounds.y);
@@ -20951,6 +21037,15 @@ class KritzelViewport {
20951
21037
  this.animateViewportTo(targetTranslateX, targetTranslateY, clampedScale, animate ? 150 : 0);
20952
21038
  return true;
20953
21039
  }
21040
+ /**
21041
+ * Centers and fits ALL objects in the viewport, including objects not currently rendered.
21042
+ * Calculates the combined bounding box of all objects and optionally animates the viewport to show them.
21043
+ * @param animate - Whether to animate the viewport transition (default: true)
21044
+ * @returns true if objects were found and viewport was adjusted, false if no objects exist
21045
+ */
21046
+ centerFitAllObjects(animate = true) {
21047
+ return this.centerFitObjects(this._core.store.allNonSelectionObjects, animate);
21048
+ }
20954
21049
  }
20955
21050
 
20956
21051
  /** The amount of pixels to move an object when using arrow key nudging. */
@@ -26475,8 +26570,18 @@ const KritzelEngine = class {
26475
26570
  }
26476
26571
  /** Context menu items shown when right-clicking the canvas background. */
26477
26572
  globalContextMenuItems;
26573
+ onGlobalContextMenuItemsChange(newValue) {
26574
+ if (this.contextMenuHandler) {
26575
+ this.contextMenuHandler.globalContextMenuItems = newValue ?? [];
26576
+ }
26577
+ }
26478
26578
  /** Context menu items shown when right-clicking a selected object. */
26479
26579
  objectContextMenuItems;
26580
+ onObjectContextMenuItemsChange(newValue) {
26581
+ if (this.contextMenuHandler) {
26582
+ this.contextMenuHandler.objectContextMenuItems = newValue ?? [];
26583
+ }
26584
+ }
26480
26585
  /** Maximum zoom scale allowed. Clamped to the absolute maximum defined by the engine. */
26481
26586
  scaleMax = ABSOLUTE_SCALE_MAX;
26482
26587
  validateScaleMax(newValue) {
@@ -26953,6 +27058,9 @@ const KritzelEngine = class {
26953
27058
  object.scale = object.scale ?? this.core.store.state.scale;
26954
27059
  object.zIndex = this.core.store.currentZIndex;
26955
27060
  object.workspaceId = this.core.store.state.activeWorkspace.id;
27061
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
27062
+ await object.prepareForInsert();
27063
+ }
26956
27064
  // Handle KritzelText: recreate the editor now that _core is available
26957
27065
  // The editor's dispatchTransaction callback needs _core for persisting changes
26958
27066
  if (KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
@@ -27037,6 +27145,12 @@ const KritzelEngine = class {
27037
27145
  if (objects.length === 0) {
27038
27146
  return [];
27039
27147
  }
27148
+ for (const object of objects) {
27149
+ object._core = this.core;
27150
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
27151
+ await object.prepareForInsert();
27152
+ }
27153
+ }
27040
27154
  this.core.store.objects.transaction(() => {
27041
27155
  for (const object of objects) {
27042
27156
  object.id = object.generateId();
@@ -27201,6 +27315,14 @@ const KritzelEngine = class {
27201
27315
  this.core.rerender();
27202
27316
  return object;
27203
27317
  }
27318
+ /**
27319
+ * Pans the viewport to center on the given object without changing the zoom level.
27320
+ * Unlike `centerObjectInViewport`, this moves the camera — not the object.
27321
+ * @param object - The object whose center the viewport should pan to.
27322
+ */
27323
+ async panToObject(object) {
27324
+ this.viewport.panTo(object.centerX, object.centerY);
27325
+ }
27204
27326
  /**
27205
27327
  * Pans and zooms the viewport to fit the nearest content, with padding.
27206
27328
  * Useful when the user has panned away from all objects.
@@ -27218,6 +27340,16 @@ const KritzelEngine = class {
27218
27340
  async centerAllObjects(animate = true) {
27219
27341
  return this.viewport.centerFitAllObjects(animate);
27220
27342
  }
27343
+ /**
27344
+ * Pans and zooms the viewport to fit the provided objects.
27345
+ * Calculates the combined bounding box of the given objects and centers the viewport to show them.
27346
+ * @param objects - The objects to center and fit in the viewport.
27347
+ * @param animate - Whether to animate the viewport transition (default: true).
27348
+ * @returns `true` if objects were provided and the viewport was adjusted, `false` otherwise.
27349
+ */
27350
+ async centerObjects(objects, animate = true) {
27351
+ return this.viewport.centerFitObjects(objects, animate);
27352
+ }
27221
27353
  /**
27222
27354
  * Sets the viewport to center on the given world coordinates at the specified scale.
27223
27355
  * @param x - X position in world coordinates to center on.
@@ -27245,6 +27377,22 @@ const KritzelEngine = class {
27245
27377
  async zoomTo(scale, worldX, worldY) {
27246
27378
  this.viewport.zoomTo(scale, worldX, worldY);
27247
27379
  }
27380
+ /**
27381
+ * Zooms in by a fixed step, centered on the current viewport center, with a smooth animation.
27382
+ * @param factor - Multiplicative zoom-in step.
27383
+ * @param duration - Animation duration in milliseconds.
27384
+ */
27385
+ async zoomIn(factor, duration) {
27386
+ this.viewport.zoomIn(factor, duration);
27387
+ }
27388
+ /**
27389
+ * Zooms out by a fixed step, centered on the current viewport center, with a smooth animation.
27390
+ * @param factor - Multiplicative zoom-out step.
27391
+ * @param duration - Animation duration in milliseconds.
27392
+ */
27393
+ async zoomOut(factor, duration) {
27394
+ this.viewport.zoomOut(factor, duration);
27395
+ }
27248
27396
  /**
27249
27397
  * Returns the current viewport state including position, scale, and dimensions.
27250
27398
  * @returns The current viewport state.
@@ -27281,11 +27429,14 @@ const KritzelEngine = class {
27281
27429
  /**
27282
27430
  * Captures a screenshot of the current viewport as a data URL.
27283
27431
  * @param format - The image format: `'png'` (default) or `'svg'`.
27432
+ * @param options - Optional screenshot settings.
27433
+ * @param options.includeBackground - Whether to include the canvas background in the export. Defaults to `true`. Set to `false` for a transparent background.
27284
27434
  * @returns A data URL string of the captured image.
27285
27435
  */
27286
- async getScreenshot(format = 'png') {
27436
+ async getScreenshot(format = 'png', options) {
27287
27437
  if (!this.host)
27288
27438
  return null;
27439
+ const includeBackground = options?.includeBackground ?? true;
27289
27440
  // Save critical state before screenshot to restore after
27290
27441
  const savedState = {
27291
27442
  objects: this.core.store.objects,
@@ -27297,7 +27448,7 @@ const KritzelEngine = class {
27297
27448
  translateY: this.core.store.state.translateY,
27298
27449
  scale: this.core.store.state.scale,
27299
27450
  };
27300
- const options = {
27451
+ const screenshotOptions = {
27301
27452
  filter: (node) => {
27302
27453
  // Exclude the context menu, debug panel, and awareness cursors from the screenshot
27303
27454
  if (node.tagName === 'KRITZEL-CONTEXT-MENU') {
@@ -27312,13 +27463,16 @@ const KritzelEngine = class {
27312
27463
  return true;
27313
27464
  },
27314
27465
  };
27466
+ if (!includeBackground) {
27467
+ screenshotOptions.backgroundColor = 'transparent';
27468
+ }
27315
27469
  let result;
27316
27470
  try {
27317
27471
  if (format === 'svg') {
27318
- result = await toSvg(this.host, options);
27472
+ result = await toSvg(this.host, screenshotOptions);
27319
27473
  }
27320
27474
  else {
27321
- result = await toPng(this.host, options);
27475
+ result = await toPng(this.host, screenshotOptions);
27322
27476
  }
27323
27477
  }
27324
27478
  finally {
@@ -27335,14 +27489,18 @@ const KritzelEngine = class {
27335
27489
  }
27336
27490
  return result;
27337
27491
  }
27338
- /** Exports the current viewport as a PNG file and triggers a browser download. */
27339
- async exportViewportAsPng() {
27492
+ /**
27493
+ * Exports the current viewport as a PNG file and triggers a browser download.
27494
+ * @param options - Optional export settings.
27495
+ * @param options.includeBackground - Whether to include the canvas background. Defaults to `true`.
27496
+ */
27497
+ async exportViewportAsPng(options) {
27340
27498
  try {
27341
27499
  const activeWorkspaceName = this.core.store.state?.activeWorkspace?.name || 'workspace';
27342
27500
  // timestamp format: YYYY-MM-DDTHH-mm-ss-sssZ, clearing colons/dots for safe filename
27343
27501
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
27344
27502
  const filename = `${activeWorkspaceName}-${timestamp}.png`;
27345
- const dataUrl = await this.getScreenshot('png');
27503
+ const dataUrl = await this.getScreenshot('png', options);
27346
27504
  if (!dataUrl) {
27347
27505
  console.error('Failed to export viewport as PNG: screenshot could not be generated');
27348
27506
  return;
@@ -27356,14 +27514,18 @@ const KritzelEngine = class {
27356
27514
  console.error('Failed to export viewport as PNG:', error);
27357
27515
  }
27358
27516
  }
27359
- /** Exports the current viewport as an SVG file and triggers a browser download. */
27360
- async exportViewportAsSvg() {
27517
+ /**
27518
+ * Exports the current viewport as an SVG file and triggers a browser download.
27519
+ * @param options - Optional export settings.
27520
+ * @param options.includeBackground - Whether to include the canvas background. Defaults to `true`.
27521
+ */
27522
+ async exportViewportAsSvg(options) {
27361
27523
  try {
27362
27524
  const activeWorkspaceName = this.core.store.state?.activeWorkspace?.name || 'workspace';
27363
27525
  // timestamp format: YYYY-MM-DDTHH-mm-ss-sssZ, clearing colons/dots for safe filename
27364
27526
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
27365
27527
  const filename = `${activeWorkspaceName}-${timestamp}.svg`;
27366
- const dataUrl = await this.getScreenshot('svg');
27528
+ const dataUrl = await this.getScreenshot('svg', options);
27367
27529
  if (!dataUrl) {
27368
27530
  console.error('Failed to export viewport as SVG: screenshot could not be generated');
27369
27531
  return;
@@ -28641,6 +28803,12 @@ const KritzelEngine = class {
28641
28803
  "user": [{
28642
28804
  "onUserChange": 0
28643
28805
  }],
28806
+ "globalContextMenuItems": [{
28807
+ "onGlobalContextMenuItemsChange": 0
28808
+ }],
28809
+ "objectContextMenuItems": [{
28810
+ "onObjectContextMenuItemsChange": 0
28811
+ }],
28644
28812
  "scaleMax": [{
28645
28813
  "validateScaleMax": 0
28646
28814
  }],
@@ -28684,7 +28852,7 @@ const KritzelEngine = class {
28684
28852
  };
28685
28853
  KritzelEngine.style = kritzelEngineCss();
28686
28854
 
28687
- 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}}`;
28855
+ 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}}`;
28688
28856
 
28689
28857
  const KritzelExport = class {
28690
28858
  constructor(hostRef) {
@@ -28880,7 +29048,7 @@ const KritzelIcon = class {
28880
29048
  };
28881
29049
  KritzelIcon.style = kritzelIconCss();
28882
29050
 
28883
- 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}`;
29051
+ 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}`;
28884
29052
 
28885
29053
  const KritzelInput = class {
28886
29054
  constructor(hostRef) {
@@ -29428,7 +29596,7 @@ const KritzelMoreMenu = class {
29428
29596
  };
29429
29597
  KritzelMoreMenu.style = kritzelMoreMenuCss();
29430
29598
 
29431
- 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}`;
29599
+ 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}`;
29432
29600
 
29433
29601
  const KritzelNumericInput = class {
29434
29602
  constructor(hostRef) {
@@ -29927,7 +30095,7 @@ const KritzelPortal = class {
29927
30095
  * This file is auto-generated by the version bump scripts.
29928
30096
  * Do not modify manually.
29929
30097
  */
29930
- const KRITZEL_VERSION = '0.3.12';
30098
+ const KRITZEL_VERSION = '0.3.14';
29931
30099
 
29932
30100
  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)}`;
29933
30101