@kritzel/editor 0.4.31 → 0.4.33

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 (197) hide show
  1. package/LICENSE.md +50 -50
  2. package/README.md +5 -5
  3. package/dist/cjs/{index-B92VHWr4.js → index-BAdxtEc7.js} +27 -9
  4. package/dist/cjs/kritzel-active-users_46.cjs.entry.js +1029 -366
  5. package/dist/cjs/kritzel-brush-style.cjs.entry.js +2 -2
  6. package/dist/cjs/kritzel-editor.cjs.js +3 -3
  7. package/dist/cjs/loader.cjs.js +2 -2
  8. package/dist/collection/collection-manifest.json +1 -1
  9. package/dist/collection/components/kritzel-active-users/kritzel-active-users.css +65 -65
  10. package/dist/collection/components/kritzel-avatar/kritzel-avatar.css +58 -58
  11. package/dist/collection/components/kritzel-avatar/kritzel-avatar.js +3 -3
  12. package/dist/collection/components/kritzel-back-to-content/kritzel-back-to-content.css +42 -42
  13. package/dist/collection/components/kritzel-back-to-content/kritzel-back-to-content.js +1 -1
  14. package/dist/collection/components/kritzel-brush-style/kritzel-brush-style.css +42 -42
  15. package/dist/collection/components/kritzel-brush-style/kritzel-brush-style.js +3 -3
  16. package/dist/collection/components/kritzel-button/kritzel-button.css +73 -73
  17. package/dist/collection/components/kritzel-button/kritzel-button.js +2 -2
  18. package/dist/collection/components/kritzel-color/kritzel-color.css +24 -24
  19. package/dist/collection/components/kritzel-color/kritzel-color.js +2 -2
  20. package/dist/collection/components/kritzel-color-palette/kritzel-color-palette.css +46 -46
  21. package/dist/collection/components/kritzel-color-palette/kritzel-color-palette.js +1 -1
  22. package/dist/collection/components/kritzel-context-menu/kritzel-context-menu.css +113 -112
  23. package/dist/collection/components/kritzel-context-menu/kritzel-context-menu.js +1 -1
  24. package/dist/collection/components/kritzel-current-user/kritzel-current-user.css +11 -11
  25. package/dist/collection/components/kritzel-current-user/kritzel-current-user.js +1 -1
  26. package/dist/collection/components/kritzel-current-user-dialog/kritzel-current-user-dialog.css +39 -39
  27. package/dist/collection/components/kritzel-current-user-dialog/kritzel-current-user-dialog.js +1 -1
  28. package/dist/collection/components/kritzel-dialog/kritzel-dialog.css +209 -209
  29. package/dist/collection/components/kritzel-dropdown/kritzel-dropdown.css +190 -190
  30. package/dist/collection/components/kritzel-dropdown/kritzel-dropdown.js +2 -2
  31. package/dist/collection/components/kritzel-editor/kritzel-editor.css +160 -160
  32. package/dist/collection/components/kritzel-editor/kritzel-editor.js +72 -46
  33. package/dist/collection/components/kritzel-export/kritzel-export.css +89 -89
  34. package/dist/collection/components/kritzel-export/kritzel-export.js +1 -1
  35. package/dist/collection/components/kritzel-font/kritzel-font.css +10 -10
  36. package/dist/collection/components/kritzel-font/kritzel-font.js +1 -1
  37. package/dist/collection/components/kritzel-font-family/kritzel-font-family.css +48 -48
  38. package/dist/collection/components/kritzel-font-family/kritzel-font-family.js +2 -2
  39. package/dist/collection/components/kritzel-font-size/kritzel-font-size.css +30 -30
  40. package/dist/collection/components/kritzel-font-size/kritzel-font-size.js +1 -1
  41. package/dist/collection/components/kritzel-input/kritzel-input.css +69 -69
  42. package/dist/collection/components/kritzel-input/kritzel-input.js +1 -1
  43. package/dist/collection/components/kritzel-line-endings/kritzel-line-endings.css +60 -60
  44. package/dist/collection/components/kritzel-line-endings/kritzel-line-endings.js +3 -3
  45. package/dist/collection/components/kritzel-loading-overlay/kritzel-loading-overlay.css +54 -54
  46. package/dist/collection/components/kritzel-loading-overlay/kritzel-loading-overlay.js +1 -1
  47. package/dist/collection/components/kritzel-login-dialog/kritzel-login-dialog.css +98 -98
  48. package/dist/collection/components/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
  49. package/dist/collection/components/kritzel-master-detail/kritzel-master-detail.css +190 -190
  50. package/dist/collection/components/kritzel-master-detail/kritzel-master-detail.js +3 -3
  51. package/dist/collection/components/kritzel-menu/kritzel-menu.css +35 -34
  52. package/dist/collection/components/kritzel-menu/kritzel-menu.js +1 -1
  53. package/dist/collection/components/kritzel-menu-item/kritzel-menu-item.css +166 -166
  54. package/dist/collection/components/kritzel-menu-item/kritzel-menu-item.js +3 -3
  55. package/dist/collection/components/kritzel-more-menu/kritzel-more-menu.css +58 -58
  56. package/dist/collection/components/kritzel-more-menu/kritzel-more-menu.js +4 -4
  57. package/dist/collection/components/kritzel-notification-card/kritzel-notification-card.css +101 -101
  58. package/dist/collection/components/kritzel-numeric-input/kritzel-numeric-input.css +102 -102
  59. package/dist/collection/components/kritzel-numeric-input/kritzel-numeric-input.js +1 -1
  60. package/dist/collection/components/kritzel-opacity-slider/kritzel-opacity-slider.css +85 -85
  61. package/dist/collection/components/kritzel-opacity-slider/kritzel-opacity-slider.js +1 -1
  62. package/dist/collection/components/kritzel-pill-tabs/kritzel-pill-tabs.css +68 -68
  63. package/dist/collection/components/kritzel-pill-tabs/kritzel-pill-tabs.js +2 -2
  64. package/dist/collection/components/kritzel-portal/kritzel-portal.js +1 -1
  65. package/dist/collection/components/kritzel-settings/kritzel-settings.css +137 -137
  66. package/dist/collection/components/kritzel-settings/kritzel-settings.js +1 -1
  67. package/dist/collection/components/kritzel-shape-fill/kritzel-shape-fill.css +47 -47
  68. package/dist/collection/components/kritzel-shape-fill/kritzel-shape-fill.js +4 -4
  69. package/dist/collection/components/kritzel-share-dialog/kritzel-share-dialog.css +150 -150
  70. package/dist/collection/components/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
  71. package/dist/collection/components/kritzel-slide-toggle/kritzel-slide-toggle.css +48 -48
  72. package/dist/collection/components/kritzel-slide-toggle/kritzel-slide-toggle.js +1 -1
  73. package/dist/collection/components/kritzel-split-button/kritzel-split-button.css +78 -78
  74. package/dist/collection/components/kritzel-split-button/kritzel-split-button.js +3 -3
  75. package/dist/collection/components/kritzel-stroke-size/kritzel-stroke-size.css +37 -37
  76. package/dist/collection/components/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
  77. package/dist/collection/components/kritzel-tool-config/kritzel-tool-config.css +38 -38
  78. package/dist/collection/components/kritzel-tool-config/kritzel-tool-config.js +1 -1
  79. package/dist/collection/components/kritzel-toolbar/kritzel-toolbar.css +347 -347
  80. package/dist/collection/components/kritzel-toolbar/kritzel-toolbar.js +12 -16
  81. package/dist/collection/components/kritzel-tooltip/kritzel-tooltip.css +18 -18
  82. package/dist/collection/components/kritzel-tooltip/kritzel-tooltip.js +2 -2
  83. package/dist/collection/components/kritzel-utility-panel/kritzel-utility-panel.css +45 -45
  84. package/dist/collection/components/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  85. package/dist/collection/components/kritzel-workspace-manager/kritzel-workspace-manager.css +16 -16
  86. package/dist/collection/components/kritzel-workspace-manager/kritzel-workspace-manager.js +1 -1
  87. package/dist/collection/components/kritzel-zoom-panel/kritzel-zoom-panel.css +72 -72
  88. package/dist/collection/components/kritzel-zoom-panel/kritzel-zoom-panel.js +1 -1
  89. package/dist/components/index.js +1 -1
  90. package/dist/components/kritzel-active-users.js +1 -1
  91. package/dist/components/kritzel-avatar.js +1 -1
  92. package/dist/components/kritzel-awareness-cursors.js +1 -1
  93. package/dist/components/kritzel-back-to-content.js +1 -1
  94. package/dist/components/kritzel-brush-style.js +4 -4
  95. package/dist/components/kritzel-button.js +1 -1
  96. package/dist/components/kritzel-color-palette.js +1 -1
  97. package/dist/components/kritzel-color.js +1 -1
  98. package/dist/components/kritzel-context-menu.js +1 -1
  99. package/dist/components/kritzel-current-user-dialog.js +1 -1
  100. package/dist/components/kritzel-current-user.js +1 -1
  101. package/dist/components/kritzel-cursor-trail.js +1 -1
  102. package/dist/components/kritzel-dialog.js +1 -1
  103. package/dist/components/kritzel-dropdown.js +1 -1
  104. package/dist/components/kritzel-editor.js +108 -81
  105. package/dist/components/kritzel-engine.js +1 -1
  106. package/dist/components/kritzel-export.js +1 -1
  107. package/dist/components/kritzel-font-family.js +1 -1
  108. package/dist/components/kritzel-font-size.js +1 -1
  109. package/dist/components/kritzel-font.js +1 -1
  110. package/dist/components/kritzel-icon.js +1 -1
  111. package/dist/components/kritzel-input.js +1 -1
  112. package/dist/components/kritzel-line-endings.js +1 -1
  113. package/dist/components/kritzel-loading-overlay.js +1 -1
  114. package/dist/components/kritzel-login-dialog.js +1 -1
  115. package/dist/components/kritzel-master-detail.js +1 -1
  116. package/dist/components/kritzel-menu-item.js +1 -1
  117. package/dist/components/kritzel-menu.js +1 -1
  118. package/dist/components/kritzel-more-menu.js +1 -1
  119. package/dist/components/kritzel-notification-card.js +1 -1
  120. package/dist/components/kritzel-numeric-input.js +1 -1
  121. package/dist/components/kritzel-opacity-slider.js +1 -1
  122. package/dist/components/kritzel-pill-tabs.js +1 -1
  123. package/dist/components/kritzel-portal.js +1 -1
  124. package/dist/components/kritzel-settings.js +1 -1
  125. package/dist/components/kritzel-shape-fill.js +1 -1
  126. package/dist/components/kritzel-share-dialog.js +1 -1
  127. package/dist/components/kritzel-slide-toggle.js +1 -1
  128. package/dist/components/kritzel-split-button.js +1 -1
  129. package/dist/components/kritzel-stroke-size.js +1 -1
  130. package/dist/components/kritzel-tool-config.js +1 -1
  131. package/dist/components/kritzel-toolbar.js +1 -1
  132. package/dist/components/kritzel-tooltip.js +1 -1
  133. package/dist/components/kritzel-utility-panel.js +1 -1
  134. package/dist/components/kritzel-watermark.js +1 -1
  135. package/dist/components/kritzel-workspace-manager.js +1 -1
  136. package/dist/components/kritzel-zoom-panel.js +1 -1
  137. package/dist/components/{p-CrIEmItB.js → p-2DAZSvN6.js} +5 -5
  138. package/dist/components/{p-CmjXRLdr.js → p-2gylYpXk.js} +7 -7
  139. package/dist/components/{p-BN8VWPlq.js → p-B-Divd0Q.js} +7 -7
  140. package/dist/components/{p-R1D8Sr0l.js → p-B-U13Ew1.js} +3 -3
  141. package/dist/components/{p-BZ_KnHdR.js → p-B1rmcPZr.js} +7 -7
  142. package/dist/components/{p-B_gT0lCn.js → p-B2-SxV8E.js} +3 -3
  143. package/dist/components/p-B6Z_VKKH.js +214 -0
  144. package/dist/components/{p-CVxGF4bJ.js → p-B8tHdknP.js} +5 -5
  145. package/dist/components/{p-CoNexfpB.js → p-BDsuJNT_.js} +3 -3
  146. package/dist/components/{p-BvG3JO85.js → p-BMi-i7sC.js} +3 -3
  147. package/dist/components/{p-Cy_cLtOP.js → p-BZ0ReYAA.js} +18 -14
  148. package/dist/components/{p-DZsSiMnA.js → p-BeCy6w6M.js} +770 -173
  149. package/dist/components/{p-4-qLegHb.js → p-Bipc1XvF.js} +4 -4
  150. package/dist/components/{p-CS3YZVYE.js → p-BmFJelgk.js} +2 -2
  151. package/dist/components/{p-DqOC_Yck.js → p-BpvSYxxN.js} +6 -6
  152. package/dist/components/{p-peZjvnkK.js → p-C0ns8IPO.js} +2 -2
  153. package/dist/components/{p-ClfOtiNp.js → p-C1_r9nJU.js} +3 -3
  154. package/dist/components/{p-GbCxpbQ6.js → p-C2ySiAXO.js} +3 -3
  155. package/dist/components/{p-B3Tqoyl9.js → p-C3KlONnT.js} +3 -3
  156. package/dist/components/{p-B5xYV1o3.js → p-C68YXjuL.js} +2 -2
  157. package/dist/components/{p-DJxgPPfs.js → p-CCuNN278.js} +3 -3
  158. package/dist/components/{p-Ds0uNtwQ.js → p-CNH7N3Aq.js} +4 -4
  159. package/dist/components/{p-DVv8ChhE.js → p-CO1cJlfg.js} +4 -4
  160. package/dist/components/{p-Cp4e4oTE.js → p-CqHKGLYE.js} +2 -2
  161. package/dist/components/{p-Blq9a1ni.js → p-CrEWqua9.js} +6 -6
  162. package/dist/components/{p-CvaxFYS0.js → p-Cv2nqOL8.js} +8 -8
  163. package/dist/components/{p-CzUeIini.js → p-D-1ixLxq.js} +13 -13
  164. package/dist/components/{p-BfMlwIcG.js → p-DF8p-DxR.js} +3 -3
  165. package/dist/components/{p-QEue33R5.js → p-DQ3VKzAS.js} +3 -3
  166. package/dist/components/{p-Ckqh1tqY.js → p-DRe-rTlX.js} +27 -31
  167. package/dist/components/{p-McY5wZ0h.js → p-DSyb29RF.js} +2 -2
  168. package/dist/components/{p-D0tPTPkR.js → p-DYDruZIw.js} +3 -3
  169. package/dist/components/{p-kOINnzaR.js → p-D_JxJxQ6.js} +7 -7
  170. package/dist/components/{p-BDjRSoAc.js → p-Dko_6jIh.js} +2 -2
  171. package/dist/components/{p-BjFrt1q0.js → p-DnHvqeyr.js} +3 -3
  172. package/dist/components/{p-BrGJIoGK.js → p-DqMikMrS.js} +3 -3
  173. package/dist/components/p-DsnHq8en.js +55 -0
  174. package/dist/components/{p-DXZBWJBt.js → p-DxFNLy9X.js} +4 -4
  175. package/dist/components/{p-5qkOM1RJ.js → p-Dzr6X2aj.js} +16 -4
  176. package/dist/components/{p-DXuf225S.js → p-HbHo7awi.js} +3 -3
  177. package/dist/components/{p-CwBxnzYu.js → p-Qbk7xE91.js} +3 -3
  178. package/dist/components/{p-h_uh_Njf.js → p-VYGV0cr3.js} +3 -3
  179. package/dist/components/{p-DyRJFg4w.js → p-YGBl60lb.js} +2 -2
  180. package/dist/components/{p-hQwVRh0t.js → p-clFfXKKn.js} +7 -7
  181. package/dist/components/{p-SLnqczCS.js → p-dUcCDLDF.js} +3 -3
  182. package/dist/components/{p-B6UJztrf.js → p-kXnNX65j.js} +4 -4
  183. package/dist/esm/{index-OjbYJz-P.js → index-YR-6hzAW.js} +27 -10
  184. package/dist/esm/kritzel-active-users_46.entry.js +1029 -366
  185. package/dist/esm/kritzel-brush-style.entry.js +2 -2
  186. package/dist/esm/kritzel-editor.js +4 -4
  187. package/dist/esm/loader.js +3 -3
  188. package/dist/kritzel-editor/kritzel-editor.esm.js +4 -4
  189. package/dist/kritzel-editor/{p-501047d8.entry.js → p-3a0f60b0.entry.js} +2 -2
  190. package/dist/kritzel-editor/{p-OjbYJz-P.js → p-YR-6hzAW.js} +27 -10
  191. package/dist/kritzel-editor/{p-60319edb.entry.js → p-adc45d46.entry.js} +1029 -366
  192. package/dist/types/components/kritzel-editor/kritzel-editor.d.ts +9 -2
  193. package/dist/types/components.d.ts +15 -15
  194. package/dist/types/stencil-public-runtime.d.ts +61 -55
  195. package/package.json +3 -3
  196. package/dist/components/p-BGmTmdLe.js +0 -167
  197. package/dist/components/p-DOJCDPVD.js +0 -55
@@ -1,9 +1,9 @@
1
- import { p as proxyCustomElement, H, c as createEvent, h, d as Host, t as transformTag } from './p-5qkOM1RJ.js';
2
- import { a as KritzelMouseButton, d as defineCustomElement$3 } from './p-Cp4e4oTE.js';
3
- import { a as KritzelBaseObject, b as KritzelLine, c as KritzelMathHelper, e as KritzelGeometryHelper, f as KritzelColorHelper, D as DEFAULT_COLOR_PALETTE, g as KritzelPath, O as ObjectHelper, h as KritzelThemeManager, d as defineCustomElement$4 } from './p-Cy_cLtOP.js';
1
+ import { p as proxyCustomElement, H, c as createEvent, h, d as Host, t as transformTag } from './p-Dzr6X2aj.js';
2
+ import { a as KritzelMouseButton, d as defineCustomElement$3 } from './p-CqHKGLYE.js';
3
+ import { a as KritzelBaseObject, b as KritzelLine, c as KritzelMathHelper, e as KritzelGeometryHelper, f as KritzelColorHelper, D as DEFAULT_COLOR_PALETTE, g as KritzelPath, O as ObjectHelper, h as KritzelThemeManager, d as defineCustomElement$4 } from './p-BZ0ReYAA.js';
4
4
  import { c as commonjsGlobal } from './p-BFTU3MAI.js';
5
- import { A as ABSOLUTE_SCALE_MAX, a as ABSOLUTE_SCALE_MIN, d as defineCustomElement$1 } from './p-SLnqczCS.js';
6
- import { a as KritzelIconRegistry, d as defineCustomElement$2 } from './p-BGmTmdLe.js';
5
+ import { A as ABSOLUTE_SCALE_MAX, a as ABSOLUTE_SCALE_MIN, d as defineCustomElement$1 } from './p-dUcCDLDF.js';
6
+ import { a as KritzelIconRegistry, d as defineCustomElement$2 } from './p-B6Z_VKKH.js';
7
7
 
8
8
  /**
9
9
  * Represents a visual selection box used for multi-object selection on the canvas.
@@ -22165,7 +22165,6 @@ class Mark {
22165
22165
  if (!type)
22166
22166
  throw new RangeError(`There is no mark type ${json.type} in this schema`);
22167
22167
  let mark = type.create(json.attrs);
22168
- type.checkAttrs(mark.attrs);
22169
22168
  return mark;
22170
22169
  }
22171
22170
  /**
@@ -23145,11 +23144,11 @@ class Node {
23145
23144
  */
23146
23145
  check() {
23147
23146
  this.type.checkContent(this.content);
23148
- this.type.checkAttrs(this.attrs);
23147
+ checkAttrs(this.type.attrs, this.attrs, "node", this.type.name);
23149
23148
  let copy = Mark.none;
23150
23149
  for (let i = 0; i < this.marks.length; i++) {
23151
23150
  let mark = this.marks[i];
23152
- mark.type.checkAttrs(mark.attrs);
23151
+ checkAttrs(mark.type.attrs, mark.attrs, "mark", mark.type.name);
23153
23152
  copy = mark.addToSet(copy);
23154
23153
  }
23155
23154
  if (!Mark.sameSet(copy, this.marks))
@@ -23190,7 +23189,6 @@ class Node {
23190
23189
  }
23191
23190
  let content = Fragment.fromJSON(schema, json.content);
23192
23191
  let node = schema.nodeType(json.type).create(json.attrs, content, marks);
23193
- node.type.checkAttrs(node.attrs);
23194
23192
  return node;
23195
23193
  }
23196
23194
  }
@@ -23240,6 +23238,15 @@ function wrapMarks(marks, str) {
23240
23238
  str = marks[i].type.name + "(" + str + ")";
23241
23239
  return str;
23242
23240
  }
23241
+ function checkAttrs(attrs, values, type, name) {
23242
+ for (let attr in values)
23243
+ if (!(attr in attrs))
23244
+ throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
23245
+ for (let attr in attrs) {
23246
+ if (attrs[attr].validate)
23247
+ attrs[attr].validate(values[attr]);
23248
+ }
23249
+ }
23243
23250
 
23244
23251
  /**
23245
23252
  Instances of this class represent a match state of a node type's
@@ -23694,27 +23701,21 @@ function defaultAttrs(attrs) {
23694
23701
  function computeAttrs(attrs, value) {
23695
23702
  let built = Object.create(null);
23696
23703
  for (let name in attrs) {
23704
+ let attr = attrs[name];
23697
23705
  let given = value && value[name];
23698
23706
  if (given === undefined) {
23699
- let attr = attrs[name];
23700
23707
  if (attr.hasDefault)
23701
23708
  given = attr.default;
23702
23709
  else
23703
23710
  throw new RangeError("No value supplied for attribute " + name);
23704
23711
  }
23712
+ else if (attr.validate) {
23713
+ attr.validate(given);
23714
+ }
23705
23715
  built[name] = given;
23706
23716
  }
23707
23717
  return built;
23708
23718
  }
23709
- function checkAttrs(attrs, values, type, name) {
23710
- for (let attr in values)
23711
- if (!(attr in attrs))
23712
- throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
23713
- for (let attr in attrs) {
23714
- if (attrs[attr].validate)
23715
- attrs[attr].validate(values[attr]);
23716
- }
23717
- }
23718
23719
  function initAttrs(typeName, attrs) {
23719
23720
  let result = Object.create(null);
23720
23721
  if (attrs)
@@ -23886,11 +23887,9 @@ let NodeType$1 = class NodeType {
23886
23887
  throw new RangeError(`Invalid content for node ${this.name}: ${content.toString().slice(0, 50)}`);
23887
23888
  }
23888
23889
  /**
23889
- @internal
23890
+ @internal no longer useful, but called by old prosemirror-view versions
23890
23891
  */
23891
- checkAttrs(attrs) {
23892
- checkAttrs(this.attrs, attrs, "node", this.name);
23893
- }
23892
+ checkAttrs(attrs) { }
23894
23893
  /**
23895
23894
  Check whether the given mark type is allowed in this node.
23896
23895
  */
@@ -24037,12 +24036,6 @@ class MarkType {
24037
24036
  return set[i];
24038
24037
  }
24039
24038
  /**
24040
- @internal
24041
- */
24042
- checkAttrs(attrs) {
24043
- checkAttrs(this.attrs, attrs, "mark", this.name);
24044
- }
24045
- /**
24046
24039
  Queries whether a given mark type is
24047
24040
  [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one.
24048
24041
  */
@@ -30734,7 +30727,8 @@ function nodeLen(node) {
30734
30727
  }
30735
30728
  function isIgnorable(dom, dir) {
30736
30729
  let desc = dom.pmViewDesc;
30737
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
30730
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
30731
+ : dom.nodeType == 1 && dom.contentEditable == "false";
30738
30732
  }
30739
30733
  function skipIgnoredNodes(view, dir) {
30740
30734
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -31323,12 +31317,11 @@ function addContext(slice, context) {
31323
31317
  if (!type || type.hasRequiredAttrs())
31324
31318
  break;
31325
31319
  try {
31326
- type.checkAttrs(array[i + 1]);
31320
+ content = Fragment.from(type.create(array[i + 1], content));
31327
31321
  }
31328
31322
  catch (e) {
31329
31323
  break;
31330
31324
  }
31331
- content = Fragment.from(type.create(array[i + 1], content));
31332
31325
  openStart++;
31333
31326
  openEnd++;
31334
31327
  }
@@ -31808,7 +31801,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
31808
31801
  if (!view.composing) {
31809
31802
  view.domObserver.flush();
31810
31803
  let { state } = view, $pos = state.selection.$to;
31811
- if (state.selection instanceof TextSelection &&
31804
+ if (state.selection instanceof TextSelection && state.selection.empty &&
31812
31805
  (state.storedMarks ||
31813
31806
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
31814
31807
  chrome && windows$1 && selectionBeforeUneditable(view))) { // Issue #1500
@@ -33445,9 +33438,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
33445
33438
  // as being an iOS enter press), just dispatch an Enter key instead.
33446
33439
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
33447
33440
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
33448
- (!inlineChange && $from.pos < parse.doc.content.size &&
33449
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
33450
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
33441
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
33451
33442
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
33452
33443
  view.input.lastIOSEnter = 0;
33453
33444
  return;
@@ -33598,6 +33589,16 @@ function looksLikeBackspace(old, start, end, $newStart, $newEnd) {
33598
33589
  // The fragments after the join point must match
33599
33590
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
33600
33591
  }
33592
+ function looksLikeEnter(content, from, to) {
33593
+ let newTextlines = 0, newLeaves = 0;
33594
+ content.nodesBetween(from, to, (node, pos) => {
33595
+ if (node.isTextblock && pos >= from && pos < to)
33596
+ newTextlines++;
33597
+ else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
33598
+ newLeaves++;
33599
+ });
33600
+ return newLeaves == 0 && newTextlines == 1;
33601
+ }
33601
33602
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
33602
33603
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
33603
33604
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
@@ -38067,9 +38068,8 @@ class KritzelSelectionTool extends KritzelBaseTool {
38067
38068
  }
38068
38069
  if (selectedObject && selectedObject.isSelected === false && selectedObject?.objects.length === 1) {
38069
38070
  const firstObj = selectedObject.objects[0];
38070
- if (KritzelClassHelper.isInstanceOf(firstObj, 'KritzelDynamicObject')) {
38071
- // Selected single dynamic objects hand pointer interaction to their
38072
- // embedded DOM content. Unselected dynamic objects remain selectable.
38071
+ if (ObjectHelper.isKritzelEmbeddedObject(firstObj)) {
38072
+ // Selected embedded objects hand pointer interaction to their content.
38073
38073
  if (firstObj.isSelected && this._core.store.selectionGroup?.objects.length === 1)
38074
38074
  return;
38075
38075
  }
@@ -40238,7 +40238,7 @@ class KritzelDynamicObject extends KritzelBaseObject {
40238
40238
  }
40239
40239
  applyInteractiveState() {
40240
40240
  const pointerEvents = this.isInteractive ? 'auto' : 'none';
40241
- const contentCursor = this.isInteractive ? 'auto' : '';
40241
+ const contentCursor = this.isInteractive ? 'var(--kritzel-global-default-cursor, auto)' : '';
40242
40242
  if (this.element) {
40243
40243
  this.element.style.pointerEvents = pointerEvents;
40244
40244
  this.element.style.cursor = contentCursor;
@@ -40274,7 +40274,7 @@ class KritzelDynamicObject extends KritzelBaseObject {
40274
40274
  if (!this.isInteractive) {
40275
40275
  return false;
40276
40276
  }
40277
- const focusHosts = this.getFocusHosts();
40277
+ const focusHosts = this.getEmbeddedContentRoots();
40278
40278
  // Primary path: locate the focused input-like element by walking from each host through
40279
40279
  // `:focus` (piercing open shadow roots). This works in real browsers even when the engine
40280
40280
  // and editor are nested web components, because it never relies on the document-level
@@ -40291,7 +40291,7 @@ class KritzelDynamicObject extends KritzelBaseObject {
40291
40291
  }
40292
40292
  return false;
40293
40293
  }
40294
- getFocusHosts() {
40294
+ getEmbeddedContentRoots() {
40295
40295
  const hosts = [];
40296
40296
  if (this.element) {
40297
40297
  hosts.push(this.element);
@@ -40504,11 +40504,11 @@ class KritzelDynamicObject extends KritzelBaseObject {
40504
40504
  * @returns A serializable object with htmlString and dimension snapshots
40505
40505
  */
40506
40506
  serialize() {
40507
- const { _core, _elementRef, element, totalWidth, totalHeight, isSelected, isHovered, isMounted, isInteractive, resizing, markedForRemoval, isVisible, ...props } = this;
40507
+ const { _core, _elementRef, element, totalWidth, totalHeight, isSelected, isHovered, isMounted, isInteractive, resizing, markedForRemoval, isVisible, rendererData, ...props } = this;
40508
40508
  const cloned = structuredClone(props);
40509
40509
  // Include rendererKey and rendererData for lifecycle-driven rendering
40510
40510
  cloned.rendererKey = this.rendererKey;
40511
- cloned.rendererData = this.rendererData;
40511
+ cloned.rendererData = this.serializeRendererData();
40512
40512
  // Store HTML as string for fallback/compatibility when renderer is unavailable
40513
40513
  cloned.htmlString = element ? element.outerHTML : '';
40514
40514
  // Capture dimension snapshot at serialization time
@@ -40516,6 +40516,19 @@ class KritzelDynamicObject extends KritzelBaseObject {
40516
40516
  cloned.serializedHeight = this.height;
40517
40517
  return cloned;
40518
40518
  }
40519
+ serializeRendererData() {
40520
+ if (this.rendererKey) {
40521
+ const renderer = KritzelDynamicObjectRendererRegistry.get(this.rendererKey);
40522
+ if (renderer?.onSerialize) {
40523
+ return structuredClone(renderer.onSerialize({
40524
+ object: this,
40525
+ container: this.isMounted && this.elementRef instanceof HTMLElement ? this.elementRef : null,
40526
+ data: this.rendererData,
40527
+ }));
40528
+ }
40529
+ }
40530
+ return structuredClone(this.rendererData);
40531
+ }
40519
40532
  /**
40520
40533
  * Deserializes the dynamic object from a plain object.
40521
40534
  * Reconstructs the element from stored HTML string with fallback to placeholder.
@@ -40548,6 +40561,452 @@ class KritzelDynamicObject extends KritzelBaseObject {
40548
40561
  }
40549
40562
  }
40550
40563
 
40564
+ const IFRAME_STATE_MESSAGE = 'kritzel-iframe-state';
40565
+ const IFRAME_PARENT_STATE_MESSAGE = 'kritzel-iframe-parent-state';
40566
+ const IFRAME_POINTER_MESSAGE = 'kritzel-iframe-pointer';
40567
+ const IFRAME_CONTEXT_MENU_MESSAGE = 'kritzel-iframe-contextmenu';
40568
+ const SUPPORTED_SANDBOX_TOKENS = new Set([
40569
+ 'allow-downloads',
40570
+ 'allow-forms',
40571
+ 'allow-modals',
40572
+ 'allow-orientation-lock',
40573
+ 'allow-pointer-lock',
40574
+ 'allow-popups',
40575
+ 'allow-popups-to-escape-sandbox',
40576
+ 'allow-presentation',
40577
+ 'allow-same-origin',
40578
+ 'allow-scripts',
40579
+ 'allow-top-navigation-by-user-activation',
40580
+ ]);
40581
+ const iframePointerBridgeStarts = new WeakMap();
40582
+ class KritzelIframeObject extends KritzelBaseObject {
40583
+ __class__ = 'KritzelIframeObject';
40584
+ content = { html: '', css: '', script: '' };
40585
+ loadingContent;
40586
+ isLoading = false;
40587
+ state = {};
40588
+ title = 'Embedded content';
40589
+ sandbox = ['allow-scripts'];
40590
+ borderRadius;
40591
+ boxShadow;
40592
+ get html() { return this.content.html; }
40593
+ set html(value) { this.content = { ...this.content, html: value }; }
40594
+ get css() { return this.content.css; }
40595
+ set css(value) { this.content = { ...this.content, css: value }; }
40596
+ get script() { return this.content.script; }
40597
+ set script(value) { this.content = { ...this.content, script: value }; }
40598
+ messageListener = null;
40599
+ constructor(config) {
40600
+ super();
40601
+ this.content = {
40602
+ html: config?.content?.html ?? config?.html ?? '',
40603
+ css: config?.content?.css ?? config?.css ?? '',
40604
+ script: config?.content?.script ?? config?.script ?? '',
40605
+ };
40606
+ this.loadingContent = config?.loadingContent ? {
40607
+ html: config.loadingContent.html ?? '',
40608
+ css: config.loadingContent.css ?? '',
40609
+ script: config.loadingContent.script ?? '',
40610
+ } : undefined;
40611
+ this.isLoading = config?.isLoading ?? false;
40612
+ this.state = structuredClone(config?.state ?? {});
40613
+ this.title = config?.title ?? 'Embedded content';
40614
+ this.sandbox = this.normalizeSandbox(config?.sandbox);
40615
+ this.borderRadius = config?.borderRadius;
40616
+ this.boxShadow = config?.boxShadow;
40617
+ this.translateX = config?.translateX ?? 0;
40618
+ this.translateY = config?.translateY ?? 0;
40619
+ this.rotation = KritzelMathHelper.degreesToRadians(config?.rotation ?? 0);
40620
+ this.scale = config?.scale ?? 1;
40621
+ this.width = config?.width ?? 0;
40622
+ this.height = config?.height ?? 0;
40623
+ }
40624
+ static create(core, config) {
40625
+ const object = new KritzelIframeObject(config);
40626
+ object._core = core;
40627
+ object.id = object.generateId();
40628
+ object.workspaceId = core.store.state.activeWorkspace.id;
40629
+ object.userId = core.user?.id;
40630
+ object.scale = config?.scale ?? core.store.state.scale;
40631
+ object.zIndex = core.store.currentZIndex;
40632
+ return object;
40633
+ }
40634
+ get sandboxAttribute() {
40635
+ return this.sandbox.join(' ');
40636
+ }
40637
+ mount(iframe) {
40638
+ if (this.isMounted && this.elementRef === iframe) {
40639
+ return;
40640
+ }
40641
+ if (this.isMounted) {
40642
+ this.unmount();
40643
+ }
40644
+ this.elementRef = iframe;
40645
+ this.isMounted = true;
40646
+ iframe.title = this.title;
40647
+ iframe.setAttribute('sandbox', this.sandboxAttribute);
40648
+ iframe.style.pointerEvents = this.isInteractive ? 'auto' : 'none';
40649
+ this.messageListener = event => this.handleMessage(event);
40650
+ window.addEventListener('message', this.messageListener);
40651
+ iframe.srcdoc = this.createSourceDocument();
40652
+ this.onMount(this.createLifecycleContext());
40653
+ }
40654
+ unmount() {
40655
+ if (!this.isMounted) {
40656
+ return;
40657
+ }
40658
+ const nextState = this.onUnmount(this.createLifecycleContext());
40659
+ if (nextState !== undefined) {
40660
+ this.state = structuredClone(nextState);
40661
+ }
40662
+ if (this.messageListener) {
40663
+ window.removeEventListener('message', this.messageListener);
40664
+ this.messageListener = null;
40665
+ }
40666
+ this.isMounted = false;
40667
+ this._elementRef = null;
40668
+ }
40669
+ setContent(content) {
40670
+ this.content = {
40671
+ html: content.html ?? this.content.html,
40672
+ css: content.css ?? this.content.css,
40673
+ script: content.script ?? this.content.script,
40674
+ };
40675
+ this.refreshDocument();
40676
+ this.persistUpdate();
40677
+ }
40678
+ setLoadingContent(content) {
40679
+ this.loadingContent = {
40680
+ html: content.html ?? this.loadingContent?.html ?? '',
40681
+ css: content.css ?? this.loadingContent?.css ?? '',
40682
+ script: content.script ?? this.loadingContent?.script ?? '',
40683
+ };
40684
+ this.refreshDocument();
40685
+ this.persistUpdate();
40686
+ }
40687
+ setLoading(isLoading) {
40688
+ this.isLoading = isLoading;
40689
+ this.refreshDocument();
40690
+ this.persistUpdate();
40691
+ }
40692
+ getActiveContent() {
40693
+ const activeLoadingContent = this.isLoading ? this.loadingContent : undefined;
40694
+ return {
40695
+ html: activeLoadingContent?.html ?? this.content.html,
40696
+ css: activeLoadingContent?.css ?? this.content.css,
40697
+ script: activeLoadingContent?.script ?? this.content.script,
40698
+ };
40699
+ }
40700
+ setState(state) {
40701
+ this.state = structuredClone(state);
40702
+ this.elementRef?.contentWindow?.postMessage({ type: IFRAME_PARENT_STATE_MESSAGE, state: this.state }, '*');
40703
+ this.persistUpdate();
40704
+ }
40705
+ setIsInteractive(isInteractive) {
40706
+ this.isInteractive = isInteractive;
40707
+ if (this.isMounted && this.elementRef) {
40708
+ this.elementRef.style.pointerEvents = isInteractive ? 'auto' : 'none';
40709
+ if (!isInteractive) {
40710
+ this.elementRef.blur();
40711
+ }
40712
+ }
40713
+ }
40714
+ hasFocusedInputElement() {
40715
+ return this.isInteractive && this.isMounted && document.activeElement === this.elementRef;
40716
+ }
40717
+ getEmbeddedContentRoots() {
40718
+ return this.isMounted && this.elementRef instanceof HTMLElement && this.elementRef.tagName === 'IFRAME' ? [this.elementRef] : [];
40719
+ }
40720
+ onMount(_context) { }
40721
+ onSerialize(context) {
40722
+ return context.state;
40723
+ }
40724
+ onUnmount(context) {
40725
+ return context.state;
40726
+ }
40727
+ serialize() {
40728
+ const nextState = this.onSerialize(this.createLifecycleContext());
40729
+ this.state = structuredClone(nextState);
40730
+ const messageListener = this.messageListener;
40731
+ this.messageListener = null;
40732
+ try {
40733
+ const serialized = super.serialize();
40734
+ delete serialized.messageListener;
40735
+ return serialized;
40736
+ }
40737
+ finally {
40738
+ this.messageListener = messageListener;
40739
+ }
40740
+ }
40741
+ deserialize(object) {
40742
+ super.deserialize(object);
40743
+ const nextContent = object.content && typeof object.content === 'object' ? object.content : {};
40744
+ const nextLoadingContent = object.loadingContent && typeof object.loadingContent === 'object' ? object.loadingContent : undefined;
40745
+ this.content = {
40746
+ html: typeof nextContent.html === 'string' ? nextContent.html : typeof object.html === 'string' ? object.html : '',
40747
+ css: typeof nextContent.css === 'string' ? nextContent.css : typeof object.css === 'string' ? object.css : '',
40748
+ script: typeof nextContent.script === 'string' ? nextContent.script : typeof object.script === 'string' ? object.script : '',
40749
+ };
40750
+ this.loadingContent = nextLoadingContent ? {
40751
+ html: typeof nextLoadingContent.html === 'string' ? nextLoadingContent.html : '',
40752
+ css: typeof nextLoadingContent.css === 'string' ? nextLoadingContent.css : '',
40753
+ script: typeof nextLoadingContent.script === 'string' ? nextLoadingContent.script : '',
40754
+ } : undefined;
40755
+ this.isLoading = typeof object.isLoading === 'boolean' ? object.isLoading : false;
40756
+ this.state = object.state && typeof object.state === 'object' ? structuredClone(object.state) : {};
40757
+ this.title = typeof object.title === 'string' ? object.title : 'Embedded content';
40758
+ this.sandbox = this.normalizeSandbox(Array.isArray(object.sandbox) ? object.sandbox.filter((token) => typeof token === 'string') : undefined);
40759
+ this.borderRadius = (typeof object.borderRadius === 'number' || typeof object.borderRadius === 'string') ? object.borderRadius : undefined;
40760
+ this.boxShadow = typeof object.boxShadow === 'string' ? object.boxShadow : undefined;
40761
+ this.messageListener = null;
40762
+ return this;
40763
+ }
40764
+ copy() {
40765
+ const copiedObject = super.copy();
40766
+ copiedObject.content = { ...this.content };
40767
+ copiedObject.loadingContent = this.loadingContent ? { ...this.loadingContent } : undefined;
40768
+ copiedObject.isLoading = this.isLoading;
40769
+ copiedObject.state = structuredClone(this.state);
40770
+ copiedObject.sandbox = [...this.sandbox];
40771
+ copiedObject.borderRadius = this.borderRadius;
40772
+ copiedObject.boxShadow = this.boxShadow;
40773
+ copiedObject.messageListener = null;
40774
+ copiedObject._elementRef = null;
40775
+ return copiedObject;
40776
+ }
40777
+ clone() {
40778
+ const clonedObject = super.clone();
40779
+ clonedObject.content = { ...this.content };
40780
+ clonedObject.loadingContent = this.loadingContent ? { ...this.loadingContent } : undefined;
40781
+ clonedObject.isLoading = this.isLoading;
40782
+ clonedObject.state = structuredClone(this.state);
40783
+ clonedObject.sandbox = [...this.sandbox];
40784
+ clonedObject.borderRadius = this.borderRadius;
40785
+ clonedObject.boxShadow = this.boxShadow;
40786
+ clonedObject.messageListener = null;
40787
+ clonedObject.isMounted = false;
40788
+ clonedObject._elementRef = null;
40789
+ return clonedObject;
40790
+ }
40791
+ adoptTransientStateFrom(previous) {
40792
+ if (!(previous instanceof KritzelIframeObject)) {
40793
+ return;
40794
+ }
40795
+ this.isInteractive = previous.isInteractive;
40796
+ this.isSelected = previous.isSelected;
40797
+ this.isHovered = previous.isHovered;
40798
+ if (!previous.isMounted || !(previous.elementRef instanceof HTMLElement) || previous.elementRef.tagName !== 'IFRAME') {
40799
+ return;
40800
+ }
40801
+ if (previous.messageListener) {
40802
+ window.removeEventListener('message', previous.messageListener);
40803
+ }
40804
+ this._elementRef = previous.elementRef;
40805
+ this.isMounted = true;
40806
+ this.messageListener = event => this.handleMessage(event);
40807
+ window.addEventListener('message', this.messageListener);
40808
+ this.elementRef.style.pointerEvents = this.isInteractive ? 'auto' : 'none';
40809
+ previous.messageListener = null;
40810
+ previous.isMounted = false;
40811
+ previous._elementRef = null;
40812
+ }
40813
+ createLifecycleContext() {
40814
+ return {
40815
+ object: this,
40816
+ iframe: this.isMounted ? this.elementRef : null,
40817
+ state: structuredClone(this.state),
40818
+ };
40819
+ }
40820
+ normalizeSandbox(tokens) {
40821
+ const requestedTokens = tokens ?? ['allow-scripts'];
40822
+ const normalized = requestedTokens.filter(token => SUPPORTED_SANDBOX_TOKENS.has(token));
40823
+ return [...new Set(normalized.length > 0 ? normalized : ['allow-scripts'])];
40824
+ }
40825
+ createSourceDocument() {
40826
+ const activeContent = this.getActiveContent();
40827
+ const state = JSON.stringify(this.state).replace(/</g, '\\u003c');
40828
+ const css = activeContent.css.replace(/<\/style/gi, '<\\/style');
40829
+ const script = activeContent.script.replace(/<\/script/gi, '<\\/script');
40830
+ const computedStyle = this.isMounted ? getComputedStyle(this.elementRef) : null;
40831
+ const defaultCursor = computedStyle?.getPropertyValue('--kritzel-global-default-cursor').trim() || 'auto';
40832
+ const pointerCursor = computedStyle?.getPropertyValue('--kritzel-global-pointer-cursor').trim() || defaultCursor;
40833
+ return `<!doctype html>
40834
+ <html>
40835
+ <head>
40836
+ <meta charset="utf-8">
40837
+ <style>
40838
+ :root {
40839
+ --kritzel-iframe-default-cursor: ${defaultCursor};
40840
+ --kritzel-iframe-pointer-cursor: ${pointerCursor};
40841
+ }
40842
+ html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; cursor: var(--kritzel-iframe-default-cursor); }
40843
+ button, button *, a, a *, input, textarea, select { cursor: var(--kritzel-iframe-pointer-cursor) !important; }
40844
+ ${css}
40845
+ </style>
40846
+ </head>
40847
+ <body>
40848
+ ${activeContent.html}
40849
+ <script>
40850
+ const kritzel = globalThis.kritzel = {
40851
+ state: ${state},
40852
+ setState(nextState) {
40853
+ this.state = nextState;
40854
+ parent.postMessage({ type: '${IFRAME_STATE_MESSAGE}', state: nextState }, '*');
40855
+ },
40856
+ };
40857
+ globalThis.addEventListener('message', event => {
40858
+ if (event.data?.type === '${IFRAME_PARENT_STATE_MESSAGE}' && event.data.state && typeof event.data.state === 'object') {
40859
+ kritzel.state = event.data.state;
40860
+ globalThis.dispatchEvent(new CustomEvent('kritzelstatechange', { detail: kritzel.state }));
40861
+ }
40862
+ });
40863
+ let bridgedPointerId = null;
40864
+ const interactiveSelector = 'button, input, textarea, select, a[href], [contenteditable="true"], [contenteditable=""]';
40865
+ const bridgePointerEvent = event => parent.postMessage({
40866
+ type: '${IFRAME_POINTER_MESSAGE}',
40867
+ eventType: event.type,
40868
+ pointerId: event.pointerId,
40869
+ pointerType: event.pointerType,
40870
+ clientX: event.clientX,
40871
+ clientY: event.clientY,
40872
+ screenX: event.screenX,
40873
+ screenY: event.screenY,
40874
+ button: event.button,
40875
+ buttons: event.buttons,
40876
+ shiftKey: event.shiftKey,
40877
+ ctrlKey: event.ctrlKey,
40878
+ altKey: event.altKey,
40879
+ metaKey: event.metaKey,
40880
+ }, '*');
40881
+ document.addEventListener('pointerdown', event => {
40882
+ if (event.target instanceof Element && event.target.closest(interactiveSelector)) return;
40883
+ bridgedPointerId = event.pointerId;
40884
+ event.preventDefault();
40885
+ bridgePointerEvent(event);
40886
+ });
40887
+ document.addEventListener('pointermove', event => {
40888
+ if (event.pointerId !== bridgedPointerId) return;
40889
+ event.preventDefault();
40890
+ bridgePointerEvent(event);
40891
+ });
40892
+ const finishPointerBridge = event => {
40893
+ if (event.pointerId !== bridgedPointerId) return;
40894
+ event.preventDefault();
40895
+ bridgePointerEvent(event);
40896
+ bridgedPointerId = null;
40897
+ };
40898
+ document.addEventListener('pointerup', finishPointerBridge);
40899
+ document.addEventListener('pointercancel', finishPointerBridge);
40900
+ document.addEventListener('contextmenu', event => {
40901
+ event.preventDefault();
40902
+ parent.postMessage({
40903
+ type: '${IFRAME_CONTEXT_MENU_MESSAGE}',
40904
+ clientX: event.clientX,
40905
+ clientY: event.clientY,
40906
+ button: event.button,
40907
+ shiftKey: event.shiftKey,
40908
+ ctrlKey: event.ctrlKey,
40909
+ altKey: event.altKey,
40910
+ metaKey: event.metaKey,
40911
+ }, '*');
40912
+ });
40913
+ ${script}
40914
+ <\/script>
40915
+ </body>
40916
+ </html>`;
40917
+ }
40918
+ handleMessage(event) {
40919
+ if (event.source !== this.elementRef?.contentWindow || !event.data || typeof event.data !== 'object') {
40920
+ return;
40921
+ }
40922
+ const message = event.data;
40923
+ if (message.type === IFRAME_POINTER_MESSAGE) {
40924
+ this.dispatchPointerMessage(event.data);
40925
+ return;
40926
+ }
40927
+ if (message.type === IFRAME_CONTEXT_MENU_MESSAGE) {
40928
+ this.dispatchContextMenuMessage(event.data);
40929
+ return;
40930
+ }
40931
+ if (message.type !== IFRAME_STATE_MESSAGE || !message.state || typeof message.state !== 'object') {
40932
+ return;
40933
+ }
40934
+ this.state = structuredClone(message.state);
40935
+ this.persistUpdate();
40936
+ }
40937
+ dispatchPointerMessage(message) {
40938
+ if (!this.isMounted || !this.elementRef || !['pointerdown', 'pointermove', 'pointerup', 'pointercancel'].includes(message.eventType)) {
40939
+ return;
40940
+ }
40941
+ const iframeRect = this.elementRef.getBoundingClientRect();
40942
+ if (message.eventType === 'pointerdown') {
40943
+ const scaleX = this.elementRef.offsetWidth > 0 ? iframeRect.width / this.elementRef.offsetWidth : 1;
40944
+ const scaleY = this.elementRef.offsetHeight > 0 ? iframeRect.height / this.elementRef.offsetHeight : 1;
40945
+ iframePointerBridgeStarts.set(this.elementRef, {
40946
+ pointerId: message.pointerId,
40947
+ clientX: iframeRect.left + message.clientX * scaleX,
40948
+ clientY: iframeRect.top + message.clientY * scaleY,
40949
+ screenX: message.screenX,
40950
+ screenY: message.screenY,
40951
+ });
40952
+ }
40953
+ const bridgeStart = iframePointerBridgeStarts.get(this.elementRef);
40954
+ const hasBridgeStart = bridgeStart?.pointerId === message.pointerId;
40955
+ const clientX = hasBridgeStart ? bridgeStart.clientX + message.screenX - bridgeStart.screenX : iframeRect.left + message.clientX;
40956
+ const clientY = hasBridgeStart ? bridgeStart.clientY + message.screenY - bridgeStart.screenY : iframeRect.top + message.clientY;
40957
+ this.elementRef.dispatchEvent(new PointerEvent(message.eventType, {
40958
+ bubbles: true,
40959
+ composed: true,
40960
+ cancelable: true,
40961
+ pointerId: message.pointerId,
40962
+ pointerType: message.pointerType,
40963
+ clientX,
40964
+ clientY,
40965
+ screenX: message.screenX,
40966
+ screenY: message.screenY,
40967
+ button: message.button,
40968
+ buttons: message.buttons,
40969
+ shiftKey: message.shiftKey,
40970
+ ctrlKey: message.ctrlKey,
40971
+ altKey: message.altKey,
40972
+ metaKey: message.metaKey,
40973
+ }));
40974
+ if (message.eventType === 'pointerup' || message.eventType === 'pointercancel') {
40975
+ iframePointerBridgeStarts.delete(this.elementRef);
40976
+ }
40977
+ }
40978
+ dispatchContextMenuMessage(message) {
40979
+ if (!this.isMounted || !this.elementRef) {
40980
+ return;
40981
+ }
40982
+ const iframeRect = this.elementRef.getBoundingClientRect();
40983
+ // Dispatched as a MouseEvent (not PointerEvent) to mirror how browsers
40984
+ // natively raise 'contextmenu' for both mouse right-click and touch long-press.
40985
+ this.elementRef.dispatchEvent(new MouseEvent('contextmenu', {
40986
+ bubbles: true,
40987
+ composed: true,
40988
+ cancelable: true,
40989
+ clientX: iframeRect.left + message.clientX,
40990
+ clientY: iframeRect.top + message.clientY,
40991
+ button: message.button,
40992
+ shiftKey: message.shiftKey,
40993
+ ctrlKey: message.ctrlKey,
40994
+ altKey: message.altKey,
40995
+ metaKey: message.metaKey,
40996
+ }));
40997
+ }
40998
+ refreshDocument() {
40999
+ if (this.isMounted && this.elementRef) {
41000
+ this.elementRef.srcdoc = this.createSourceDocument();
41001
+ }
41002
+ }
41003
+ persistUpdate() {
41004
+ if (this._core?.store?.objects) {
41005
+ this.update();
41006
+ }
41007
+ }
41008
+ }
41009
+
40551
41010
  /**
40552
41011
  * Handles deserialization/revival of Kritzel objects from plain JavaScript objects.
40553
41012
  * This class uses a pattern similar to JSON.parse reviver to reconstruct class instances
@@ -40610,6 +41069,9 @@ class KritzelReviver {
40610
41069
  case 'KritzelDynamicObject':
40611
41070
  revivedObj = KritzelDynamicObject.create(this._core).deserialize(obj);
40612
41071
  break;
41072
+ case 'KritzelIframeObject':
41073
+ revivedObj = KritzelIframeObject.create(this._core).deserialize(obj);
41074
+ break;
40613
41075
  case 'KritzelSelectionGroup':
40614
41076
  revivedObj = KritzelSelectionGroup.create(this._core).deserialize(obj);
40615
41077
  break;
@@ -45534,20 +45996,22 @@ const cleanupTransactions = (transactionCleanups, i) => {
45534
45996
  // We need to think about the possibility that the user transforms the
45535
45997
  // Y.Doc in the event.
45536
45998
  if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
45537
- events = events
45538
- .filter(event =>
45539
- event.target._item === null || !event.target._item.deleted
45540
- );
45541
- events
45542
- .forEach(event => {
45543
- event.currentTarget = type;
45544
- // path is relative to the current target
45545
- event._path = null;
45546
- });
45547
- // sort events by path length so that top-level events are fired first.
45548
- events
45549
- .sort((event1, event2) => event1.path.length - event2.path.length);
45550
45999
  fs.push(() => {
46000
+ // The same event instance is shared by all parent types. Hence, we must set
46001
+ // currentTarget right before calling the handlers (see #768).
46002
+ events = events
46003
+ .filter(event =>
46004
+ event.target._item === null || !event.target._item.deleted
46005
+ );
46006
+ events
46007
+ .forEach(event => {
46008
+ event.currentTarget = type;
46009
+ // path is relative to the current target
46010
+ event._path = null;
46011
+ });
46012
+ // sort events by path length so that top-level events are fired first.
46013
+ events
46014
+ .sort((event1, event2) => event1.path.length - event2.path.length);
45551
46015
  // We don't need to check for events.length
45552
46016
  // because we know it has at least one element
45553
46017
  callEventHandlerListeners(type._dEH, events, transaction);
@@ -45561,6 +46025,7 @@ const cleanupTransactions = (transactionCleanups, i) => {
45561
46025
  }
45562
46026
  });
45563
46027
  });
46028
+ // note the nested fs calls, must not modify fs at this point
45564
46029
  callAll(fs, []);
45565
46030
  } finally {
45566
46031
  // Replace deleted items with ItemDeleted / GC.
@@ -52971,9 +53436,16 @@ class KritzelStore {
52971
53436
  * Gets the currently selected dynamic object whose focused descendant is an input-like element.
52972
53437
  * @returns The interactive dynamic object with focused input-like content, or null if none matches
52973
53438
  */
53439
+ get activeInteractiveEmbeddedObject() {
53440
+ for (const object of this.selectedObjects) {
53441
+ if (ObjectHelper.isKritzelEmbeddedObject(object) && object.hasFocusedInputElement()) {
53442
+ return object;
53443
+ }
53444
+ }
53445
+ return null;
53446
+ }
52974
53447
  get activeInteractiveDynamicObject() {
52975
- const interactiveDynamicObject = this.selectedObjects.find(object => KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject') && object.hasFocusedInputElement());
52976
- return interactiveDynamicObject ?? null;
53448
+ return this.activeInteractiveEmbeddedObject;
52977
53449
  }
52978
53450
  /**
52979
53451
  * Gets the path currently being drawn (not yet completed).
@@ -55073,7 +55545,7 @@ class KritzelCursorHelper {
55073
55545
  * The icon is retrieved from the KritzelIconRegistry.
55074
55546
  */
55075
55547
  static getCursor(options) {
55076
- const iconName = options.iconName === 'default' ? 'mouse-pointer' : options.iconName;
55548
+ const iconName = options.iconName === 'default' ? 'mousePointer' : options.iconName;
55077
55549
  const iconSvg = KritzelIconRegistry.get(iconName);
55078
55550
  if (!iconSvg) {
55079
55551
  console.warn(`Icon "${iconName}" not found in registry.`);
@@ -55082,7 +55554,7 @@ class KritzelCursorHelper {
55082
55554
  const size = options.size || 24;
55083
55555
  const rotation = options.rotation || 0;
55084
55556
  const color = options.color || 'black';
55085
- // Default cursor (mouse-pointer) has hotspot at (4, 4), others at center
55557
+ // Default cursor (mousePointer) has hotspot at (4, 4), others at center
55086
55558
  const hotspot = options.hotspot || (options.iconName === 'default' ? { x: 4, y: 4 } : { x: size / 2, y: size / 2 });
55087
55559
  // Modify the SVG string to set size and color
55088
55560
  // We replace width and height to match the requested size
@@ -55095,12 +55567,12 @@ class KritzelCursorHelper {
55095
55567
  // We rotate around the center of the SVG canvas
55096
55568
  const center = size / 2;
55097
55569
  // We use a group to apply the rotation
55098
- const svg = `
55099
- <svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
55100
- <g transform="rotate(${rotation} ${center} ${center})">
55101
- ${content}
55102
- </g>
55103
- </svg>
55570
+ const svg = `
55571
+ <svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
55572
+ <g transform="rotate(${rotation} ${center} ${center})">
55573
+ ${content}
55574
+ </g>
55575
+ </svg>
55104
55576
  `;
55105
55577
  // Encode the SVG for use in a data URI
55106
55578
  // We need to be careful with encoding to ensure it works across browsers
@@ -55138,11 +55610,13 @@ class KritzelCursorManager {
55138
55610
  // Reset cursor on old target
55139
55611
  if (this._targetElement) {
55140
55612
  this._targetElement.style.cursor = '';
55613
+ this._targetElement.style.removeProperty('--kritzel-global-default-cursor');
55141
55614
  this._targetElement.style.removeProperty('--kritzel-global-pointer-cursor');
55142
55615
  }
55143
55616
  this._targetElement = element;
55144
55617
  // Set the pointer cursor CSS variable for child components to use
55145
55618
  if (this._targetElement) {
55619
+ this._targetElement.style.setProperty('--kritzel-global-default-cursor', KritzelCursorHelper.getCursor({ iconName: 'default' }));
55146
55620
  this._targetElement.style.setProperty('--kritzel-global-pointer-cursor', KritzelCursorHelper.getPointerCursor());
55147
55621
  }
55148
55622
  }
@@ -55187,8 +55661,10 @@ class KritzelCursorManager {
55187
55661
  if (!this._shadowRoot)
55188
55662
  return;
55189
55663
  const elementsAtPoint = this._shadowRoot.elementsFromPoint(ev.clientX, ev.clientY);
55190
- if (!elementsAtPoint || elementsAtPoint.length === 0)
55664
+ if (!elementsAtPoint || elementsAtPoint.length === 0) {
55665
+ this.resetToDefault();
55191
55666
  return;
55667
+ }
55192
55668
  // Check for resize handle overlays (selection group)
55193
55669
  const resizeHandleOverlay = elementsAtPoint.find(el => el.classList.contains('resize-handle-overlay'));
55194
55670
  if (resizeHandleOverlay) {
@@ -55198,19 +55674,19 @@ class KritzelCursorManager {
55198
55674
  const isTopLeft = resizeHandleOverlay.classList.contains('top-left');
55199
55675
  const isBottomRight = resizeHandleOverlay.classList.contains('bottom-right');
55200
55676
  const rotationOffset = (isTopLeft || isBottomRight) ? -45 : 45;
55201
- this._core.store.state.cursor = { icon: 'move-vertical', rotation: rotationDegrees + rotationOffset };
55677
+ this._core.store.state.cursor = { icon: 'moveVertical', rotation: rotationDegrees + rotationOffset };
55202
55678
  return;
55203
55679
  }
55204
55680
  // Check for rotation handle overlay
55205
55681
  const rotationHandleOverlay = elementsAtPoint.find(el => el.classList.contains('rotation-handle-overlay'));
55206
55682
  if (rotationHandleOverlay) {
55207
- this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
55683
+ this._core.store.state.cursor = { icon: 'hand', iconActive: 'handGrab' };
55208
55684
  return;
55209
55685
  }
55210
55686
  // Check for line handle overlays (selection line)
55211
55687
  const lineHandleOverlay = elementsAtPoint.find(el => el.classList.contains('selection-line-handle-overlay'));
55212
55688
  if (lineHandleOverlay) {
55213
- this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
55689
+ this._core.store.state.cursor = { icon: 'hand', iconActive: 'handGrab' };
55214
55690
  return;
55215
55691
  }
55216
55692
  // Reset cursor if not hovering any handle
@@ -55245,7 +55721,8 @@ class KritzelCursorManager {
55245
55721
  cleanup() {
55246
55722
  if (this._targetElement) {
55247
55723
  this._targetElement.style.cursor = '';
55248
- this._targetElement.style.removeProperty('--kritzel-pointer-cursor');
55724
+ this._targetElement.style.removeProperty('--kritzel-global-default-cursor');
55725
+ this._targetElement.style.removeProperty('--kritzel-global-pointer-cursor');
55249
55726
  }
55250
55727
  this._targetElement = null;
55251
55728
  this._shadowRoot = null;
@@ -57148,7 +57625,7 @@ class KritzelCore {
57148
57625
  this._store.state.translateY = viewportHeight / 2 - (viewport.centerWorldY ?? 0) * scale;
57149
57626
  this._store.state.scale = scale;
57150
57627
  await objectsMap.initialize(this, activeWorkspace.id, this._syncConfig);
57151
- this.seedWorkspaceObjects(activeWorkspace, objectsMap);
57628
+ await this.seedWorkspaceObjects(activeWorkspace, objectsMap);
57152
57629
  // Set local user in awareness after object map is initialized
57153
57630
  if (this._user) {
57154
57631
  objectsMap.setLocalUser(this._user);
@@ -57162,15 +57639,21 @@ class KritzelCore {
57162
57639
  this.engine.emitObjectsChange();
57163
57640
  this.rerender();
57164
57641
  }
57165
- seedWorkspaceObjects(workspace, objectsMap) {
57642
+ async seedWorkspaceObjects(workspace, objectsMap) {
57166
57643
  if (!workspace.objects?.length) {
57167
57644
  return;
57168
57645
  }
57646
+ const pendingObjects = workspace.objects.filter(object => !objectsMap.findById(object.id));
57647
+ // Mirrors engine.addObject()/addObjects(): image asset upload is async and must
57648
+ // happen before the (synchronous) Yjs transaction that inserts the objects.
57649
+ for (const object of pendingObjects) {
57650
+ object._core = this;
57651
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
57652
+ await object.prepareForInsert();
57653
+ }
57654
+ }
57169
57655
  objectsMap.transaction(() => {
57170
- for (const object of workspace.objects) {
57171
- if (objectsMap.findById(object.id)) {
57172
- continue;
57173
- }
57656
+ for (const object of pendingObjects) {
57174
57657
  this.prepareObjectForWorkspace(object, workspace.id, this._store.currentZIndex, this._store.state.scale);
57175
57658
  objectsMap.insert(object);
57176
57659
  }
@@ -57209,16 +57692,30 @@ class KritzelCore {
57209
57692
  * @param scaleFallback - Scale applied to objects that do not define one
57210
57693
  * @returns The objects that were added, updated and removed
57211
57694
  */
57212
- reconcileWorkspaceObjects(objectsMap, workspaceId, desiredObjects, nextZIndex, scaleFallback) {
57695
+ async reconcileWorkspaceObjects(objectsMap, workspaceId, desiredObjects, nextZIndex, scaleFallback) {
57213
57696
  const existingObjects = objectsMap.allObjects().filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox));
57214
57697
  const existingById = new Map(existingObjects.map(object => [object.id, object]));
57215
57698
  const desiredIds = new Set();
57216
57699
  const diff = { added: [], updated: [], removed: [] };
57700
+ // Assign IDs up front so the insert-vs-update lookup below is stable, and so the
57701
+ // async image-prepare pass and the (synchronous) transaction agree on identity.
57702
+ for (const object of desiredObjects) {
57703
+ if (!object.id) {
57704
+ object.id = object.generateId();
57705
+ }
57706
+ }
57707
+ // Mirrors engine.addObject()/addObjects(): image asset upload is async and must
57708
+ // happen before the (synchronous) Yjs transaction that inserts the objects.
57709
+ for (const object of desiredObjects) {
57710
+ const existingObject = existingById.get(object.id);
57711
+ const isNewOrReplaced = !existingObject || existingObject !== object;
57712
+ if (isNewOrReplaced && KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
57713
+ object._core = this;
57714
+ await object.prepareForInsert();
57715
+ }
57716
+ }
57217
57717
  objectsMap.transaction(() => {
57218
57718
  for (const object of desiredObjects) {
57219
- if (!object.id) {
57220
- object.id = object.generateId();
57221
- }
57222
57719
  desiredIds.add(object.id);
57223
57720
  const existingObject = existingById.get(object.id);
57224
57721
  if (!existingObject) {
@@ -57256,7 +57753,7 @@ class KritzelCore {
57256
57753
  * object set stays exactly what the caller declared.
57257
57754
  */
57258
57755
  detachObject(object) {
57259
- if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
57756
+ if (ObjectHelper.isKritzelEmbeddedObject(object)) {
57260
57757
  object.unmount();
57261
57758
  }
57262
57759
  object.isMounted = false;
@@ -57432,13 +57929,13 @@ class KritzelCore {
57432
57929
  activeWorkspace.viewport = { centerWorldX, centerWorldY, scale };
57433
57930
  }
57434
57931
  }
57435
- applyObjectsToActiveWorkspace(workspace, desiredObjects) {
57932
+ async applyObjectsToActiveWorkspace(workspace, desiredObjects) {
57436
57933
  const objectsMap = this._store.objects;
57437
57934
  if (!objectsMap) {
57438
57935
  return null;
57439
57936
  }
57440
57937
  this.clearSelection();
57441
- const diff = this.reconcileWorkspaceObjects(objectsMap, workspace.id, desiredObjects, () => this._store.currentZIndex, this._store.state.scale);
57938
+ const diff = await this.reconcileWorkspaceObjects(objectsMap, workspace.id, desiredObjects, () => this._store.currentZIndex, this._store.state.scale);
57442
57939
  this._anchorManager.rebuildIndex();
57443
57940
  this.rerender();
57444
57941
  return diff;
@@ -57457,7 +57954,7 @@ class KritzelCore {
57457
57954
  try {
57458
57955
  await objectsMap.initialize(this, workspace.id, this._syncConfig, { headless: true, workspaceName: workspace.name });
57459
57956
  await objectsMap.whenNetworkSynced();
57460
- return this.reconcileWorkspaceObjects(objectsMap, workspace.id, desiredObjects, () => this.nextZIndexOf(objectsMap), this._store.state.scale);
57957
+ return await this.reconcileWorkspaceObjects(objectsMap, workspace.id, desiredObjects, () => this.nextZIndexOf(objectsMap), this._store.state.scale);
57461
57958
  }
57462
57959
  finally {
57463
57960
  objectsMap.destroy();
@@ -57543,8 +58040,7 @@ class KritzelCore {
57543
58040
  this.removeObject(child);
57544
58041
  });
57545
58042
  }
57546
- // Unmount dynamic objects before removal
57547
- if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
58043
+ if (ObjectHelper.isKritzelEmbeddedObject(object)) {
57548
58044
  object.unmount();
57549
58045
  }
57550
58046
  // Handle anchor cleanup
@@ -57590,14 +58086,8 @@ class KritzelCore {
57590
58086
  this.removeLocalSelectionGroups();
57591
58087
  this.removeSelectionBox();
57592
58088
  for (const object of selectionGroup.objects ?? []) {
57593
- if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
57594
- const dynamicObject = object;
57595
- if (typeof dynamicObject.setIsInteractive === 'function') {
57596
- dynamicObject.setIsInteractive(true);
57597
- }
57598
- else {
57599
- dynamicObject.isInteractive = true;
57600
- }
58089
+ if (ObjectHelper.isKritzelEmbeddedObject(object)) {
58090
+ object.setIsInteractive(true);
57601
58091
  }
57602
58092
  }
57603
58093
  this._store.objects.insert(selectionGroup);
@@ -57618,14 +58108,8 @@ class KritzelCore {
57618
58108
  teardownSelectionGroup(selectionGroup) {
57619
58109
  selectionGroup.deselectAllChildren?.();
57620
58110
  for (const object of selectionGroup.objects ?? []) {
57621
- if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
57622
- const dynamicObject = object;
57623
- if (typeof dynamicObject.setIsInteractive === 'function') {
57624
- dynamicObject.setIsInteractive(false);
57625
- }
57626
- else {
57627
- dynamicObject.isInteractive = false;
57628
- }
58111
+ if (ObjectHelper.isKritzelEmbeddedObject(object)) {
58112
+ object.setIsInteractive(false);
57629
58113
  }
57630
58114
  }
57631
58115
  }
@@ -59071,13 +59555,7 @@ class KritzelWheelHelper {
59071
59555
  return this.canElementConsumeWheel(scrollContainer, ev.deltaX, ev.deltaY);
59072
59556
  }
59073
59557
  static getScrollableContainerFromEventPath(path, dynamicObject) {
59074
- const potentialRoots = [];
59075
- if (dynamicObject.element instanceof HTMLElement) {
59076
- potentialRoots.push(dynamicObject.element);
59077
- }
59078
- if (dynamicObject.elementRef instanceof HTMLElement) {
59079
- potentialRoots.push(dynamicObject.elementRef);
59080
- }
59558
+ const potentialRoots = dynamicObject.getEmbeddedContentRoots();
59081
59559
  const legacyElementRef = dynamicObject.elmeentRef;
59082
59560
  if (legacyElementRef instanceof HTMLElement) {
59083
59561
  potentialRoots.push(legacyElementRef);
@@ -59254,8 +59732,8 @@ class KritzelSvgExportHelper {
59254
59732
  .join('\n ');
59255
59733
  const xmlDecl = includeXmlDeclaration ? '<?xml version="1.0" encoding="UTF-8"?>\n' : '';
59256
59734
  const defsContent = defs.length > 0 ? `\n <defs>\n ${defs.join('\n ')}\n </defs>` : '';
59257
- return `${xmlDecl}<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}" width="${viewBoxWidth}" height="${viewBoxHeight}">${defsContent}
59258
- ${elements}
59735
+ return `${xmlDecl}<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}" width="${viewBoxWidth}" height="${viewBoxHeight}">${defsContent}
59736
+ ${elements}
59259
59737
  </svg>`;
59260
59738
  }
59261
59739
  /**
@@ -59407,8 +59885,8 @@ class KritzelSvgExportHelper {
59407
59885
  const orient = end === 'start' ? 'auto-start-reverse' : 'auto';
59408
59886
  const refX = 0;
59409
59887
  const refY = size / 2;
59410
- return `<marker id="${markerId}" markerWidth="${size}" markerHeight="${size}" refX="${refX}" refY="${refY}" orient="${orient}" markerUnits="userSpaceOnUse">
59411
- <path d="${path}" fill="${fill}" transform="scale(${size / 10})"/>
59888
+ return `<marker id="${markerId}" markerWidth="${size}" markerHeight="${size}" refX="${refX}" refY="${refY}" orient="${orient}" markerUnits="userSpaceOnUse">
59889
+ <path d="${path}" fill="${fill}" transform="scale(${size / 10})"/>
59412
59890
  </marker>`;
59413
59891
  }
59414
59892
  /**
@@ -59437,6 +59915,9 @@ class KritzelSvgExportHelper {
59437
59915
  if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
59438
59916
  return this.dynamicObjectToSvg(object, rasterSafeForCanvas);
59439
59917
  }
59918
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelIframeObject')) {
59919
+ return this.iframeObjectToSvg(object);
59920
+ }
59440
59921
  if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
59441
59922
  return this.groupToSvg(object, theme, imageDataUrls, rasterSafeForCanvas);
59442
59923
  }
@@ -59455,10 +59936,10 @@ class KritzelSvgExportHelper {
59455
59936
  const opacity = path.opacity !== 1 ? ` opacity="${path.opacity}"` : '';
59456
59937
  const scale = this.getObjectScale(path);
59457
59938
  // Path needs to be wrapped in a g with translation since path.d uses local coordinates
59458
- return `<g transform="${transform}"${opacity}>
59459
- <svg viewBox="${path.viewBox}" width="${path.totalWidth / scale}" height="${path.totalHeight / scale}" overflow="visible">
59460
- <path d="${path.d}" fill="${fill || 'none'}" stroke="${stroke || 'none'}"${path.strokeWidth ? ` stroke-width="${path.strokeWidth}"` : ''}/>
59461
- </svg>
59939
+ return `<g transform="${transform}"${opacity}>
59940
+ <svg viewBox="${path.viewBox}" width="${path.totalWidth / scale}" height="${path.totalHeight / scale}" overflow="visible">
59941
+ <path d="${path.d}" fill="${fill || 'none'}" stroke="${stroke || 'none'}"${path.strokeWidth ? ` stroke-width="${path.strokeWidth}"` : ''}/>
59942
+ </svg>
59462
59943
  </g>`;
59463
59944
  }
59464
59945
  /**
@@ -59474,10 +59955,10 @@ class KritzelSvgExportHelper {
59474
59955
  const scale = this.getObjectScale(line);
59475
59956
  const markerStart = line.hasStartArrow ? ` marker-start="url(#${line.startMarkerId})"` : '';
59476
59957
  const markerEnd = line.hasEndArrow ? ` marker-end="url(#${line.endMarkerId})"` : '';
59477
- return `<g transform="${transform}"${opacity}>
59478
- <svg viewBox="${line.viewBox}" width="${line.totalWidth / scale}" height="${line.totalHeight / scale}" overflow="visible">
59479
- <path d="${line.d}" fill="none" stroke="${stroke}" stroke-width="${line.strokeWidth}" stroke-linecap="round"${markerStart}${markerEnd}/>
59480
- </svg>
59958
+ return `<g transform="${transform}"${opacity}>
59959
+ <svg viewBox="${line.viewBox}" width="${line.totalWidth / scale}" height="${line.totalHeight / scale}" overflow="visible">
59960
+ <path d="${line.d}" fill="none" stroke="${stroke}" stroke-width="${line.strokeWidth}" stroke-linecap="round"${markerStart}${markerEnd}/>
59961
+ </svg>
59481
59962
  </g>`;
59482
59963
  }
59483
59964
  /**
@@ -59501,18 +59982,18 @@ class KritzelSvgExportHelper {
59501
59982
  const textHtml = this.prosemirrorToHtml(shape.content, shape, theme);
59502
59983
  if (textHtml) {
59503
59984
  const fontColor = KritzelColorHelper.resolveThemeColor(shape.fontColor, theme);
59504
- textContent = `
59505
- <foreignObject x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}">
59506
- <div xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; text-align: center; font-family: ${shape.fontFamily}; font-size: ${shape.fontSize}px; color: ${fontColor}; overflow: hidden;">
59507
- ${textHtml}
59508
- </div>
59985
+ textContent = `
59986
+ <foreignObject x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}">
59987
+ <div xmlns="http://www.w3.org/1999/xhtml" style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; text-align: center; font-family: ${shape.fontFamily}; font-size: ${shape.fontSize}px; color: ${fontColor}; overflow: hidden;">
59988
+ ${textHtml}
59989
+ </div>
59509
59990
  </foreignObject>`;
59510
59991
  }
59511
59992
  }
59512
- return `<g transform="${transform}"${opacity}>
59513
- <svg viewBox="${shape.viewBox}" width="${shape.totalWidth / scale}" height="${shape.totalHeight / scale}" overflow="visible" preserveAspectRatio="none">
59514
- <path d="${pathD}" fill="${fill || 'transparent'}" stroke="${stroke}" stroke-width="${shape.strokeWidth}"/>${textContent}
59515
- </svg>
59993
+ return `<g transform="${transform}"${opacity}>
59994
+ <svg viewBox="${shape.viewBox}" width="${shape.totalWidth / scale}" height="${shape.totalHeight / scale}" overflow="visible" preserveAspectRatio="none">
59995
+ <path d="${pathD}" fill="${fill || 'transparent'}" stroke="${stroke}" stroke-width="${shape.strokeWidth}"/>${textContent}
59996
+ </svg>
59516
59997
  </g>`;
59517
59998
  }
59518
59999
  /**
@@ -59543,10 +60024,10 @@ class KritzelSvgExportHelper {
59543
60024
  // adjusted font-size already accounts for it – keeping both would double-scale
59544
60025
  // the content and overflow the foreignObject.
59545
60026
  const svgFontSizePx = (text.fontSize * (4 / 3) * (text.scaleFactor || 1) / scale).toFixed(4);
59546
- return `<g transform="${transform}"${opacity}>
59547
- <foreignObject x="0" y="0" width="${width}" height="${height}" overflow="visible">
59548
- <div xmlns="http://www.w3.org/1999/xhtml" style="font-family: ${text.fontFamily}; font-size: ${svgFontSizePx}px; color: ${fontColor}; background-color: ${bgColor || 'transparent'}; white-space: pre-wrap; word-wrap: break-word; width: 100%; margin: 0; padding: 0; box-sizing: border-box;">${htmlContent.trim()}</div>
59549
- </foreignObject>
60027
+ return `<g transform="${transform}"${opacity}>
60028
+ <foreignObject x="0" y="0" width="${width}" height="${height}" overflow="visible">
60029
+ <div xmlns="http://www.w3.org/1999/xhtml" style="font-family: ${text.fontFamily}; font-size: ${svgFontSizePx}px; color: ${fontColor}; background-color: ${bgColor || 'transparent'}; white-space: pre-wrap; word-wrap: break-word; width: 100%; margin: 0; padding: 0; box-sizing: border-box;">${htmlContent.trim()}</div>
60030
+ </foreignObject>
59550
60031
  </g>`;
59551
60032
  }
59552
60033
  /**
@@ -59580,9 +60061,9 @@ class KritzelSvgExportHelper {
59580
60061
  return `<tspan x="0" y="${y}" xml:space="preserve">${this.escapeHtml(line)}</tspan>`;
59581
60062
  })
59582
60063
  .join('');
59583
- return `<g transform="${transform}"${opacity}>
59584
- ${bgRect}
59585
- <text font-family="${this.escapeHtml(text.fontFamily)}" font-size="${resolvedFontSizePx}" fill="${fontColor}">${tspans}</text>
60064
+ return `<g transform="${transform}"${opacity}>
60065
+ ${bgRect}
60066
+ <text font-family="${this.escapeHtml(text.fontFamily)}" font-size="${resolvedFontSizePx}" fill="${fontColor}">${tspans}</text>
59586
60067
  </g>`;
59587
60068
  }
59588
60069
  /**
@@ -59610,8 +60091,8 @@ class KritzelSvgExportHelper {
59610
60091
  const width = image.totalWidth / scale;
59611
60092
  const height = image.totalHeight / scale;
59612
60093
  const href = imageDataUrls?.get(image.id) || image.resolvedSrc || image.src || '';
59613
- return `<g transform="${transform}"${opacity}>
59614
- <image href="${href}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet"/>
60094
+ return `<g transform="${transform}"${opacity}>
60095
+ <image href="${href}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet"/>
59615
60096
  </g>`;
59616
60097
  }
59617
60098
  /**
@@ -59631,19 +60112,30 @@ class KritzelSvgExportHelper {
59631
60112
  if (rasterSafeForCanvas) {
59632
60113
  // PNG export: render placeholder rect (foreignObject doesn't rasterize to PNG well)
59633
60114
  console.warn('[KritzelDynamicObject SVG Export] Dynamic objects do not serialize well to PNG. Use SVG export or screenshot instead.');
59634
- return `<g transform="${transform}"${opacity}>
59635
- <rect x="0" y="0" width="${width}" height="${height}" fill="#f0f0f0" stroke="#999" stroke-width="1" />
59636
- <text x="${width / 2}" y="${height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999">[Dynamic Object]</text>
60115
+ return `<g transform="${transform}"${opacity}>
60116
+ <rect x="0" y="0" width="${width}" height="${height}" fill="#f0f0f0" stroke="#999" stroke-width="1" />
60117
+ <text x="${width / 2}" y="${height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999">[Dynamic Object]</text>
59637
60118
  </g>`;
59638
60119
  }
59639
60120
  // SVG export: use foreignObject to embed HTML
59640
60121
  const html = obj.element?.outerHTML || '<div style="border:1px dashed #ccc">Empty</div>';
59641
- return `<g transform="${transform}"${opacity}>
59642
- <foreignObject x="0" y="0" width="${width}" height="${height}">
59643
- <div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;overflow:hidden;">
59644
- ${html}
59645
- </div>
59646
- </foreignObject>
60122
+ return `<g transform="${transform}"${opacity}>
60123
+ <foreignObject x="0" y="0" width="${width}" height="${height}">
60124
+ <div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;overflow:hidden;">
60125
+ ${html}
60126
+ </div>
60127
+ </foreignObject>
60128
+ </g>`;
60129
+ }
60130
+ static iframeObjectToSvg(object) {
60131
+ const transform = this.buildTransform(object);
60132
+ const opacity = object.opacity !== 1 ? ` opacity="${object.opacity}"` : '';
60133
+ const scale = this.getObjectScale(object);
60134
+ const width = object.totalWidth / scale;
60135
+ const height = object.totalHeight / scale;
60136
+ return `<g transform="${transform}"${opacity}>
60137
+ <rect x="0" y="0" width="${width}" height="${height}" fill="#f0f0f0" stroke="#999" stroke-width="1" />
60138
+ <text x="${width / 2}" y="${height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#999">[Iframe]</text>
59647
60139
  </g>`;
59648
60140
  }
59649
60141
  /**
@@ -59663,8 +60155,8 @@ class KritzelSvgExportHelper {
59663
60155
  return '';
59664
60156
  }
59665
60157
  const opacity = group.opacity !== 1 ? ` opacity="${group.opacity}"` : '';
59666
- return `<g${opacity}>
59667
- ${children}
60158
+ return `<g${opacity}>
60159
+ ${children}
59668
60160
  </g>`;
59669
60161
  }
59670
60162
  /**
@@ -59849,12 +60341,26 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
59849
60341
  /** Authoritative workspace catalog for this engine instance. When provided, provider-only workspaces are hidden but not deleted. */
59850
60342
  workspaces;
59851
60343
  async onWorkspacesPropChange() {
59852
- if (!this._isYjsInitialized) {
60344
+ this._workspacesRevision++;
60345
+ if (!this._isYjsInitialized || this._syncInitPromise) {
59853
60346
  return;
59854
60347
  }
59855
- await this.reconcileProvidedWorkspaces();
59856
- await this.ensureActiveWorkspaceIsVisible();
59857
- this.workspacesChange.emit(this.getVisibleWorkspaces());
60348
+ const previousReconciliation = this._workspacePropReconciliationPromise;
60349
+ const reconciliationPromise = (async () => {
60350
+ await previousReconciliation;
60351
+ await this.reconcileProvidedWorkspaces();
60352
+ await this.ensureActiveWorkspaceIsVisible();
60353
+ this.workspacesChange.emit(this.getVisibleWorkspaces());
60354
+ })();
60355
+ this._workspacePropReconciliationPromise = reconciliationPromise;
60356
+ try {
60357
+ await reconciliationPromise;
60358
+ }
60359
+ finally {
60360
+ if (this._workspacePropReconciliationPromise === reconciliationPromise) {
60361
+ this._workspacePropReconciliationPromise = null;
60362
+ }
60363
+ }
59858
60364
  }
59859
60365
  /** Optional unique identifier for namespacing storage keys across multiple editor instances. */
59860
60366
  editorId;
@@ -59908,6 +60414,12 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
59908
60414
  onUserChange(newValue) {
59909
60415
  this.core.setUser(newValue);
59910
60416
  }
60417
+ /** Tool definitions to register with this engine instance. */
60418
+ tools = [];
60419
+ onToolsChange() {
60420
+ this._toolsRevision++;
60421
+ void this.registerConfiguredTools();
60422
+ }
59911
60423
  /** Context menu items shown when right-clicking the canvas background. */
59912
60424
  globalContextMenuItems;
59913
60425
  onGlobalContextMenuItemsChange(newValue) {
@@ -60098,7 +60610,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
60098
60610
  }
60099
60611
  const hoveredObject = this.core.getObjectFromPointerEvent(ev);
60100
60612
  if (hoveredObject &&
60101
- ObjectHelper.isClass(hoveredObject, 'KritzelDynamicObject') &&
60613
+ ObjectHelper.isKritzelEmbeddedObject(hoveredObject) &&
60102
60614
  KritzelWheelHelper.shouldKeepWheelInDynamicObject(ev, hoveredObject)) {
60103
60615
  return;
60104
60616
  }
@@ -60200,7 +60712,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
60200
60712
  return false;
60201
60713
  }
60202
60714
  const object = this.core.store.objects.findById(objectElement.id);
60203
- if (!object || !KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
60715
+ if (!object || !ObjectHelper.isKritzelEmbeddedObject(object)) {
60204
60716
  return false;
60205
60717
  }
60206
60718
  const isSelected = !!this.core.store.selectionGroup?.objects?.some(selectedObject => selectedObject.id === object.id);
@@ -60210,13 +60722,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
60210
60722
  if (object.isInteractive !== true) {
60211
60723
  return false;
60212
60724
  }
60213
- const potentialRoots = [];
60214
- if (object.element instanceof H) {
60215
- potentialRoots.push(object.element);
60216
- }
60217
- if (object.elementRef instanceof H) {
60218
- potentialRoots.push(object.elementRef);
60219
- }
60725
+ const potentialRoots = object.getEmbeddedContentRoots();
60220
60726
  if (potentialRoots.length === 0) {
60221
60727
  return false;
60222
60728
  }
@@ -60390,7 +60896,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
60390
60896
  * Switches the active drawing tool by its registered name.
60391
60897
  * @param toolName - The name the tool was registered with (e.g., 'brush', 'eraser').
60392
60898
  */
60393
- async changeActiveTool(toolName) {
60899
+ async setActiveTool(toolName) {
60394
60900
  const tool = this.core.toolRegistry.getTool(toolName);
60395
60901
  if (!tool) {
60396
60902
  console.warn(`[KritzelEngine] No tool registered with name: ${toolName}`);
@@ -61696,9 +62202,13 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
61696
62202
  _stateChangeListenersRegistered = false;
61697
62203
  _workspaceInitializationPromise = null;
61698
62204
  _workspaceInitializationTargetKey = null;
62205
+ _workspacePropReconciliationPromise = null;
61699
62206
  _syncInitPromise = null;
62207
+ _toolsInitPromise = null;
62208
+ _toolsRevision = 0;
61700
62209
  _syncConfigRevision = 0;
61701
62210
  _assetStorageConfigRevision = 0;
62211
+ _workspacesRevision = 0;
61702
62212
  _hasLoggedUnlicensedWelcomeBanner = false;
61703
62213
  _previousVisibleDynamicObjects = new Set();
61704
62214
  _revealedImageKeys = new Set();
@@ -61711,6 +62221,37 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
61711
62221
  undoStackSize: 0,
61712
62222
  redoStackSize: 0,
61713
62223
  };
62224
+ /** Returns a tool registered in this engine instance. */
62225
+ async getTool(toolName) {
62226
+ await this.registerConfiguredTools();
62227
+ return this.core.toolRegistry.getTool(toolName);
62228
+ }
62229
+ async registerConfiguredTools() {
62230
+ if (this._toolsInitPromise) {
62231
+ return this._toolsInitPromise;
62232
+ }
62233
+ this._toolsInitPromise = (async () => {
62234
+ do {
62235
+ const revision = this._toolsRevision;
62236
+ for (const definition of this.tools) {
62237
+ let toolClass = definition.tool;
62238
+ if (typeof toolClass !== 'function') {
62239
+ toolClass = toolClass.constructor;
62240
+ }
62241
+ await this.registerTool(definition.name, toolClass, definition.config);
62242
+ }
62243
+ if (revision === this._toolsRevision) {
62244
+ break;
62245
+ }
62246
+ } while (true);
62247
+ })();
62248
+ try {
62249
+ await this._toolsInitPromise;
62250
+ }
62251
+ finally {
62252
+ this._toolsInitPromise = null;
62253
+ }
62254
+ }
61714
62255
  setLoadingState(isLoading) {
61715
62256
  if (this.core.store.state.isLoading === isLoading) {
61716
62257
  return;
@@ -61842,6 +62383,8 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
61842
62383
  this.core.licenseManager.destroy();
61843
62384
  }
61844
62385
  componentWillLoad() {
62386
+ this._toolsRevision++;
62387
+ void this.registerConfiguredTools();
61845
62388
  this.core.setEditorId(this.editorId);
61846
62389
  if (this.themes && this.themes.length > 0) {
61847
62390
  this.core.themeManager.registerThemes(this.themes);
@@ -61881,7 +62424,9 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
61881
62424
  const editorElement = this.host.closest('kritzel-editor');
61882
62425
  this.core.themeManager.setTargetElement(editorElement || this.host);
61883
62426
  // Initialize sync config and Yjs
62427
+ await this.registerConfiguredTools();
61884
62428
  await this.initializeSyncAndWorkspace();
62429
+ await this.waitForWorkspaceAndSceneReady();
61885
62430
  if (this.core.store.state.isReady === false) {
61886
62431
  this.core.store.state.isReady = true;
61887
62432
  this.logUnlicensedWelcomeBanner();
@@ -61903,6 +62448,20 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
61903
62448
  this._syncInitPromise = null;
61904
62449
  }
61905
62450
  }
62451
+ async waitForSceneRender() {
62452
+ await new Promise(resolve => {
62453
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
62454
+ });
62455
+ }
62456
+ async waitForWorkspaceAndSceneReady() {
62457
+ let observedRevision;
62458
+ do {
62459
+ observedRevision = this._workspacesRevision;
62460
+ await this._workspacePropReconciliationPromise;
62461
+ await this.waitForSceneRender();
62462
+ } while (observedRevision !== this._workspacesRevision ||
62463
+ this._workspacePropReconciliationPromise);
62464
+ }
61906
62465
  /**
61907
62466
  * Initializes the asset storage layer with the latest config. Mirrors
61908
62467
  * the in-flight replay logic of {@link doInitializeSyncAndWorkspace} for
@@ -62285,7 +62844,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62285
62844
  if (!KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup')) {
62286
62845
  return 'auto';
62287
62846
  }
62288
- if (object.objects.length === 1 && KritzelClassHelper.isInstanceOf(object.objects[0], 'KritzelDynamicObject')) {
62847
+ if (object.objects.length === 1 && ObjectHelper.isKritzelEmbeddedObject(object.objects[0])) {
62289
62848
  return 'none';
62290
62849
  }
62291
62850
  return 'auto';
@@ -62293,7 +62852,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62293
62852
  // Track visible dynamic objects and unmount culled ones
62294
62853
  const currentVisibleDynamicObjects = new Set();
62295
62854
  visibleObjects.forEach(object => {
62296
- if (KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
62855
+ if (ObjectHelper.isKritzelEmbeddedObject(object)) {
62297
62856
  currentVisibleDynamicObjects.add(object.id);
62298
62857
  }
62299
62858
  });
@@ -62301,7 +62860,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62301
62860
  this._previousVisibleDynamicObjects.forEach(id => {
62302
62861
  if (!currentVisibleDynamicObjects.has(id)) {
62303
62862
  const object = this.core.store.objects.findById(id);
62304
- if (object && KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject')) {
62863
+ if (object && ObjectHelper.isKritzelEmbeddedObject(object)) {
62305
62864
  object.unmount();
62306
62865
  }
62307
62866
  }
@@ -62394,7 +62953,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62394
62953
  display: 'flex',
62395
62954
  alignItems: 'center',
62396
62955
  justifyContent: 'center',
62397
- } }, h("kritzel-icon", { name: object.loadState === 'error' ? 'image-off' : 'image', size: Math.max(16, Math.min(object.totalWidth, object.totalHeight) * 0.3), style: {
62956
+ } }, h("kritzel-icon", { name: object.loadState === 'error' ? 'imageOff' : 'image', size: Math.max(16, Math.min(object.totalWidth, object.totalHeight) * 0.3), style: {
62398
62957
  color: KritzelColorHelper.resolveThemeColor({ light: '#9ca3af', dark: '#6b7280' }, currentTheme),
62399
62958
  } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelDynamicObject') && (h("div", { ref: el => el && object.mount(el), style: {
62400
62959
  position: 'absolute',
@@ -62413,7 +62972,37 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62413
62972
  padding: object.padding + 'px',
62414
62973
  overflow: 'visible',
62415
62974
  display: 'block',
62416
- } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => el && object.mount(el), style: {
62975
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelIframeObject') && (h("div", { style: {
62976
+ position: 'absolute',
62977
+ left: '0',
62978
+ top: '0',
62979
+ width: object.totalWidth + 'px',
62980
+ height: object.totalHeight + 'px',
62981
+ transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
62982
+ transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
62983
+ opacity: effectiveOpacityString,
62984
+ backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
62985
+ borderColor: KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme),
62986
+ borderWidth: object.borderWidth + 'px',
62987
+ borderStyle: 'solid',
62988
+ borderRadius: object.borderRadius !== undefined ? (typeof object.borderRadius === 'number' ? `${object.borderRadius}px` : object.borderRadius) : undefined,
62989
+ boxShadow: object.boxShadow,
62990
+ overflow: 'hidden',
62991
+ display: 'block',
62992
+ pointerEvents: object.markedForRemoval ? 'none' : 'auto',
62993
+ } }, h("iframe", { ref: element => element && object.mount(element), title: object.title, sandbox: object.sandboxAttribute, style: {
62994
+ display: 'block',
62995
+ width: '100%',
62996
+ height: '100%',
62997
+ border: '0',
62998
+ borderRadius: object.borderRadius !== undefined ? (typeof object.borderRadius === 'number' ? `${object.borderRadius}px` : object.borderRadius) : undefined,
62999
+ pointerEvents: object.isInteractive ? 'auto' : 'none',
63000
+ } }), h("div", { style: {
63001
+ position: 'absolute',
63002
+ inset: '0',
63003
+ borderRadius: object.borderRadius !== undefined ? (typeof object.borderRadius === 'number' ? `${object.borderRadius}px` : object.borderRadius) : undefined,
63004
+ pointerEvents: object.isInteractive ? 'none' : 'auto',
63005
+ } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => el && object.mount(el), style: {
62417
63006
  position: 'absolute',
62418
63007
  left: '0',
62419
63008
  top: '0',
@@ -62771,6 +63360,9 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62771
63360
  "user": [{
62772
63361
  "onUserChange": 0
62773
63362
  }],
63363
+ "tools": [{
63364
+ "onToolsChange": 0
63365
+ }],
62774
63366
  "globalContextMenuItems": [{
62775
63367
  "onGlobalContextMenuItemsChange": 0
62776
63368
  }],
@@ -62831,6 +63423,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62831
63423
  "syncConfig": [16],
62832
63424
  "assetStorageConfig": [16],
62833
63425
  "user": [16],
63426
+ "tools": [16],
62834
63427
  "globalContextMenuItems": [16],
62835
63428
  "objectContextMenuItems": [16],
62836
63429
  "scaleMax": [1026, "scale-max"],
@@ -62855,7 +63448,7 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62855
63448
  "beginSceneBootstrap": [64],
62856
63449
  "endSceneBootstrap": [64],
62857
63450
  "registerTool": [64],
62858
- "changeActiveTool": [64],
63451
+ "setActiveTool": [64],
62859
63452
  "disable": [64],
62860
63453
  "enable": [64],
62861
63454
  "delete": [64],
@@ -62931,7 +63524,8 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62931
63524
  "getAvailableLocales": [64],
62932
63525
  "getAvailableLocaleOptions": [64],
62933
63526
  "t": [64],
62934
- "getResolvedTerms": [64]
63527
+ "getResolvedTerms": [64],
63528
+ "getTool": [64]
62935
63529
  }, [[1, "wheel", "handleWheel"], [0, "pointerdown", "handlePointerDown"], [0, "pointermove", "handlePointerMove"], [0, "pointerup", "handlePointerUp"], [0, "pointercancel", "handlePointerCancel"], [1, "pointerleave", "handlePointerLeave"], [1, "longpress", "handleLongPress"], [0, "contextmenu", "handleContextMenu"], [9, "resize", "handleResize"], [8, "keydown", "handleKeyDown"], [8, "keyup", "handleKeyUp"], [8, "copy", "handleCopy"], [8, "cut", "handleCut"], [8, "paste", "handlePaste"], [4, "dblclick", "preventDoubleTapZoomOnTouchDevices"]], {
62936
63530
  "workspaces": [{
62937
63531
  "onWorkspacesPropChange": 0
@@ -62948,6 +63542,9 @@ const KritzelEngine = /*@__PURE__*/ proxyCustomElement(class KritzelEngine exten
62948
63542
  "user": [{
62949
63543
  "onUserChange": 0
62950
63544
  }],
63545
+ "tools": [{
63546
+ "onToolsChange": 0
63547
+ }],
62951
63548
  "globalContextMenuItems": [{
62952
63549
  "onGlobalContextMenuItemsChange": 0
62953
63550
  }],