kritzel-stencil 0.0.144 → 0.0.146

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 (290) hide show
  1. package/dist/cjs/{index-C9GjuVAx.js → default-text-tool.config-C0W0noF9.js} +15960 -1098
  2. package/dist/cjs/default-text-tool.config-C0W0noF9.js.map +1 -0
  3. package/dist/cjs/{index-DcTwXs_q.js → index-Cj__YTlG.js} +9 -11
  4. package/dist/cjs/index-Cj__YTlG.js.map +1 -0
  5. package/dist/cjs/index.cjs.js +1369 -12
  6. package/dist/cjs/index.cjs.js.map +1 -1
  7. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  8. package/dist/cjs/kritzel-color_22.cjs.entry.js +777 -754
  9. package/dist/cjs/loader.cjs.js +2 -2
  10. package/dist/cjs/stencil.cjs.js +3 -3
  11. package/dist/cjs/stencil.cjs.js.map +1 -1
  12. package/dist/collection/classes/core/core.class.js +263 -211
  13. package/dist/collection/classes/core/core.class.js.map +1 -1
  14. package/dist/collection/classes/core/store.class.js +21 -3
  15. package/dist/collection/classes/core/store.class.js.map +1 -1
  16. package/dist/collection/classes/core/viewport.class.js +4 -1
  17. package/dist/collection/classes/core/viewport.class.js.map +1 -1
  18. package/dist/collection/classes/core/workspace.class.js +2 -3
  19. package/dist/collection/classes/core/workspace.class.js.map +1 -1
  20. package/dist/collection/classes/handlers/context-menu.handler.js +11 -14
  21. package/dist/collection/classes/handlers/context-menu.handler.js.map +1 -1
  22. package/dist/collection/classes/handlers/key.handler.js +13 -13
  23. package/dist/collection/classes/handlers/key.handler.js.map +1 -1
  24. package/dist/collection/classes/handlers/move.handler.js +12 -9
  25. package/dist/collection/classes/handlers/move.handler.js.map +1 -1
  26. package/dist/collection/classes/handlers/resize.handler.js +20 -17
  27. package/dist/collection/classes/handlers/resize.handler.js.map +1 -1
  28. package/dist/collection/classes/handlers/rotation.handler.js +26 -23
  29. package/dist/collection/classes/handlers/rotation.handler.js.map +1 -1
  30. package/dist/collection/classes/handlers/selection.handler.js +32 -30
  31. package/dist/collection/classes/handlers/selection.handler.js.map +1 -1
  32. package/dist/collection/classes/objects/base-object.class.js +6 -15
  33. package/dist/collection/classes/objects/base-object.class.js.map +1 -1
  34. package/dist/collection/classes/objects/custom-element.class.js +2 -0
  35. package/dist/collection/classes/objects/custom-element.class.js.map +1 -1
  36. package/dist/collection/classes/objects/image.class.js +2 -0
  37. package/dist/collection/classes/objects/image.class.js.map +1 -1
  38. package/dist/collection/classes/objects/path.class.js +4 -0
  39. package/dist/collection/classes/objects/path.class.js.map +1 -1
  40. package/dist/collection/classes/objects/selection-box.class.js +3 -4
  41. package/dist/collection/classes/objects/selection-box.class.js.map +1 -1
  42. package/dist/collection/classes/objects/selection-group.class.js +109 -49
  43. package/dist/collection/classes/objects/selection-group.class.js.map +1 -1
  44. package/dist/collection/classes/objects/text.class.js +37 -43
  45. package/dist/collection/classes/objects/text.class.js.map +1 -1
  46. package/dist/collection/classes/providers/broadcast-sync-provider.class.js +93 -0
  47. package/dist/collection/classes/providers/broadcast-sync-provider.class.js.map +1 -0
  48. package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js +232 -0
  49. package/dist/collection/classes/providers/hocuspocus-sync-provider.class.js.map +1 -0
  50. package/dist/collection/classes/providers/indexeddb-sync-provider.class.js +35 -0
  51. package/dist/collection/classes/providers/indexeddb-sync-provider.class.js.map +1 -0
  52. package/dist/collection/classes/providers/websocket-sync-provider.class.js +89 -0
  53. package/dist/collection/classes/providers/websocket-sync-provider.class.js.map +1 -0
  54. package/dist/collection/classes/structures/app-state-map.structure.js +189 -0
  55. package/dist/collection/classes/structures/app-state-map.structure.js.map +1 -0
  56. package/dist/collection/classes/structures/object-map.structure.js +260 -1
  57. package/dist/collection/classes/structures/object-map.structure.js.map +1 -1
  58. package/dist/collection/classes/tools/brush-tool.class.js +48 -37
  59. package/dist/collection/classes/tools/brush-tool.class.js.map +1 -1
  60. package/dist/collection/classes/tools/eraser-tool.class.js +10 -12
  61. package/dist/collection/classes/tools/eraser-tool.class.js.map +1 -1
  62. package/dist/collection/classes/tools/image-tool.class.js +2 -10
  63. package/dist/collection/classes/tools/image-tool.class.js.map +1 -1
  64. package/dist/collection/classes/tools/selection-tool.class.js +11 -8
  65. package/dist/collection/classes/tools/selection-tool.class.js.map +1 -1
  66. package/dist/collection/classes/tools/text-tool.class.js +13 -26
  67. package/dist/collection/classes/tools/text-tool.class.js.map +1 -1
  68. package/dist/collection/collection-manifest.json +1 -1
  69. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +1 -1
  70. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +36 -1
  71. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
  72. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +61 -35
  73. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -1
  74. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
  75. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +1 -1
  76. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
  77. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js +1 -1
  78. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
  79. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
  80. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +2 -2
  81. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
  82. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +1 -1
  83. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
  84. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +4 -4
  85. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +1 -1
  86. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js +2 -2
  87. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js +2 -2
  88. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +3 -3
  89. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  90. package/dist/collection/configs/{default-engine-state.js → default-engine-config.js} +2 -8
  91. package/dist/collection/configs/default-engine-config.js.map +1 -0
  92. package/dist/collection/configs/default-sync.config.js +12 -0
  93. package/dist/collection/configs/default-sync.config.js.map +1 -0
  94. package/dist/collection/constants/core.constants.js +2 -0
  95. package/dist/collection/constants/core.constants.js.map +1 -0
  96. package/dist/collection/index.js +8 -1
  97. package/dist/collection/index.js.map +1 -1
  98. package/dist/collection/interfaces/debug-info.interface.js.map +1 -1
  99. package/dist/collection/interfaces/engine-state.interface.js.map +1 -1
  100. package/dist/collection/interfaces/object.interface.js.map +1 -1
  101. package/dist/collection/interfaces/selection-state.interface.js.map +1 -1
  102. package/dist/collection/interfaces/sync-config.interface.js +2 -0
  103. package/dist/collection/interfaces/sync-config.interface.js.map +1 -0
  104. package/dist/collection/interfaces/sync-provider.interface.js +2 -0
  105. package/dist/collection/interfaces/sync-provider.interface.js.map +1 -0
  106. package/dist/components/index.js +1361 -4
  107. package/dist/components/index.js.map +1 -1
  108. package/dist/components/kritzel-brush-style.js +4 -4
  109. package/dist/components/kritzel-color-palette.js +1 -1
  110. package/dist/components/kritzel-color.js +1 -1
  111. package/dist/components/kritzel-context-menu.js +1 -1
  112. package/dist/components/kritzel-control-brush-config.js +1 -1
  113. package/dist/components/kritzel-control-text-config.js +1 -1
  114. package/dist/components/kritzel-controls.js +1 -1
  115. package/dist/components/kritzel-cursor-trail.js +1 -1
  116. package/dist/components/kritzel-dropdown.js +1 -1
  117. package/dist/components/kritzel-editor.js +39 -27
  118. package/dist/components/kritzel-editor.js.map +1 -1
  119. package/dist/components/kritzel-engine.js +1 -1
  120. package/dist/components/kritzel-font-family.js +1 -1
  121. package/dist/components/kritzel-font-size.js +1 -1
  122. package/dist/components/kritzel-font.js +1 -1
  123. package/dist/components/kritzel-icon.js +1 -1
  124. package/dist/components/kritzel-menu-item.js +1 -1
  125. package/dist/components/kritzel-menu.js +1 -1
  126. package/dist/components/kritzel-portal.js +1 -1
  127. package/dist/components/kritzel-split-button.js +1 -1
  128. package/dist/components/kritzel-stroke-size.js +1 -1
  129. package/dist/components/kritzel-tooltip.js +1 -1
  130. package/dist/components/kritzel-utility-panel.js +1 -1
  131. package/dist/components/kritzel-workspace-manager.js +1 -1
  132. package/dist/components/{p-C_hSH2nN.js → p-8iFF5GHL.js} +6 -6
  133. package/dist/components/{p-C_hSH2nN.js.map → p-8iFF5GHL.js.map} +1 -1
  134. package/dist/components/{p-BycHaC-9.js → p-BCrMfH5n.js} +6 -6
  135. package/dist/components/{p-BycHaC-9.js.map → p-BCrMfH5n.js.map} +1 -1
  136. package/dist/components/{p-D_RcVGj0.js → p-BHDOht0m.js} +6 -6
  137. package/dist/components/{p-D_RcVGj0.js.map → p-BHDOht0m.js.map} +1 -1
  138. package/dist/components/{p-DqsgZIHC.js → p-BHT7_POQ.js} +6 -6
  139. package/dist/components/{p-DqsgZIHC.js.map → p-BHT7_POQ.js.map} +1 -1
  140. package/dist/components/{p-DzyZA2GT.js → p-BQ5cdSqE.js} +11 -11
  141. package/dist/components/{p-DzyZA2GT.js.map → p-BQ5cdSqE.js.map} +1 -1
  142. package/dist/components/{p-Co5lU_7h.js → p-BaHZYvfq.js} +13 -13
  143. package/dist/components/{p-Co5lU_7h.js.map → p-BaHZYvfq.js.map} +1 -1
  144. package/dist/components/{p-BJbN3vca.js → p-BctNMdxr.js} +8 -8
  145. package/dist/components/{p-BJbN3vca.js.map → p-BctNMdxr.js.map} +1 -1
  146. package/dist/components/{p-D27d2rKT.js → p-Bhtn9qay.js} +5 -5
  147. package/dist/components/{p-D27d2rKT.js.map → p-Bhtn9qay.js.map} +1 -1
  148. package/dist/components/{p-CEn1WeG3.js → p-Bit0z7Yg.js} +9 -9
  149. package/dist/components/{p-CEn1WeG3.js.map → p-Bit0z7Yg.js.map} +1 -1
  150. package/dist/components/{p-CGb-8cK4.js → p-BlI4vzRZ.js} +5 -5
  151. package/dist/components/{p-CGb-8cK4.js.map → p-BlI4vzRZ.js.map} +1 -1
  152. package/dist/components/{p-fiFoOjv0.js → p-C3_LIgzd.js} +10 -10
  153. package/dist/components/{p-fiFoOjv0.js.map → p-C3_LIgzd.js.map} +1 -1
  154. package/dist/components/{p-DPxzgBs0.js → p-CIXPLjCu.js} +4 -4
  155. package/dist/components/{p-DPxzgBs0.js.map → p-CIXPLjCu.js.map} +1 -1
  156. package/dist/components/{p-dcR2uxM3.js → p-CURq0twf.js} +6 -6
  157. package/dist/components/{p-dcR2uxM3.js.map → p-CURq0twf.js.map} +1 -1
  158. package/dist/components/p-CwHz5s2a.js +18262 -0
  159. package/dist/components/p-CwHz5s2a.js.map +1 -0
  160. package/dist/components/{p-C9hrbrUN.js → p-CwkUrTy1.js} +5 -7
  161. package/dist/{cjs/index-DcTwXs_q.js.map → components/p-CwkUrTy1.js.map} +1 -1
  162. package/dist/components/{p-ByAzDzS5.js → p-D13ydJjo.js} +5 -5
  163. package/dist/components/{p-ByAzDzS5.js.map → p-D13ydJjo.js.map} +1 -1
  164. package/dist/components/{p-1bVCRi-d.js → p-DPN0PZvw.js} +20 -20
  165. package/dist/components/{p-1bVCRi-d.js.map → p-DPN0PZvw.js.map} +1 -1
  166. package/dist/components/{p-BFNwskCY.js → p-Dbp5YJIa.js} +5 -5
  167. package/dist/components/{p-BFNwskCY.js.map → p-Dbp5YJIa.js.map} +1 -1
  168. package/dist/components/{p-BEKicPnH.js → p-Dcf7tVJW.js} +5 -5
  169. package/dist/components/{p-BEKicPnH.js.map → p-Dcf7tVJW.js.map} +1 -1
  170. package/dist/components/{p-CieOx1XL.js → p-EBtkRix7.js} +8 -8
  171. package/dist/components/{p-CieOx1XL.js.map → p-EBtkRix7.js.map} +1 -1
  172. package/dist/components/{p-UsToUu6G.js → p-G2HGJcNm.js} +118 -196
  173. package/dist/components/p-G2HGJcNm.js.map +1 -0
  174. package/dist/components/{p-gCHmJzc2.js → p-NXPGXBZ2.js} +6 -6
  175. package/dist/components/{p-gCHmJzc2.js.map → p-NXPGXBZ2.js.map} +1 -1
  176. package/dist/components/{p-YqK8ch2R.js → p-n789Y3S-.js} +4 -5
  177. package/dist/components/p-n789Y3S-.js.map +1 -0
  178. package/dist/esm/{index-YVlgItFD.js → default-text-tool.config-nXXHSTK9.js} +15920 -1090
  179. package/dist/esm/default-text-tool.config-nXXHSTK9.js.map +1 -0
  180. package/dist/esm/{index-Cw77zP6g.js → index-SGde3HXB.js} +9 -11
  181. package/dist/esm/index-SGde3HXB.js.map +1 -0
  182. package/dist/esm/index.js +1358 -1
  183. package/dist/esm/index.js.map +1 -1
  184. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  185. package/dist/esm/kritzel-color_22.entry.js +732 -709
  186. package/dist/esm/loader.js +3 -3
  187. package/dist/esm/stencil.js +4 -4
  188. package/dist/esm/stencil.js.map +1 -1
  189. package/dist/stencil/index.esm.js +1 -1
  190. package/dist/stencil/index.esm.js.map +1 -1
  191. package/dist/stencil/{p-Cw77zP6g.js → p-SGde3HXB.js} +2 -2
  192. package/dist/stencil/p-SGde3HXB.js.map +1 -0
  193. package/dist/stencil/{p-8b831c94.entry.js → p-d702c5af.entry.js} +2 -2
  194. package/dist/stencil/p-f8a8a8d7.entry.js +2 -0
  195. package/dist/stencil/p-f8a8a8d7.entry.js.map +1 -0
  196. package/dist/stencil/p-nXXHSTK9.js +2 -0
  197. package/dist/stencil/p-nXXHSTK9.js.map +1 -0
  198. package/dist/stencil/stencil.esm.js +1 -1
  199. package/dist/stencil/stencil.esm.js.map +1 -1
  200. package/dist/types/classes/core/core.class.d.ts +34 -21
  201. package/dist/types/classes/core/store.class.d.ts +8 -0
  202. package/dist/types/classes/objects/base-object.class.d.ts +1 -5
  203. package/dist/types/classes/objects/path.class.d.ts +1 -0
  204. package/dist/types/classes/objects/selection-box.class.d.ts +2 -3
  205. package/dist/types/classes/objects/selection-group.class.d.ts +24 -5
  206. package/dist/types/classes/objects/text.class.d.ts +1 -3
  207. package/dist/types/classes/providers/broadcast-sync-provider.class.d.ts +18 -0
  208. package/dist/types/classes/providers/hocuspocus-sync-provider.class.d.ts +120 -0
  209. package/dist/types/classes/providers/indexeddb-sync-provider.class.d.ts +22 -0
  210. package/dist/types/classes/providers/websocket-sync-provider.class.d.ts +52 -0
  211. package/dist/types/classes/structures/app-state-map.structure.d.ts +30 -0
  212. package/dist/types/classes/structures/object-map.structure.d.ts +39 -1
  213. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +3 -0
  214. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -0
  215. package/dist/types/components.d.ts +6 -0
  216. package/dist/types/configs/{default-engine-state.d.ts → default-engine-config.d.ts} +1 -1
  217. package/dist/types/configs/default-sync.config.d.ts +5 -0
  218. package/dist/types/constants/core.constants.d.ts +0 -0
  219. package/dist/types/index.d.ts +8 -1
  220. package/dist/types/interfaces/debug-info.interface.d.ts +0 -1
  221. package/dist/types/interfaces/engine-state.interface.d.ts +1 -10
  222. package/dist/types/interfaces/object.interface.d.ts +1 -1
  223. package/dist/types/interfaces/selection-state.interface.d.ts +0 -4
  224. package/dist/types/interfaces/sync-config.interface.d.ts +22 -0
  225. package/dist/types/interfaces/sync-provider.interface.d.ts +29 -0
  226. package/dist/types/stencil-public-runtime.d.ts +1 -1
  227. package/package.json +16 -11
  228. package/dist/cjs/index-C9GjuVAx.js.map +0 -1
  229. package/dist/collection/classes/commands/add-object.command.js +0 -18
  230. package/dist/collection/classes/commands/add-object.command.js.map +0 -1
  231. package/dist/collection/classes/commands/add-selection-group.command.js +0 -24
  232. package/dist/collection/classes/commands/add-selection-group.command.js.map +0 -1
  233. package/dist/collection/classes/commands/base.command.js +0 -19
  234. package/dist/collection/classes/commands/base.command.js.map +0 -1
  235. package/dist/collection/classes/commands/batch.command.js +0 -15
  236. package/dist/collection/classes/commands/batch.command.js.map +0 -1
  237. package/dist/collection/classes/commands/move-selection-group.command.js +0 -44
  238. package/dist/collection/classes/commands/move-selection-group.command.js.map +0 -1
  239. package/dist/collection/classes/commands/remove-object.command.js +0 -18
  240. package/dist/collection/classes/commands/remove-object.command.js.map +0 -1
  241. package/dist/collection/classes/commands/remove-selection-group.command.js +0 -19
  242. package/dist/collection/classes/commands/remove-selection-group.command.js.map +0 -1
  243. package/dist/collection/classes/commands/resize-selection-group.command.js +0 -29
  244. package/dist/collection/classes/commands/resize-selection-group.command.js.map +0 -1
  245. package/dist/collection/classes/commands/rotate-selection-group.command.js +0 -29
  246. package/dist/collection/classes/commands/rotate-selection-group.command.js.map +0 -1
  247. package/dist/collection/classes/commands/update-object.command.js +0 -38
  248. package/dist/collection/classes/commands/update-object.command.js.map +0 -1
  249. package/dist/collection/classes/commands/update-viewport.command.js +0 -25
  250. package/dist/collection/classes/commands/update-viewport.command.js.map +0 -1
  251. package/dist/collection/classes/core/command-manager.class.js +0 -51
  252. package/dist/collection/classes/core/command-manager.class.js.map +0 -1
  253. package/dist/collection/classes/core/database.class.js +0 -236
  254. package/dist/collection/classes/core/database.class.js.map +0 -1
  255. package/dist/collection/classes/core/history.class.js +0 -51
  256. package/dist/collection/classes/core/history.class.js.map +0 -1
  257. package/dist/collection/classes/structures/circular-buffer.structure.js +0 -48
  258. package/dist/collection/classes/structures/circular-buffer.structure.js.map +0 -1
  259. package/dist/collection/configs/default-engine-state.js.map +0 -1
  260. package/dist/collection/interfaces/command.interface.js +0 -2
  261. package/dist/collection/interfaces/command.interface.js.map +0 -1
  262. package/dist/components/p-C9hrbrUN.js.map +0 -1
  263. package/dist/components/p-UsToUu6G.js.map +0 -1
  264. package/dist/components/p-YqK8ch2R.js.map +0 -1
  265. package/dist/components/p-kn4eunyR.js +0 -3338
  266. package/dist/components/p-kn4eunyR.js.map +0 -1
  267. package/dist/esm/index-Cw77zP6g.js.map +0 -1
  268. package/dist/esm/index-YVlgItFD.js.map +0 -1
  269. package/dist/stencil/p-Cw77zP6g.js.map +0 -1
  270. package/dist/stencil/p-YVlgItFD.js +0 -2
  271. package/dist/stencil/p-YVlgItFD.js.map +0 -1
  272. package/dist/stencil/p-fe738990.entry.js +0 -2
  273. package/dist/stencil/p-fe738990.entry.js.map +0 -1
  274. package/dist/types/classes/commands/add-object.command.d.ts +0 -9
  275. package/dist/types/classes/commands/add-selection-group.command.d.ts +0 -10
  276. package/dist/types/classes/commands/base.command.d.ts +0 -11
  277. package/dist/types/classes/commands/batch.command.d.ts +0 -8
  278. package/dist/types/classes/commands/move-selection-group.command.d.ts +0 -13
  279. package/dist/types/classes/commands/remove-object.command.d.ts +0 -9
  280. package/dist/types/classes/commands/remove-selection-group.command.d.ts +0 -8
  281. package/dist/types/classes/commands/resize-selection-group.command.d.ts +0 -20
  282. package/dist/types/classes/commands/rotate-selection-group.command.d.ts +0 -10
  283. package/dist/types/classes/commands/update-object.command.d.ts +0 -11
  284. package/dist/types/classes/commands/update-viewport.command.d.ts +0 -21
  285. package/dist/types/classes/core/command-manager.class.d.ts +0 -16
  286. package/dist/types/classes/core/database.class.d.ts +0 -29
  287. package/dist/types/classes/core/history.class.d.ts +0 -12
  288. package/dist/types/classes/structures/circular-buffer.structure.d.ts +0 -13
  289. package/dist/types/interfaces/command.interface.d.ts +0 -6
  290. /package/dist/stencil/{p-8b831c94.entry.js.map → p-d702c5af.entry.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-Cw77zP6g.js';
2
- import { K as KritzelBrushTool, a as KritzelTextTool, b as KritzelMouseButton, c as KritzelSelectionTool, D as DEFAULT_BRUSH_CONFIG, d as KritzelEraserTool, e as DEFAULT_TEXT_CONFIG, f as KritzelImageTool, g as KritzelWorkspace, h as KritzelKeyboardHelper, i as KritzelBaseHandler, j as KritzelToolRegistry, k as KrtizelSelectionBox, l as KritzelSelectionGroup, B as BatchCommand, R as RemoveSelectionGroupCommand, A as AddSelectionGroupCommand, m as KritzelBaseCommand, O as ObjectHelper, n as KritzelReviver, o as RemoveObjectCommand, p as AddObjectCommand, U as UpdateObjectCommand, q as KritzelEventHelper, r as KritzelBaseTool } from './index-YVlgItFD.js';
1
+ import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-SGde3HXB.js';
2
+ import { U as KritzelDevicesHelper, G as KritzelBrushTool, L as KritzelTextTool, V as KritzelMouseButton, M as KritzelSelectionTool, S as DEFAULT_BRUSH_CONFIG, I as KritzelEraserTool, T as DEFAULT_TEXT_CONFIG, J as KritzelImageTool, R as KritzelWorkspace, W as KritzelKeyboardHelper, X as KritzelBaseHandler, Y as KritzelToolRegistry, Z as KritzelSelectionBox, _ as KritzelSelectionGroup, $ as KritzelBaseObject, F as KritzelImage, K as KritzelText, E as KritzelPath, a0 as Doc, a1 as DEFAULT_SYNC_CONFIG, a2 as UndoManager, Q as KritzelAppStateMap, a3 as ObjectHelper, a4 as KritzelEventHelper, a5 as KritzelBaseTool } from './default-text-tool.config-nXXHSTK9.js';
3
3
 
4
4
  const kritzelColorCss = ":host{display:flex}.checkerboard-bg{background:repeating-conic-gradient(#ccc 0% 25%, #fff 0% 50%) 50% / 8px 8px;position:relative;overflow:hidden}.color-circle{width:24px;height:24px;border-radius:50%;box-sizing:border-box;display:block}.color-circle.white{border:1px solid var(--kritzel-color-palette-circle-border-color, #dddcdc)}";
5
5
 
@@ -35,13 +35,13 @@ const KritzelColor = class {
35
35
  }
36
36
  render() {
37
37
  const isColorVeryLight = this.isLightColor(this.value);
38
- return (h(Host, { key: '000e54c604c8ceca2c44365e95ec1f5bfb1b729a' }, h("div", { key: '77b2abeae70e4a80714e1364eb4e11e67f16d066', class: "checkerboard-bg", style: {
38
+ return (h(Host, { key: '198dba41e1600d76faace18de78191d2b7a551ec' }, h("div", { key: 'ee690cffb7925e09cb2c51022eec607247a4849f', class: "checkerboard-bg", style: {
39
39
  width: `${this.size}px`,
40
40
  height: `${this.size}px`,
41
41
  borderRadius: '50%',
42
42
  display: 'inline-block',
43
43
  position: 'relative',
44
- } }, h("div", { key: 'df71720cf51d845a36598499adb900a30770c503', class: {
44
+ } }, h("div", { key: '66cc8df8fabd008db8c00942994875e3e8d722ce', class: {
45
45
  'color-circle': true,
46
46
  'white': isColorVeryLight,
47
47
  }, style: {
@@ -84,7 +84,7 @@ const KritzelColorPalette = class {
84
84
  render() {
85
85
  const displayedColors = this.isExpanded ? this.colors : this.colors.slice(0, 6);
86
86
  const expandedHeight = this.isExpanded ? this.calculateHeight() : '32px';
87
- return (h(Host, { key: 'd533725a8ab2019ae963959727283fbbf833c56a' }, h("div", { key: '7fb50c16d79e9b7330100b0f4e116f8f07b20827', class: {
87
+ return (h(Host, { key: '2ead7cd530ce181856e5f582f086a22a1fe69390' }, h("div", { key: 'fcc75b267f36e271d50615bfde42a29c28aa2536', class: {
88
88
  'color-grid': true,
89
89
  'expanded': this.isExpanded,
90
90
  }, style: {
@@ -149,7 +149,7 @@ const KritzelContextMenu = class {
149
149
  return defaultValue;
150
150
  }
151
151
  render() {
152
- return (h(Host, { key: '45b9652285f9c3fe7568cbe222667d23c151622f' }, h("div", { key: '9aecc01027f297fa4d991780efaaf51b8d4542dc', class: "menu-container" }, this.processedItems.map(({ item, isDisabled }, index) => (h("button", { key: `${item.label}-${index}`, class: { 'menu-item': true, 'disabled': isDisabled }, onClick: () => this.handleItemClick(item, isDisabled), disabled: isDisabled }, item.icon && h("kritzel-icon", { name: item.icon, size: 16 }), h("span", { class: "label" }, item.label)))))));
152
+ return (h(Host, { key: '908711e45cb4ea41f25c4f66a9d3b03c847f886e' }, h("div", { key: '7dcb6e5654ecafebc1fc1a2efb9fa1b8678236c4', class: "menu-container" }, this.processedItems.map(({ item, isDisabled }, index) => (h("button", { key: `${item.label}-${index}`, class: { 'menu-item': true, 'disabled': isDisabled }, onClick: () => this.handleItemClick(item, isDisabled), disabled: isDisabled }, item.icon && h("kritzel-icon", { name: item.icon, size: 16 }), h("span", { class: "label" }, item.label)))))));
153
153
  }
154
154
  static get watchers() { return {
155
155
  "items": ["onItemsChanged"]
@@ -192,14 +192,14 @@ const KritzelControlBrushConfig = class {
192
192
  this.toolChange.emit(this.tool);
193
193
  }
194
194
  render() {
195
- return (h(Host, { key: '4b060826312e6d5a2117f5ba9522553af9b02d6f' }, h("div", { key: '0975a250184d5bb2d38cc60263bd718157230d8c', style: {
195
+ return (h(Host, { key: '8fe8c0564f491121c0c44c6ff4083034f92dbb67' }, h("div", { key: '3e8a69b827785976768bfc1e809126bee7c48c62', style: {
196
196
  display: 'flex',
197
197
  flexDirection: 'row',
198
198
  alignItems: this.isExpanded ? 'flex-start' : 'center',
199
199
  justifyContent: 'flex-start',
200
200
  width: '100%',
201
201
  gap: '8px',
202
- } }, h("kritzel-color-palette", { key: 'df84a6fdda01bc7bf3aff42e3b88c4bd9dca500f', colors: this.palette, selectedColor: this.tool.color, isExpanded: this.isExpanded, isOpaque: true, onColorChange: color => this.handleColorChange(color) }), h("button", { key: 'e43c19612807fc4f9cd1bf04f4fb79a048cfd62b', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand', style: this.palette.length > 6 ? { visibillity: 'visible' } : { visibility: 'hidden' } }, h("kritzel-icon", { key: '915cce6c4744ad175f3836c946330882de840880', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-stroke-size", { key: 'c07eebae3ba1785e2644c6b5a22d23f76be950fb', selectedSize: this.tool.size, onSizeChange: event => this.handleSizeChange(event) })));
202
+ } }, h("kritzel-color-palette", { key: 'c9056f81cf47d81fef0a0f5743000dcd6633258a', colors: this.palette, selectedColor: this.tool.color, isExpanded: this.isExpanded, isOpaque: true, onColorChange: color => this.handleColorChange(color) }), h("button", { key: '2f307264b80a732d976edeb025d509bc1164606b', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand', style: this.palette.length > 6 ? { visibillity: 'visible' } : { visibility: 'hidden' } }, h("kritzel-icon", { key: '08133ba0a23353b2bb3f87c685a7a0798b8dd16c', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-stroke-size", { key: '3de25cc80029ffdfdc173c4c79e937a7dc329743', selectedSize: this.tool.size, onSizeChange: event => this.handleSizeChange(event) })));
203
203
  }
204
204
  static get watchers() { return {
205
205
  "tool": ["handleToolChange"]
@@ -233,44 +233,18 @@ const KritzelControlTextConfig = class {
233
233
  this.toolChange.emit(this.tool);
234
234
  }
235
235
  render() {
236
- return (h(Host, { key: '82e611092700f057bd36823e7f7503fe7a0423ed' }, h("div", { key: '37ed39adeeeb58981a917918cd185e96d589e973', style: {
236
+ return (h(Host, { key: '3695b187943af25566885d63257ae3de9f405ea5' }, h("div", { key: '7bb146ae3c188478ba17f18f70fd170ce3536308', style: {
237
237
  display: 'flex',
238
238
  flexDirection: 'row',
239
239
  alignItems: 'center',
240
240
  justifyContent: 'flex-start',
241
241
  width: '100%',
242
242
  gap: '8px',
243
- } }, h("kritzel-font-family", { key: 'cd8afc5c4a1eee087610cd3d5a6c05210cfda6b3', selectedFontFamily: this.tool.fontFamily, onFontFamilyChange: event => this.handleFamilyChange(event) }), h("button", { key: '085f1bba060bde27a7b64dc5477bb51305b76235', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand' }, h("kritzel-icon", { key: '3ff8fec207120e67f43315c6dace72fc2f6bd0f1', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-color-palette", { key: '2e29d01a6b5c0e4a8ec347e63b6a2698c282db40', colors: this.tool.palette, selectedColor: this.tool.fontColor, isExpanded: this.isExpanded, onColorChange: event => this.handleColorChange(event) }), h("kritzel-font-size", { key: 'c972068f1251d66e756b8de72fbdd1b6002d1daa', selectedSize: this.tool.fontSize, fontFamily: this.tool.fontFamily, onSizeChange: event => this.handleSizeChange(event) })));
243
+ } }, h("kritzel-font-family", { key: '87f4c5ac2e2a4cfea216b1b828faad231438b9ec', selectedFontFamily: this.tool.fontFamily, onFontFamilyChange: event => this.handleFamilyChange(event) }), h("button", { key: '2e73aaf7da659b9e069c247cc762f68394212293', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand' }, h("kritzel-icon", { key: '785b664697ba266432c535ea26e0665f8d8d657f', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-color-palette", { key: 'ed2517a39d254b77f45154914b3ce6a934f66c33', colors: this.tool.palette, selectedColor: this.tool.fontColor, isExpanded: this.isExpanded, onColorChange: event => this.handleColorChange(event) }), h("kritzel-font-size", { key: '9b25c9607fa69c991e769852e3e3e378e48387bd', selectedSize: this.tool.fontSize, fontFamily: this.tool.fontFamily, onSizeChange: event => this.handleSizeChange(event) })));
244
244
  }
245
245
  };
246
246
  KritzelControlTextConfig.style = kritzelControlTextConfigCss;
247
247
 
248
- class KritzelDevicesHelper {
249
- static isTouchDevice() {
250
- return window.matchMedia('(any-pointer: coarse)').matches;
251
- }
252
- static isAndroid() {
253
- return /android/i.test(navigator.userAgent);
254
- }
255
- static isIOS() {
256
- return /iPad|iPhone|iPod/.test(navigator.userAgent);
257
- }
258
- static detectOS() {
259
- if (this.isIOS()) {
260
- return 'iOS';
261
- }
262
- else if (this.isAndroid()) {
263
- return 'Android';
264
- }
265
- else {
266
- return 'Other';
267
- }
268
- }
269
- static isFirefox() {
270
- return /firefox/i.test(navigator.userAgent);
271
- }
272
- }
273
-
274
248
  const kritzelControlsCss = ":host{display:flex;flex-direction:column;user-select:none}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:10000;position:relative}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;outline:none;background:none;cursor:pointer;-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-divider{width:var(--kritzel-controls-divider-width, 1px);height:var(--kritzel-controls-divider-height, 24px);background-color:var(--kritzel-controls-divider-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;width:40px;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:50%}.kritzel-config:focus{outline:var(--kritzel-menu-focus-outline, 2px solid #e3e3e3)}.color-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:pointer;border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.font-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:pointer;border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.no-config{height:24px;width:24px;border-radius:50%;border:1px dashed gray}kritzel-tooltip{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);z-index:10001}";
275
249
 
276
250
  const KritzelControls = class {
@@ -374,13 +348,13 @@ const KritzelControls = class {
374
348
  }
375
349
  render() {
376
350
  const hasNoConfig = this.activeControl?.config === undefined || this.activeControl?.config === null;
377
- return (h(Host, { key: 'ab3e5f078d6d197c6e10c9dee180c04ef85281bf', class: {
351
+ return (h(Host, { key: 'a463310d88265b71097f838bf775abdcabc99225', class: {
378
352
  mobile: this.isTouchDevice,
379
- } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '290ceb6f2c46eb7e869a4741dd6600bc7c47bbb4', style: {
353
+ } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '267e9c26b41a52c655209dbaa8c85cbd72323577', style: {
380
354
  position: 'absolute',
381
355
  bottom: '56px',
382
356
  left: '12px',
383
- }, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: 'd2590bc56b709e77910e7159296741c8859158d7', class: "kritzel-controls" }, this.controls.map(control => {
357
+ }, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: 'c55773245c925e1b972f3e83cb4d8f1c93ebe995', class: "kritzel-controls" }, this.controls.map(control => {
384
358
  if (control.type === 'tool') {
385
359
  return (h("button", { class: {
386
360
  'kritzel-control': true,
@@ -477,7 +451,7 @@ const KritzelCursorTrail = class {
477
451
  }
478
452
  }
479
453
  render() {
480
- return (h(Host, { key: '10ef620f19d72a8a5c3a12d0d98686bc69308a30' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: 'd03403051e53422aaa28d6360aaa9c0391e3ef6a', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
454
+ return (h(Host, { key: '87003b14680b3cbca302e7b31ff57e74cc774e25' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: 'aa6460089c9f3157d2dea9396405b14ab8cc1710', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
481
455
  position: 'absolute',
482
456
  left: '0',
483
457
  top: '0',
@@ -723,6 +697,7 @@ const KritzelEditor = class {
723
697
  customSvgIcons = {};
724
698
  isControlsVisible = true;
725
699
  isUtilityPanelVisible = true;
700
+ syncConfig;
726
701
  isReady;
727
702
  isEngineReady = false;
728
703
  isControlsReady = false;
@@ -740,6 +715,14 @@ const KritzelEditor = class {
740
715
  this.checkIsReady();
741
716
  }
742
717
  }
718
+ onWorkspacesChange(newWorkspaces) {
719
+ if (this.activeWorkspace) {
720
+ const updatedActiveWorkspace = newWorkspaces.find(ws => ws.id === this.activeWorkspace.id);
721
+ if (updatedActiveWorkspace && updatedActiveWorkspace !== this.activeWorkspace) {
722
+ this.activeWorkspace = updatedActiveWorkspace;
723
+ }
724
+ }
725
+ }
743
726
  handleTouchStart(event) {
744
727
  if (event.cancelable) {
745
728
  event.preventDefault();
@@ -848,11 +831,12 @@ const KritzelEditor = class {
848
831
  }
849
832
  }
850
833
  render() {
851
- return (h(Host, { key: '8dc4fa4d4c3512d3a0ac40d5ab67566720b8a3e4' }, h("kritzel-workspace-manager", { key: 'b7a032b8bb01b27af192719b46a3891037770a28', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: '163c4aea9d07290c89e63931ed4a4cf0184757be', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, scaleMax: this.scaleMax, scaleMin: this.scaleMin, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => (this.workspaces = event.detail) }), h("kritzel-controls", { key: '4c9307c3831f2b179a446265f3226b0ae1541afc', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, onIsControlsReady: () => (this.isControlsReady = true) })));
834
+ return (h(Host, { key: '5e91eb780eed57131e0389969c359b9ec9a4faaf' }, h("kritzel-workspace-manager", { key: 'c212455bc5042d35963e774d918ef15f5e4fd7e1', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: '214b6c42b21893172401a6918b2797c0758b3d48', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, syncConfig: this.syncConfig, scaleMax: this.scaleMax, scaleMin: this.scaleMin, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => (this.workspaces = event.detail) }), h("kritzel-controls", { key: '32c6b6408e2fd2c4eaa30efc50bb75b55252a265', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, onIsControlsReady: () => (this.isControlsReady = true) })));
852
835
  }
853
836
  static get watchers() { return {
854
837
  "isEngineReady": ["onIsEngineReady"],
855
- "isControlsReady": ["onIsControlsReady"]
838
+ "isControlsReady": ["onIsControlsReady"],
839
+ "workspaces": ["onWorkspacesChange"]
856
840
  }; }
857
841
  };
858
842
  KritzelEditor.style = kritzelEditorCss;
@@ -902,7 +886,10 @@ class KritzelViewport {
902
886
  if (event.pointerType === 'touch') {
903
887
  const activePointers = Array.from(this._core.store.state.pointers.values());
904
888
  if (activePointers.length === 2) {
905
- this._core.store.state.currentPath = null;
889
+ const currentPath = this._core.store.currentPath;
890
+ if (currentPath) {
891
+ this._core.store.state.objectsMap.remove(obj => obj.id === currentPath.id);
892
+ }
906
893
  this._core.store.state.isScaling = true;
907
894
  const firstTouchX = activePointers[0].clientX - this._core.store.offsetX;
908
895
  const firstTouchY = activePointers[0].clientY - this._core.store.offsetY;
@@ -1049,11 +1036,11 @@ class KritzelViewport {
1049
1036
  class KritzelKeyHandler extends KritzelBaseHandler {
1050
1037
  shortcuts = [
1051
1038
  // General
1052
- { key: 'Escape', condition: c => !!c.store.state.selectionGroup, action: c => c.clearSelection() },
1053
- { key: 'Delete', condition: c => !!c.store.state.selectionGroup, action: c => c.delete() },
1054
- // History
1055
- { key: 'z', ctrl: true, action: c => c.history.undo() },
1056
- { key: 'y', ctrl: true, action: c => c.history.redo() },
1039
+ { key: 'Escape', condition: c => !!c.store.selectionGroup, action: c => c.clearSelection() },
1040
+ { key: 'Delete', condition: c => !!c.store.selectionGroup, action: c => c.delete() },
1041
+ // Undo/Redo
1042
+ { key: 'z', ctrl: true, action: c => c.undo() },
1043
+ { key: 'y', ctrl: true, action: c => c.redo() },
1057
1044
  // Tool selection
1058
1045
  { key: 's', ctrl: true, action: () => this.switchTool('selection') },
1059
1046
  { key: 'b', ctrl: true, action: () => this.switchTool('brush') },
@@ -1064,21 +1051,21 @@ class KritzelKeyHandler extends KritzelBaseHandler {
1064
1051
  {
1065
1052
  key: 'c',
1066
1053
  ctrl: true,
1067
- condition: c => !!c.store.state.selectionGroup,
1054
+ condition: c => !!c.store.selectionGroup,
1068
1055
  action: c => {
1069
1056
  c.copy();
1070
1057
  c.rerender();
1071
1058
  },
1072
1059
  },
1073
- { key: 'v', ctrl: true, condition: c => !!c.store.state.copiedObjects && !c.store.state.activeText, action: c => c.paste() },
1060
+ { key: 'v', ctrl: true, condition: c => !!c.store.state.copiedObjects && !c.store.activeText, action: c => c.paste() },
1074
1061
  // Text editing
1075
- // { key: 'a', ctrl: true, condition: c => !!c.store.state.activeText, action: c => c.store.state.activeText.selectAll() },
1076
- // { key: 'v', ctrl: true, condition: c => !!c.store.state.activeText, action: c => c.store.state.activeText.insertFromClipboard() },
1062
+ // { key: 'a', ctrl: true, condition: c => !!c.store.activeText, action: c => c.store.activeText.selectAll() },
1063
+ // { key: 'v', ctrl: true, condition: c => !!c.store.activeText, action: c => c.store.activeText.insertFromClipboard() },
1077
1064
  // Object layering
1078
- { key: '+', ctrl: true, condition: c => !!c.store.state.selectionGroup, action: c => c.bringForward() },
1079
- { key: '-', ctrl: true, condition: c => !!c.store.state.selectionGroup, action: c => c.sendBackward() },
1080
- { key: '*', shift: true, condition: c => !!c.store.state.selectionGroup, action: c => c.bringToFront() },
1081
- { key: '_', shift: true, condition: c => !!c.store.state.selectionGroup, action: c => c.sendToBack() },
1065
+ { key: '+', ctrl: true, condition: c => !!c.store.selectionGroup, action: c => c.bringForward() },
1066
+ { key: '-', ctrl: true, condition: c => !!c.store.selectionGroup, action: c => c.sendBackward() },
1067
+ { key: '*', shift: true, condition: c => !!c.store.selectionGroup, action: c => c.bringToFront() },
1068
+ { key: '_', shift: true, condition: c => !!c.store.selectionGroup, action: c => c.sendToBack() },
1082
1069
  ];
1083
1070
  constructor(core) {
1084
1071
  super(core);
@@ -1120,25 +1107,25 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
1120
1107
  }
1121
1108
  const selectionTool = this._core.store.state.activeTool;
1122
1109
  selectionTool?.moveHandler?.cancelPendingDrag();
1123
- if (this._core.store.state.selectionBox) {
1124
- this._core.store.state.objectsMap.remove(object => object instanceof KrtizelSelectionBox);
1125
- this._core.store.state.selectionBox = null;
1110
+ if (this._core.store.selectionBox) {
1111
+ this._core.store.state.objectsMap.remove(object => object instanceof KritzelSelectionBox);
1126
1112
  this._core.store.state.isSelecting = false;
1127
1113
  }
1128
1114
  const selectedObject = this._core.getObjectFromPointerEvent(event, '.object');
1129
- if (selectedObject && !(selectedObject instanceof KritzelSelectionGroup) && !(selectedObject instanceof KrtizelSelectionBox)) {
1115
+ if (selectedObject && !(selectedObject instanceof KritzelSelectionGroup) && !(selectedObject instanceof KritzelSelectionBox)) {
1130
1116
  const selectionGroup = KritzelSelectionGroup.create(this._core);
1131
1117
  selectionGroup.addOrRemove(selectedObject);
1132
1118
  selectionGroup.isSelected = true;
1133
1119
  selectionGroup.rotation = selectedObject.rotation;
1134
1120
  this._core.store.state.isSelecting = false;
1135
- const batch = new BatchCommand(this._core, this, [
1136
- new RemoveSelectionGroupCommand(this._core, this._core.store.state.selectionGroup),
1137
- new AddSelectionGroupCommand(this._core, this, selectionGroup),
1138
- ]);
1139
- this._core.commandManager.executeCommand(batch);
1121
+ const currentSelectionGroup = this._core.store.selectionGroup;
1122
+ if (currentSelectionGroup) {
1123
+ this._core.removeSelectionGroup();
1124
+ }
1125
+ this._core.addSelectionGroup(selectionGroup);
1126
+ this._core.rerender();
1140
1127
  }
1141
- this._core.store.state.contextMenuItems = this._core.store.state.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
1128
+ this._core.store.state.contextMenuItems = this._core.store.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
1142
1129
  let x = event.clientX - this._core.store.offsetX;
1143
1130
  let y = event.clientY - this._core.store.offsetY;
1144
1131
  const menuWidthEstimate = 150;
@@ -1166,15 +1153,11 @@ class KritzelClassHelper {
1166
1153
  }
1167
1154
  }
1168
1155
 
1169
- const DEFAULT_ENGINE_STATE = {
1156
+ const DEFAULT_ENGINE_CONFIG = {
1170
1157
  activeWorkspace: null,
1171
1158
  activeTool: null,
1172
- activeText: null,
1173
- currentPath: null,
1174
1159
  copiedObjects: null,
1175
1160
  objectsMap: null,
1176
- selectionBox: null,
1177
- selectionGroup: null,
1178
1161
  resizeHandleType: null,
1179
1162
  hasViewportChanged: false,
1180
1163
  hasObjectsChanged: false,
@@ -1201,7 +1184,6 @@ const DEFAULT_ENGINE_STATE = {
1201
1184
  showObjectInfo: false,
1202
1185
  showViewportInfo: false,
1203
1186
  logCommands: false,
1204
- logDatabase: false,
1205
1187
  },
1206
1188
  host: null,
1207
1189
  pointerX: 0,
@@ -1220,396 +1202,314 @@ const DEFAULT_ENGINE_STATE = {
1220
1202
  translateYMin: 0,
1221
1203
  viewportWidth: 0,
1222
1204
  viewportHeight: 0,
1223
- historyBufferSize: 1000,
1224
1205
  longTouchTimeout: null,
1225
1206
  longTouchDelay: 300,
1226
1207
  pointers: new Map(),
1227
1208
  workspaces: [],
1228
1209
  };
1229
1210
 
1230
- class KritzelDatabase {
1231
- db = null;
1232
- dbName;
1233
- dbVersion;
1234
- isLoggingEnabled;
1235
- constructor(dbName, dbVersion, isLoggingEnabled = false) {
1236
- this.dbName = dbName;
1237
- this.dbVersion = dbVersion;
1238
- this.isLoggingEnabled = isLoggingEnabled;
1239
- }
1240
- async open(stores) {
1241
- return new Promise((resolve, reject) => {
1242
- if (this.db) {
1243
- resolve();
1244
- return;
1245
- }
1246
- if (this.isLoggingEnabled) {
1247
- console.info(`[IndexedDB] Opening database: ${this.dbName}, version: ${this.dbVersion}`);
1248
- }
1249
- const request = indexedDB.open(this.dbName, this.dbVersion);
1250
- request.onerror = () => {
1251
- console.error('IndexedDB error:', request.error);
1252
- reject(request.error);
1253
- };
1254
- request.onsuccess = () => {
1255
- this.db = request.result;
1256
- if (this.isLoggingEnabled) {
1257
- console.info(`[IndexedDB] Database opened successfully.`);
1258
- }
1259
- resolve();
1260
- };
1261
- request.onupgradeneeded = event => {
1262
- if (this.isLoggingEnabled) {
1263
- console.info(`[IndexedDB] Upgrade needed for database: ${this.dbName}`);
1264
- }
1265
- const db = event.target.result;
1266
- stores.forEach(storeConfig => {
1267
- if (!db.objectStoreNames.contains(storeConfig.name)) {
1268
- if (this.isLoggingEnabled) {
1269
- console.info(`[IndexedDB] Creating store: ${storeConfig.name}`);
1270
- }
1271
- const store = db.createObjectStore(storeConfig.name, storeConfig.options);
1272
- if (storeConfig.indices) {
1273
- storeConfig.indices.forEach(index => {
1274
- if (this.isLoggingEnabled) {
1275
- console.info(`[IndexedDB] Creating index: ${index.name} on store: ${storeConfig.name}`);
1276
- }
1277
- store.createIndex(index.name, index.keyPath, index.options);
1278
- });
1279
- }
1280
- }
1281
- });
1282
- };
1283
- });
1284
- }
1285
- close() {
1286
- if (this.db) {
1287
- if (this.isLoggingEnabled) {
1288
- console.info(`[IndexedDB] Closing database: ${this.dbName}`);
1289
- }
1290
- this.db.close();
1291
- this.db = null;
1292
- }
1211
+ class KritzelCustomElement extends KritzelBaseObject {
1212
+ __class__ = 'KritzelCustomElement';
1213
+ element;
1214
+ isInteractive = true;
1215
+ constructor(config) {
1216
+ super();
1217
+ if (config) {
1218
+ this.translateX = config.translateX || 0;
1219
+ this.translateY = config.translateY || 0;
1220
+ this.scale = config.scale || 1;
1221
+ this.element = config.element;
1222
+ this.height = config.height || 0;
1223
+ this.width = config.width || 0;
1224
+ }
1225
+ }
1226
+ static create(core, config) {
1227
+ const object = new KritzelCustomElement(config);
1228
+ object._core = core;
1229
+ object.id = object.generateId();
1230
+ object.workspaceId = core.store.state.activeWorkspace.id;
1231
+ return object;
1293
1232
  }
1294
- async add(storeName, item) {
1295
- if (this.isLoggingEnabled) {
1296
- console.info('[IndexedDB] Add:', { storeName, item });
1233
+ mount(element) {
1234
+ if (element === null) {
1235
+ return;
1297
1236
  }
1298
- if (item.serialize === undefined) {
1299
- throw new Error('Item does not implement KritzelSerializable interface.');
1237
+ // If already mounted to the same element and content is still attached, skip
1238
+ if (this.isMounted && this.elementRef === element && this.element.parentElement === element) {
1239
+ return;
1300
1240
  }
1301
- const serializedItem = item.serialize();
1302
- return this.executeTransaction(storeName, 'readwrite', store => store.add(serializedItem));
1241
+ this.elementRef = element;
1242
+ this.isMounted = true;
1243
+ // Clear existing content and append the element
1244
+ this.elementRef.innerHTML = '';
1245
+ this.elementRef.appendChild(this.element);
1303
1246
  }
1304
- async get(storeName, key) {
1305
- if (this.isLoggingEnabled) {
1306
- console.info('[IndexedDB] Get:', { storeName, key });
1247
+ resize(x, y, width, height) {
1248
+ if (width <= 1 || height <= 1) {
1249
+ return;
1307
1250
  }
1308
- return this.executeTransaction(storeName, 'readonly', store => store.get(key));
1309
- }
1310
- async getAll(storeName) {
1311
- if (this.isLoggingEnabled) {
1312
- console.info('[IndexedDB] GetAll:', { storeName });
1251
+ this.width = width;
1252
+ this.height = height;
1253
+ this.translateX = x;
1254
+ this.translateY = y;
1255
+ if (this.element) {
1256
+ this.element.style.width = `${width}px`;
1257
+ this.element.style.height = `${height}px`;
1313
1258
  }
1314
- return this.executeTransaction(storeName, 'readonly', store => store.getAll());
1259
+ // Update to sync changes to y.js and propagate to other tabs
1260
+ this._core.store.state.objectsMap.update(this);
1315
1261
  }
1316
- async update(storeName, item) {
1317
- if (this.isLoggingEnabled) {
1318
- console.info('[IndexedDB] Update:', { storeName, item });
1319
- }
1320
- if (item.serialize === undefined) {
1321
- throw new Error('Item does not implement KritzelSerializable interface.');
1322
- }
1323
- const serializedItem = item.serialize();
1324
- return this.executeTransaction(storeName, 'readwrite', store => store.put(serializedItem));
1262
+ copy() {
1263
+ const copiedObject = Object.create(Object.getPrototypeOf(this));
1264
+ Object.assign(copiedObject, this);
1265
+ copiedObject.id = this.generateId();
1266
+ copiedObject.isMounted = false;
1267
+ copiedObject.element = this.element.cloneNode(true);
1268
+ return copiedObject;
1325
1269
  }
1326
- async delete(storeName, key) {
1327
- if (this.isLoggingEnabled) {
1328
- console.info('[IndexedDB] Delete:', { storeName, key });
1329
- }
1330
- return this.executeTransaction(storeName, 'readwrite', store => store.delete(key));
1270
+ }
1271
+
1272
+ class KritzelReviver {
1273
+ _core;
1274
+ constructor(core) {
1275
+ this._core = core;
1331
1276
  }
1332
- async deleteByRange(storeName, range) {
1333
- if (this.isLoggingEnabled) {
1334
- console.info('[IndexedDB] DeleteByRange:', { storeName, range });
1277
+ revive(obj) {
1278
+ if (obj && typeof obj === 'object') {
1279
+ if (obj.__class__) {
1280
+ let revivedObj;
1281
+ switch (obj.__class__) {
1282
+ case 'KritzelPath':
1283
+ revivedObj = KritzelPath.create(this._core).deserialize(obj);
1284
+ break;
1285
+ case 'KritzelText':
1286
+ revivedObj = KritzelText.create(this._core, obj.fontSize, obj.fontFamily).deserialize(obj);
1287
+ break;
1288
+ case 'KritzelImage':
1289
+ revivedObj = KritzelImage.create(this._core).deserialize(obj);
1290
+ break;
1291
+ case 'KritzelCustomElement':
1292
+ revivedObj = KritzelCustomElement.create(this._core).deserialize(obj);
1293
+ break;
1294
+ case 'KritzelSelectionGroup':
1295
+ revivedObj = KritzelSelectionGroup.create(this._core).deserialize(obj);
1296
+ break;
1297
+ case 'KritzelWorkspace':
1298
+ revivedObj = KritzelWorkspace.create(this._core, obj).deserialize(obj);
1299
+ break;
1300
+ case 'KritzelBrushTool':
1301
+ revivedObj = new KritzelBrushTool(this._core);
1302
+ break;
1303
+ case 'KritzelEraserTool':
1304
+ revivedObj = new KritzelEraserTool(this._core);
1305
+ break;
1306
+ case 'KritzelImageTool':
1307
+ revivedObj = new KritzelImageTool(this._core);
1308
+ break;
1309
+ case 'KritzelSelectionTool':
1310
+ revivedObj = new KritzelSelectionTool(this._core);
1311
+ break;
1312
+ case 'KritzelTextTool':
1313
+ revivedObj = new KritzelTextTool(this._core);
1314
+ break;
1315
+ default:
1316
+ revivedObj = obj;
1317
+ }
1318
+ return revivedObj;
1319
+ }
1320
+ const newObj = Array.isArray(obj) ? [] : {};
1321
+ for (const key in obj) {
1322
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1323
+ newObj[key] = this.revive(obj[key]);
1324
+ }
1325
+ }
1326
+ return newObj;
1335
1327
  }
1336
- return this.executeTransaction(storeName, 'readwrite', store => store.delete(range));
1328
+ return obj;
1337
1329
  }
1338
- async getAllByRange(storeName, range) {
1339
- if (this.isLoggingEnabled) {
1340
- console.info('[IndexedDB] GetAllByRange:', { storeName, range });
1341
- }
1342
- return this.executeTransaction(storeName, 'readonly', store => {
1343
- return store.getAll(range);
1344
- });
1330
+ }
1331
+
1332
+ class KritzelObjectMap {
1333
+ map;
1334
+ _ydoc = null;
1335
+ _objectsMap = null;
1336
+ _providers = [];
1337
+ _undoManager = null;
1338
+ _reviver = null;
1339
+ _core = null;
1340
+ _workspaceId = null;
1341
+ _isReady = false;
1342
+ _temporaryItemsCount = 0;
1343
+ get isReady() {
1344
+ return this._isReady;
1345
+ }
1346
+ get undoManager() {
1347
+ return this._undoManager;
1348
+ }
1349
+ get workspaceId() {
1350
+ return this._workspaceId;
1345
1351
  }
1346
- async getAllByIndex(storeName, indexName, query) {
1347
- if (this.isLoggingEnabled) {
1348
- console.info('[IndexedDB] GetAllByIndex:', { storeName, indexName, query });
1349
- }
1350
- return this.executeTransaction(storeName, 'readonly', store => {
1351
- const index = store.index(indexName);
1352
- return index.getAll(query);
1353
- });
1352
+ constructor() {
1353
+ this.map = new Map();
1354
1354
  }
1355
- async executeTransaction(storeName, mode, action) {
1356
- if (!this.db) {
1357
- throw new Error('Database is not open.');
1358
- }
1359
- return new Promise((resolve, reject) => {
1360
- const transaction = this.db.transaction(storeName, mode);
1361
- const store = transaction.objectStore(storeName);
1362
- const request = action(store);
1363
- let requestResult;
1364
- transaction.oncomplete = () => {
1365
- resolve(requestResult);
1366
- };
1367
- transaction.onabort = () => {
1368
- reject(transaction.error ?? new Error('Transaction aborted'));
1369
- };
1370
- transaction.onerror = () => {
1371
- reject(transaction.error);
1372
- };
1373
- request.onsuccess = () => {
1374
- requestResult = request.result;
1375
- };
1355
+ async initialize(core, workspaceId, config) {
1356
+ this._core = core;
1357
+ this._workspaceId = workspaceId;
1358
+ this._reviver = new KritzelReviver(core);
1359
+ // Create a dedicated Y.Doc for this workspace
1360
+ this._ydoc = new Doc();
1361
+ this._objectsMap = this._ydoc.getMap('objects');
1362
+ const docName = `kritzel-workspace-${workspaceId}`;
1363
+ const finalConfig = config ?? DEFAULT_SYNC_CONFIG;
1364
+ // Instantiate providers from configuration
1365
+ for (const providerConfig of finalConfig.providers) {
1366
+ let provider;
1367
+ // Check if it's a class constructor or a factory
1368
+ if (typeof providerConfig === 'function') {
1369
+ // It's a class constructor
1370
+ provider = new providerConfig(docName, this._ydoc);
1371
+ }
1372
+ else {
1373
+ // It's a factory with a create method
1374
+ provider = providerConfig.create(docName, this._ydoc);
1375
+ }
1376
+ this._providers.push(provider);
1377
+ }
1378
+ // Set up undo/redo manager for this workspace
1379
+ this._undoManager = new UndoManager([this._objectsMap], {
1380
+ captureTimeout: 200,
1381
+ trackedOrigins: new Set(['local', 'temporary']),
1382
+ ignoreRemoteMapChanges: true,
1376
1383
  });
1377
- }
1378
- async batch(actions) {
1379
- if (!this.db) {
1380
- throw new Error('Database is not open.');
1381
- }
1382
- const storeNames = await this.extractStoreNamesFromActions(actions);
1383
- if (this.isLoggingEnabled) {
1384
- console.info('[IndexedDB] Starting batch transaction:', { storeNames });
1385
- }
1386
- return new Promise((resolve, reject) => {
1387
- const transaction = this.db.transaction(storeNames, 'readwrite');
1388
- const results = [];
1389
- const promises = [];
1390
- const tempDbInstance = {
1391
- add: (storeName, item) => this.add(storeName, item),
1392
- get: (storeName, key) => this.get(storeName, key),
1393
- getAll: (storeName) => this.getAll(storeName),
1394
- update: (storeName, item) => this.update(storeName, item),
1395
- delete: (storeName, key) => this.delete(storeName, key),
1396
- deleteByRange: (storeName, range) => this.deleteByRange(storeName, range),
1397
- getAllByRange: (storeName, range) => this.getAllByRange(storeName, range),
1398
- getAllByIndex: (storeName, indexName, query) => this.getAllByIndex(storeName, indexName, query),
1399
- executeTransaction: (storeName, mode, action) => {
1400
- return new Promise((resolveRequest, rejectRequest) => {
1401
- if (this.isLoggingEnabled) {
1402
- console.info('[IndexedDB] Executing batch action:', { storeName, mode });
1403
- }
1404
- const store = transaction.objectStore(storeName);
1405
- const request = action(store);
1406
- request.onsuccess = () => {
1407
- if (this.isLoggingEnabled) {
1408
- console.info('[IndexedDB] Batch action request successful:', { result: request.result });
1409
- }
1410
- resolveRequest(request.result);
1411
- };
1412
- request.onerror = () => {
1413
- console.error('[IndexedDB] Batch action request error:', request.error);
1414
- rejectRequest(request.error);
1415
- };
1416
- });
1417
- },
1418
- };
1419
- transaction.oncomplete = () => {
1420
- if (this.isLoggingEnabled) {
1421
- console.info('[IndexedDB] Batch transaction complete.');
1384
+ this._undoManager.on('stack-item-added', event => {
1385
+ if (event.type === 'undo') {
1386
+ // Track if this was a temporary item
1387
+ if (event.origin === 'temporary') {
1388
+ this._temporaryItemsCount++;
1422
1389
  }
1423
- Promise.all(promises).then(() => resolve(results));
1424
- };
1425
- transaction.onabort = () => {
1426
- console.error('[IndexedDB] Batch transaction aborted:', transaction.error);
1427
- reject(transaction.error ?? new Error('Transaction aborted'));
1428
- };
1429
- transaction.onerror = () => {
1430
- console.error('[IndexedDB] Batch transaction error:', transaction.error);
1431
- reject(transaction.error);
1432
- };
1433
- actions.forEach((action, index) => {
1434
- const promise = action(tempDbInstance)
1435
- .then(result => {
1436
- results[index] = result;
1437
- })
1438
- .catch(err => {
1439
- if (!transaction.error) {
1440
- transaction.abort();
1441
- }
1442
- reject(err);
1443
- });
1444
- promises.push(promise);
1445
- });
1390
+ console.log('Undo performed for workspace', workspaceId, this._undoManager.undoStack.length, this._undoManager.redoStack.length);
1391
+ }
1446
1392
  });
1447
- }
1448
- async extractStoreNamesFromActions(actions) {
1449
- const storeNamesSet = new Set();
1450
- const storeNameCollector = new Proxy(this, {
1451
- get: (target, prop) => {
1452
- if (['add', 'get', 'getAll', 'update', 'delete', 'deleteByRange', 'getAllByRange', 'getAllByIndex'].includes(prop)) {
1453
- return (storeName) => {
1454
- storeNamesSet.add(storeName);
1455
- return Promise.resolve();
1456
- };
1393
+ this._undoManager.on('stack-item-popped', event => {
1394
+ if (event.type === 'undo') {
1395
+ // Reduce temporary count when items are undone
1396
+ if (event.origin === 'temporary' && this._temporaryItemsCount > 0) {
1397
+ this._temporaryItemsCount--;
1457
1398
  }
1458
- return target[prop];
1459
- },
1399
+ console.log('Redo performed for workspace', workspaceId, this._undoManager.undoStack.length, this._undoManager.redoStack.length);
1400
+ }
1460
1401
  });
1461
- await Promise.all(actions.map(action => action(storeNameCollector)));
1462
- return Array.from(storeNamesSet);
1463
- }
1464
- }
1465
-
1466
- class UpdateViewportCommand extends KritzelBaseCommand {
1467
- currentViewport;
1468
- previousViewport;
1469
- constructor(core, initiator, previousViewport, skipHistory = false) {
1470
- super(core, initiator, skipHistory);
1471
- this.previousViewport = previousViewport;
1472
- this.currentViewport = {
1473
- scale: this._core.store.state.scale,
1474
- translateX: this._core.store.state.translateX,
1475
- translateY: this._core.store.state.translateY,
1476
- };
1477
- }
1478
- execute() {
1479
- this._core.store.state.scale = this.currentViewport.scale;
1480
- this._core.store.state.translateX = this.currentViewport.translateX;
1481
- this._core.store.state.translateY = this.currentViewport.translateY;
1482
- }
1483
- undo() {
1484
- this._core.store.state.scale = this.previousViewport.scale;
1485
- this._core.store.state.translateX = this.previousViewport.translateX;
1486
- this._core.store.state.translateY = this.previousViewport.translateY;
1487
- }
1488
- }
1489
-
1490
- class KritzelCircularBuffer {
1491
- buffer;
1492
- capacity;
1493
- head = 0;
1494
- tail = 0;
1495
- size = 0;
1496
- constructor(capacity) {
1497
- this.capacity = capacity;
1498
- this.buffer = new Array(capacity).fill(null);
1499
- }
1500
- add(item) {
1501
- this.buffer[this.head] = item;
1502
- this.head = (this.head + 1) % this.capacity;
1503
- if (this.size < this.capacity) {
1504
- this.size++;
1505
- }
1506
- else {
1507
- this.tail = (this.tail + 1) % this.capacity;
1508
- }
1509
- }
1510
- pop() {
1511
- if (this.size === 0) {
1512
- return null;
1402
+ // Observe changes to objects and sync with application state
1403
+ this._objectsMap.observe(event => {
1404
+ this.handleObjectsChange(event);
1405
+ });
1406
+ // Connect all providers in parallel
1407
+ await Promise.all(this._providers.map(p => p.connect()));
1408
+ this._isReady = true;
1409
+ // Load objects from Yjs
1410
+ this.loadFromYjs();
1411
+ }
1412
+ handleObjectsChange(event) {
1413
+ // Skip Map updates for local changes (already done), but still trigger re-render
1414
+ // 'temporary' is also a local change that shouldn't be re-deserialized
1415
+ if (event.transaction.origin === 'local' || event.transaction.origin === 'temporary') {
1416
+ this._core?.rerender();
1417
+ return;
1513
1418
  }
1514
- this.head = (this.head - 1 + this.capacity) % this.capacity;
1515
- const item = this.buffer[this.head];
1516
- this.buffer[this.head] = null;
1517
- this.size--;
1518
- return item;
1419
+ const changedKeys = Array.from(event.keysChanged);
1420
+ const objectsToUpdate = [];
1421
+ const selectionGroupsToUpdate = [];
1422
+ const objectsToDelete = [];
1423
+ changedKeys.forEach(key => {
1424
+ const change = event.changes.keys.get(key);
1425
+ if (change && change.action === 'delete') {
1426
+ objectsToDelete.push(key);
1427
+ }
1428
+ else {
1429
+ const serialized = this._objectsMap.get(key);
1430
+ if (serialized) {
1431
+ const object = this._reviver.revive(serialized);
1432
+ // Separate SelectionGroups to process them after regular objects
1433
+ if (object instanceof KritzelSelectionGroup) {
1434
+ selectionGroupsToUpdate.push(object);
1435
+ }
1436
+ else {
1437
+ objectsToUpdate.push(object);
1438
+ }
1439
+ }
1440
+ }
1441
+ });
1442
+ // Delete objects from local map
1443
+ objectsToDelete.forEach(objectId => {
1444
+ this.map.delete(objectId);
1445
+ });
1446
+ // First, update or insert regular objects
1447
+ objectsToUpdate.forEach(object => {
1448
+ this.map.set(object.id, object);
1449
+ });
1450
+ // Then, update or insert SelectionGroups
1451
+ selectionGroupsToUpdate.forEach(object => {
1452
+ this.map.set(object.id, object);
1453
+ });
1454
+ this._core?.rerender();
1519
1455
  }
1520
- peek() {
1521
- if (this.size === 0) {
1522
- return null;
1456
+ transaction(callback) {
1457
+ if (this._ydoc) {
1458
+ this._ydoc.transact(callback, 'local');
1523
1459
  }
1524
- const lastIndex = (this.head - 1 + this.capacity) % this.capacity;
1525
- return this.buffer[lastIndex];
1526
- }
1527
- isEmpty() {
1528
- return this.size === 0;
1529
- }
1530
- clear() {
1531
- this.buffer.fill(null);
1532
- this.head = 0;
1533
- this.tail = 0;
1534
- this.size = 0;
1535
- }
1536
- }
1537
-
1538
- class KritzelHistory {
1539
- _core;
1540
- undoStack;
1541
- redoStack;
1542
- constructor(core) {
1543
- this._core = core;
1544
- this.undoStack = new KritzelCircularBuffer(this._core.store.state.historyBufferSize);
1545
- this.redoStack = new KritzelCircularBuffer(this._core.store.state.historyBufferSize);
1546
1460
  }
1547
- reset() {
1548
- this.undoStack.clear();
1549
- this.redoStack.clear();
1550
- this._core.commandManager.previousViewport = {
1551
- scale: this._core.store.state.scale,
1552
- scaleStep: this._core.store.state.scaleStep,
1553
- translateX: this._core.store.state.translateX,
1554
- translateY: this._core.store.state.translateY
1555
- };
1556
- }
1557
- undo() {
1558
- if (this._core.store.state.hasViewportChanged) {
1559
- const command = new UpdateViewportCommand(this._core, this, this._core.commandManager.previousViewport);
1560
- command.undo();
1561
- this._core.store.state.hasViewportChanged = false;
1562
- this._core.rerender();
1461
+ loadFromYjs() {
1462
+ if (!this._objectsMap || !this._reviver) {
1563
1463
  return;
1564
1464
  }
1565
- const command = this.undoStack.pop();
1566
- if (command) {
1567
- command.undo();
1568
- if (this._core.store.state.debugInfo.logCommands)
1569
- console.info('undo', command);
1570
- this.redoStack.add(command);
1571
- }
1572
- this._core.store.state.copiedObjects = null;
1573
- this._core.rerender();
1574
- }
1575
- redo() {
1576
- const command = this.redoStack.pop();
1577
- if (command) {
1578
- command.execute();
1579
- if (this._core.store.state.debugInfo.logCommands)
1580
- console.info('redo', command);
1581
- this.undoStack.add(command);
1582
- }
1583
- this._core.rerender();
1584
- }
1585
- }
1586
-
1587
- class KritzelObjectMap {
1588
- map;
1589
- constructor() {
1590
- this.map = new Map();
1465
+ this.map.clear();
1466
+ this._objectsMap.forEach((serialized, key) => {
1467
+ const object = this._reviver.revive(serialized);
1468
+ this.map.set(key, object);
1469
+ });
1591
1470
  }
1592
1471
  reset() {
1593
1472
  this.map.clear();
1473
+ this._ydoc.transact(() => {
1474
+ this._objectsMap.clear();
1475
+ }, 'local');
1594
1476
  }
1595
1477
  insert(object) {
1596
1478
  if (!object.id) {
1597
1479
  return false;
1598
1480
  }
1599
1481
  this.map.set(object.id, object);
1482
+ if (this._objectsMap && this.isPersistable(object)) {
1483
+ const serialized = object.serialize();
1484
+ this._ydoc.transact(() => {
1485
+ this._objectsMap.set(object.id, serialized);
1486
+ }, 'local');
1487
+ }
1600
1488
  return true;
1601
1489
  }
1602
- update(object) {
1490
+ update(object, options = {}) {
1603
1491
  if (!object.id || !this.map.has(object.id)) {
1604
1492
  return false;
1605
1493
  }
1606
1494
  this.map.set(object.id, object);
1495
+ if (this._objectsMap && this.isPersistable(object)) {
1496
+ const serialized = object.serialize();
1497
+ const origin = options.temporary ? 'temporary' : 'local';
1498
+ this._ydoc.transact(() => {
1499
+ this._objectsMap.set(object.id, serialized);
1500
+ }, origin);
1501
+ }
1607
1502
  return true;
1608
1503
  }
1609
1504
  remove(predicate) {
1610
1505
  for (const [id, object] of this.map) {
1611
1506
  if (predicate(object)) {
1612
1507
  this.map.delete(id);
1508
+ if (this._objectsMap && this.isPersistable(object)) {
1509
+ this._ydoc.transact(() => {
1510
+ this._objectsMap.delete(id);
1511
+ }, 'local');
1512
+ }
1613
1513
  }
1614
1514
  }
1615
1515
  }
@@ -1625,6 +1525,98 @@ class KritzelObjectMap {
1625
1525
  allObjects() {
1626
1526
  return Array.from(this.map.values());
1627
1527
  }
1528
+ isPersistable(object) {
1529
+ if (object instanceof KritzelSelectionBox) {
1530
+ return false;
1531
+ }
1532
+ return true;
1533
+ }
1534
+ undo() {
1535
+ if (this._undoManager && this._undoManager.canUndo()) {
1536
+ this._undoManager.undo();
1537
+ }
1538
+ }
1539
+ redo() {
1540
+ if (this._undoManager && this._undoManager.canRedo()) {
1541
+ this._undoManager.redo();
1542
+ }
1543
+ }
1544
+ canUndo() {
1545
+ return this._undoManager ? this._undoManager.canUndo() : false;
1546
+ }
1547
+ canRedo() {
1548
+ return this._undoManager ? this._undoManager.canRedo() : false;
1549
+ }
1550
+ clearHistory() {
1551
+ if (this._undoManager) {
1552
+ this._undoManager.clear();
1553
+ this._temporaryItemsCount = 0;
1554
+ }
1555
+ }
1556
+ /**
1557
+ * Consolidates all temporary items in the undo stack into a single undo item.
1558
+ * Call this when you want to merge multiple temporary changes (e.g., keystrokes) into one.
1559
+ */
1560
+ consolidateTemporaryItems() {
1561
+ if (!this._undoManager || this._temporaryItemsCount === 0) {
1562
+ return;
1563
+ }
1564
+ // Get current stack length
1565
+ const stackLength = this._undoManager.undoStack.length;
1566
+ if (stackLength === 0) {
1567
+ this._temporaryItemsCount = 0;
1568
+ return;
1569
+ }
1570
+ // Stop tracking temporarily
1571
+ this._undoManager.stopCapturing();
1572
+ // The temporary items should be at the end of the stack
1573
+ // We'll need to undo them all, then redo as a single transaction
1574
+ const itemsToConsolidate = Math.min(this._temporaryItemsCount, stackLength);
1575
+ if (itemsToConsolidate > 1) {
1576
+ // Undo all temporary items
1577
+ for (let i = 0; i < itemsToConsolidate; i++) {
1578
+ if (this._undoManager.canUndo()) {
1579
+ this._undoManager.undo();
1580
+ }
1581
+ }
1582
+ // Now redo them all as a single 'local' transaction
1583
+ // This will consolidate them into one undo item
1584
+ this._ydoc.transact(() => {
1585
+ for (let i = itemsToConsolidate - 1; i >= 0; i--) {
1586
+ if (this._undoManager.canRedo()) {
1587
+ this._undoManager.redo();
1588
+ }
1589
+ }
1590
+ }, 'local');
1591
+ }
1592
+ this._temporaryItemsCount = 0;
1593
+ }
1594
+ /**
1595
+ * Removes all temporary items from the undo stack without consolidating them.
1596
+ * Use this to discard temporary changes completely.
1597
+ */
1598
+ clearTemporaryItems() {
1599
+ if (!this._undoManager || this._temporaryItemsCount === 0) {
1600
+ return;
1601
+ }
1602
+ const stackLength = this._undoManager.undoStack.length;
1603
+ const itemsToRemove = Math.min(this._temporaryItemsCount, stackLength);
1604
+ // Remove items from the end of the stack
1605
+ for (let i = 0; i < itemsToRemove; i++) {
1606
+ if (this._undoManager.undoStack.length > 0) {
1607
+ this._undoManager.undoStack.pop();
1608
+ }
1609
+ }
1610
+ this._temporaryItemsCount = 0;
1611
+ }
1612
+ destroy() {
1613
+ this._providers.forEach(p => p.destroy());
1614
+ this._providers = [];
1615
+ if (this._ydoc) {
1616
+ this._ydoc.destroy();
1617
+ }
1618
+ this.map.clear();
1619
+ }
1628
1620
  }
1629
1621
 
1630
1622
  class KritzelStore {
@@ -1634,17 +1626,33 @@ class KritzelStore {
1634
1626
  return this._state;
1635
1627
  }
1636
1628
  get currentZIndex() {
1637
- return Math.max(0, ...this._state.objectsMap.filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KrtizelSelectionBox)).map(o => o.zIndex)) + 1;
1629
+ return Math.max(0, ...this._state.objectsMap.filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox)).map(o => o.zIndex)) + 1;
1638
1630
  }
1639
1631
  get allObjects() {
1640
1632
  return this._state.objectsMap.allObjects();
1641
1633
  }
1642
1634
  get allNonSelectionObjects() {
1643
- return this._state.objectsMap.allObjects().filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KrtizelSelectionBox));
1635
+ return this._state.objectsMap.allObjects().filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox));
1644
1636
  }
1645
1637
  get selectedObjects() {
1646
1638
  return this.allObjects.filter(o => !(o instanceof KritzelSelectionGroup)).filter(o => o.isSelected);
1647
1639
  }
1640
+ get selectionBox() {
1641
+ const selectionBoxes = this._state.objectsMap.filter(o => o instanceof KritzelSelectionBox);
1642
+ return selectionBoxes.length > 0 ? selectionBoxes[0] : null;
1643
+ }
1644
+ get selectionGroup() {
1645
+ const selectionGroups = this._state.objectsMap.filter(o => o instanceof KritzelSelectionGroup);
1646
+ return selectionGroups.length > 0 ? selectionGroups[0] : null;
1647
+ }
1648
+ get activeText() {
1649
+ const activeTexts = this._state.objectsMap.filter(o => o instanceof KritzelText && o.isEditing);
1650
+ return activeTexts.length > 0 ? activeTexts[0] : null;
1651
+ }
1652
+ get currentPath() {
1653
+ const drawingPaths = this._state.objectsMap.filter(o => o instanceof KritzelPath && o.isCompleted === false);
1654
+ return drawingPaths.length > 0 ? drawingPaths[0] : null;
1655
+ }
1648
1656
  get offsetX() {
1649
1657
  return this._state.host.getBoundingClientRect().left;
1650
1658
  }
@@ -1678,203 +1686,124 @@ class KritzelStore {
1678
1686
  }
1679
1687
  }
1680
1688
 
1681
- class KritzelCommandManager {
1682
- _core;
1683
- _history;
1684
- previousViewport;
1685
- constructor(core) {
1686
- this._core = core;
1687
- this._history = this._core.history;
1688
- this.previousViewport = {
1689
- scale: this._core.store.state.scale,
1690
- scaleStep: this._core.store.state.scaleStep,
1691
- translateX: this._core.store.state.translateX,
1692
- translateY: this._core.store.state.translateY,
1693
- };
1694
- }
1695
- executeCommand(command) {
1696
- if (this._core.store.state.hasViewportChanged) {
1697
- this.addUpdateViewportCommand();
1698
- }
1699
- command.execute();
1700
- if (this.isSkipped(command) === false) {
1701
- if (this._core.store.state.debugInfo.logCommands) {
1702
- console.log('execute', command);
1703
- }
1704
- this._history.undoStack.add(command);
1705
- if (this._history.redoStack.isEmpty() === false) {
1706
- this._history.redoStack.clear();
1707
- }
1708
- }
1709
- this._core.rerender();
1710
- }
1711
- isSkipped(command) {
1712
- return command.skipHistory === true;
1713
- }
1714
- addUpdateViewportCommand() {
1715
- const command = new UpdateViewportCommand(this._core, this, this.previousViewport);
1716
- command.execute();
1717
- this._history.undoStack.add(command);
1718
- if (this._history.redoStack.isEmpty() === false) {
1719
- this._history.redoStack.clear();
1720
- }
1721
- this._core.store.state.hasViewportChanged = false;
1722
- this.previousViewport = {
1723
- scale: this._core.store.state.scale,
1724
- scaleStep: this._core.store.state.scaleStep,
1725
- translateX: this._core.store.state.translateX,
1726
- translateY: this._core.store.state.translateY,
1727
- };
1728
- }
1729
- }
1730
-
1731
1689
  class KritzelCore {
1732
1690
  _kritzelEngine;
1733
1691
  _store;
1734
- _history;
1735
- _commandManager;
1736
- _database;
1692
+ _syncConfig;
1693
+ _appStateMap;
1737
1694
  get engine() {
1738
1695
  return this._kritzelEngine;
1739
1696
  }
1740
- get history() {
1741
- return this._history;
1742
- }
1743
- get commandManager() {
1744
- return this._commandManager;
1745
- }
1746
- get database() {
1747
- return this._database;
1748
- }
1749
1697
  get store() {
1750
1698
  return this._store;
1751
1699
  }
1700
+ get appStateMap() {
1701
+ return this._appStateMap;
1702
+ }
1752
1703
  constructor(kritzelEngine) {
1753
1704
  this._kritzelEngine = kritzelEngine;
1754
- this._store = new KritzelStore(DEFAULT_ENGINE_STATE);
1755
- this._history = new KritzelHistory(this);
1756
- this._commandManager = new KritzelCommandManager(this);
1757
- this._database = new KritzelDatabase('kritzelDB', 1, this._store.state.debugInfo.logDatabase);
1758
- }
1759
- async initializeDatabase() {
1760
- await this._database.open([
1761
- {
1762
- name: 'objects',
1763
- options: { keyPath: ['workspaceId', 'id'] },
1764
- },
1765
- { name: 'workspaces', options: { keyPath: 'id' } },
1766
- ]);
1767
- this.rerender();
1705
+ this._store = new KritzelStore(DEFAULT_ENGINE_CONFIG);
1706
+ this._appStateMap = new KritzelAppStateMap();
1768
1707
  }
1769
- async initializeWorkspace(workspace) {
1770
- const workspaces = await this.getWorkspaces();
1771
- const mostRecentWorkspace = [...workspaces].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];
1772
- const fallbackWorkspace = new KritzelWorkspace(ObjectHelper.generateUUID(), 'New Workspace');
1773
- const candidateWorkspace = workspace ?? mostRecentWorkspace ?? fallbackWorkspace;
1774
- const existingWorkspace = await this.getWorkspace(candidateWorkspace.id);
1775
- if (existingWorkspace) {
1776
- this._store.state.activeWorkspace = existingWorkspace;
1777
- await this.updateWorkspace(this._store.state.activeWorkspace);
1778
- }
1779
- else {
1780
- this._store.state.activeWorkspace = candidateWorkspace;
1781
- await this.createWorkspace(this._store.state.activeWorkspace);
1782
- }
1783
- this._store.state.workspaces = await this.getWorkspaces();
1784
- const viewport = this._store.state.activeWorkspace.viewport ?? { translateX: 0, translateY: 0, scale: 1 };
1785
- this._store.state.translateX = viewport.translateX ?? 0;
1786
- this._store.state.translateY = viewport.translateY ?? 0;
1787
- this._store.state.scale = viewport.scale ?? 1;
1788
- await this.initializeWorkspaceObjects(this._store.state.activeWorkspace.id);
1789
- }
1790
- async initializeWorkspaceObjects(workspaceId) {
1791
- this._store.state.objectsMap.reset();
1792
- this._history.reset();
1793
- const objectsFromDb = await this._database.getAllByRange('objects', IDBKeyRange.bound([workspaceId], [workspaceId, '\uffff']));
1794
- const reviver = new KritzelReviver(this);
1795
- objectsFromDb.forEach(element => {
1796
- const revivedObject = reviver.revive(element);
1797
- this._store.state.objectsMap.insert(revivedObject);
1798
- });
1799
- this.rerender();
1708
+ setSyncConfig(config) {
1709
+ this._syncConfig = config;
1800
1710
  }
1801
- async updateWorkspaceViewport(translateX, translateY, scale) {
1802
- const activeWorkspace = this._store.state.activeWorkspace;
1803
- if (!activeWorkspace) {
1804
- throw new Error('Workspace not initialized');
1805
- }
1806
- activeWorkspace.viewport = { translateX, translateY, scale };
1807
- activeWorkspace.updatedAt = new Date();
1808
- await this._database.update('workspaces', activeWorkspace);
1711
+ async initializeYjs() {
1712
+ await this._appStateMap.initialize(this, this._syncConfig);
1809
1713
  }
1810
- async addObjectToDatabase(object) {
1811
- if (!this._database) {
1812
- throw new Error('Database not initialized');
1813
- }
1814
- const activeWorkspace = this._store.state.activeWorkspace;
1815
- if (!activeWorkspace) {
1816
- throw new Error('Workspace not initialized');
1817
- }
1818
- activeWorkspace.updatedAt = new Date();
1819
- await this._database.batch([db => db.add('objects', object), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1820
- console.error('Error adding object to database:', err);
1821
- });
1714
+ /**
1715
+ * Load all workspaces from app state map
1716
+ */
1717
+ loadWorkspacesFromAppState() {
1718
+ return this._appStateMap.allWorkspaces();
1822
1719
  }
1823
- async updateObjectInDatabase(object) {
1824
- if (!this._database) {
1825
- throw new Error('Database not initialized');
1720
+ /**
1721
+ * Save a workspace to app state map
1722
+ */
1723
+ saveWorkspaceToAppState(workspace) {
1724
+ if (this._appStateMap.has(workspace.id)) {
1725
+ this._appStateMap.update(workspace);
1826
1726
  }
1827
- const activeWorkspace = this._store.state.activeWorkspace;
1828
- if (!activeWorkspace) {
1829
- throw new Error('Workspace not initialized');
1727
+ else {
1728
+ this._appStateMap.insert(workspace);
1830
1729
  }
1831
- activeWorkspace.updatedAt = new Date();
1832
- await this._database.batch([db => db.update('objects', object), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1833
- console.error('Error updating object in database:', err);
1834
- });
1835
1730
  }
1836
- async deleteObjectFromDatabase(objectId) {
1837
- if (!this._database) {
1838
- throw new Error('Database not initialized');
1731
+ /**
1732
+ * Delete a workspace from app state map
1733
+ */
1734
+ deleteWorkspaceFromAppState(workspaceId) {
1735
+ this._appStateMap.remove(w => w.id === workspaceId);
1736
+ }
1737
+ async initializeWorkspace(workspace) {
1738
+ // Load all workspaces from app state map
1739
+ const workspaces = this.loadWorkspacesFromAppState();
1740
+ // Find most recently updated workspace or use provided/fallback
1741
+ const mostRecentWorkspace = workspaces.length > 0 ? [...workspaces].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0] : null;
1742
+ let activeWorkspace;
1743
+ if (workspace) {
1744
+ // Use provided workspace
1745
+ activeWorkspace = workspace;
1746
+ const existing = workspaces.find(w => w.id === workspace.id);
1747
+ if (!existing) {
1748
+ // New workspace, save it
1749
+ activeWorkspace._core = this;
1750
+ this.saveWorkspaceToAppState(activeWorkspace);
1751
+ }
1839
1752
  }
1840
- const activeWorkspace = this._store.state.activeWorkspace;
1841
- if (!activeWorkspace) {
1842
- throw new Error('Workspace not initialized');
1753
+ else if (mostRecentWorkspace) {
1754
+ // Use most recent workspace
1755
+ activeWorkspace = mostRecentWorkspace;
1843
1756
  }
1844
- activeWorkspace.updatedAt = new Date();
1845
- await this._database.batch([db => db.delete('objects', [activeWorkspace.id, objectId]), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1846
- console.error('Error deleting object from database:', err);
1847
- });
1757
+ else {
1758
+ // Create fallback workspace
1759
+ activeWorkspace = new KritzelWorkspace(ObjectHelper.generateUUID(), 'New Workspace');
1760
+ activeWorkspace._core = this;
1761
+ this.saveWorkspaceToAppState(activeWorkspace);
1762
+ }
1763
+ // Destroy old ObjectMap if switching workspaces
1764
+ if (this._store.state.objectsMap && this._store.state.objectsMap.isReady) {
1765
+ this._store.state.objectsMap.destroy();
1766
+ }
1767
+ // Set active workspace
1768
+ this._store.state.activeWorkspace = activeWorkspace;
1769
+ this._store.state.workspaces = this.loadWorkspacesFromAppState();
1770
+ // Set viewport from workspace
1771
+ const viewport = activeWorkspace.viewport ?? { translateX: 0, translateY: 0, scale: 1 };
1772
+ this._store.state.translateX = viewport.translateX ?? 0;
1773
+ this._store.state.translateY = viewport.translateY ?? 0;
1774
+ this._store.state.scale = viewport.scale ?? 1;
1775
+ // Create new ObjectMap with its own Y.Doc for this workspace
1776
+ const objectsMap = new KritzelObjectMap();
1777
+ await objectsMap.initialize(this, activeWorkspace.id, this._syncConfig);
1778
+ this._store.state.objectsMap = objectsMap;
1779
+ this.rerender();
1848
1780
  }
1849
- async getWorkspace(id) {
1850
- if (!this._database) {
1851
- throw new Error('Database not initialized');
1781
+ rerender() {
1782
+ if (this._kritzelEngine) {
1783
+ this._kritzelEngine.forceUpdate++;
1852
1784
  }
1853
- const reviver = new KritzelReviver(this);
1854
- return this._database.get('workspaces', id).then(rawWorkspace => (rawWorkspace ? reviver.revive(rawWorkspace) : null));
1855
1785
  }
1856
- async getWorkspaces() {
1857
- if (!this._database) {
1858
- throw new Error('Database not initialized');
1786
+ findObjectById(id) {
1787
+ for (const object of this._store.allObjects) {
1788
+ if (object.id === id) {
1789
+ return object;
1790
+ }
1859
1791
  }
1860
- const reviver = new KritzelReviver(this);
1861
- return this._database.getAll('workspaces').then(rawWorkspaces => rawWorkspaces.map(ws => reviver.revive(ws)));
1792
+ return null;
1862
1793
  }
1863
- async createWorkspace(workspace) {
1864
- if (!this._database) {
1865
- throw new Error('Database not initialized');
1866
- }
1794
+ getWorkspaces() {
1795
+ return this.loadWorkspacesFromAppState();
1796
+ }
1797
+ createWorkspace(workspace) {
1798
+ workspace._core = this;
1867
1799
  workspace.createdAt = new Date();
1868
1800
  workspace.updatedAt = new Date();
1869
- await this._database.add('workspaces', workspace);
1870
- this._store.state.workspaces.push(workspace);
1801
+ this.saveWorkspaceToAppState(workspace);
1802
+ this._store.state.workspaces = this.loadWorkspacesFromAppState();
1871
1803
  }
1872
- async updateWorkspace(workspace) {
1873
- if (!this._database) {
1874
- throw new Error('Database not initialized');
1875
- }
1804
+ updateWorkspace(workspace) {
1876
1805
  workspace.updatedAt = new Date();
1877
- await this._database.update('workspaces', workspace);
1806
+ this.saveWorkspaceToAppState(workspace);
1878
1807
  const workspaces = this._store.state.workspaces;
1879
1808
  const index = workspaces.findIndex(w => w.id === workspace.id);
1880
1809
  if (index !== -1) {
@@ -1882,126 +1811,216 @@ class KritzelCore {
1882
1811
  this._store.state.workspaces = workspaces;
1883
1812
  }
1884
1813
  }
1885
- async deleteWorkspace(workspace) {
1886
- if (!this._database) {
1887
- throw new Error('Database not initialized');
1814
+ deleteWorkspace(workspace) {
1815
+ // If deleting the active workspace, need to handle ObjectMap cleanup
1816
+ if (this._store.state.activeWorkspace?.id === workspace.id) {
1817
+ this._store.state.objectsMap?.destroy();
1888
1818
  }
1889
- const objectRange = IDBKeyRange.bound([workspace.id], [workspace.id, '\uffff']);
1890
- await this._database.deleteByRange('objects', objectRange);
1891
- await this._database.delete('workspaces', workspace.id);
1892
- this._store.state.workspaces = this._store.state.workspaces.filter(ws => ws.id !== workspace.id);
1819
+ this.deleteWorkspaceFromAppState(workspace.id);
1820
+ this._store.state.workspaces = this.loadWorkspacesFromAppState();
1821
+ // Also delete the workspace's IndexedDB database
1822
+ const dbName = `kritzel-workspace-${workspace.id}`;
1823
+ window.indexedDB.deleteDatabase(dbName);
1893
1824
  }
1894
- rerender() {
1895
- if (this._kritzelEngine) {
1896
- this._kritzelEngine.forceUpdate++;
1825
+ updateWorkspaceViewport(translateX, translateY, scale) {
1826
+ const activeWorkspace = this._store.state.activeWorkspace;
1827
+ if (!activeWorkspace) {
1828
+ return;
1897
1829
  }
1830
+ activeWorkspace.viewport = { translateX, translateY, scale };
1831
+ activeWorkspace.updatedAt = new Date();
1832
+ this.saveWorkspaceToAppState(activeWorkspace);
1898
1833
  }
1899
- findObjectById(id) {
1900
- for (const object of this._store.allObjects) {
1901
- if (object.id === id) {
1902
- return object;
1834
+ addObject(object) {
1835
+ this._store.state.objectsMap.insert(object);
1836
+ }
1837
+ removeObject(object) {
1838
+ object.isMounted = false;
1839
+ this._store.state.objectsMap.remove(o => o.id === object.id);
1840
+ }
1841
+ updateObject(object, updatedProperties) {
1842
+ for (const key in updatedProperties) {
1843
+ if (updatedProperties.hasOwnProperty(key)) {
1844
+ object[key] = updatedProperties[key];
1903
1845
  }
1904
1846
  }
1905
- return null;
1847
+ this._store.state.objectsMap.update(object);
1906
1848
  }
1907
- deselectAllObjects() {
1908
- if (this._store.state.selectionGroup) {
1909
- this.commandManager.executeCommand(new RemoveSelectionGroupCommand(this, this, true));
1849
+ addSelectionGroup(selectionGroup) {
1850
+ this.removeSelectionGroup();
1851
+ this.removeSelectionBox();
1852
+ this._store.state.objectsMap.insert(selectionGroup);
1853
+ }
1854
+ removeSelectionGroup() {
1855
+ const selectionGroup = this._store.selectionGroup;
1856
+ if (selectionGroup) {
1857
+ this._store.state.objectsMap.remove(object => object.id === selectionGroup.id);
1858
+ }
1859
+ }
1860
+ removeSelectionBox() {
1861
+ const selectionBox = this._store.selectionBox;
1862
+ if (selectionBox) {
1863
+ this._store.state.objectsMap.remove(object => object.id === selectionBox.id);
1910
1864
  }
1911
1865
  }
1866
+ deselectAllObjects() {
1867
+ this.removeSelectionGroup();
1868
+ this.rerender();
1869
+ }
1912
1870
  delete() {
1913
- if (!this._store.state.selectionGroup) {
1871
+ const selectionGroup = this._store.selectionGroup;
1872
+ if (!selectionGroup) {
1914
1873
  return;
1915
1874
  }
1916
- const deleteSelectedObjectsCommand = this._store.state.selectionGroup.objects.map(obj => new RemoveObjectCommand(this, this._store.state.selectionGroup, obj));
1917
- const removeSelectionGroupCommand = new RemoveSelectionGroupCommand(this, this._store.state.selectionGroup);
1918
- const commands = [...deleteSelectedObjectsCommand, removeSelectionGroupCommand];
1919
- this.commandManager.executeCommand(new BatchCommand(this, this._store.state.selectionGroup, commands));
1875
+ selectionGroup.objects.forEach(obj => this.removeObject(obj));
1876
+ this.removeSelectionGroup();
1877
+ this.rerender();
1878
+ }
1879
+ undo() {
1880
+ this._store.state.objectsMap?.undo();
1920
1881
  }
1921
- deleteObject(id, skipHistory = false) {
1882
+ redo() {
1883
+ this._store.state.objectsMap?.redo();
1884
+ }
1885
+ deleteObject(id) {
1922
1886
  const object = this.findObjectById(id);
1923
1887
  if (object) {
1924
- const removeObjectCommand = new RemoveObjectCommand(this, this, object, skipHistory);
1925
- this.commandManager.executeCommand(removeObjectCommand);
1888
+ this.removeObject(object);
1889
+ this.rerender();
1926
1890
  }
1927
1891
  }
1928
1892
  copy() {
1929
- this._store.state.copiedObjects = this._store.state.selectionGroup.copy();
1893
+ const selectionGroup = this._store.selectionGroup;
1894
+ if (selectionGroup) {
1895
+ // Copy each object and store them in an array
1896
+ this._store.state.copiedObjects = selectionGroup.objects.sort((a, b) => a.zIndex - b.zIndex).map(obj => obj.copy());
1897
+ }
1930
1898
  }
1931
1899
  paste(x, y) {
1932
1900
  const copiedObjects = this._store.state.copiedObjects;
1933
- copiedObjects.isSelected = true;
1934
- this._store.state.copiedObjects = copiedObjects;
1935
- const adjustedX = x !== undefined ? x : this._store.state.copiedObjects.translateX + 25 / this._store.state.scale;
1936
- const adjustedY = y !== undefined ? y : this._store.state.copiedObjects.translateY + 25 / this._store.state.scale;
1937
- this._store.state.copiedObjects.updatePosition(adjustedX, adjustedY);
1938
- this._store.state.copiedObjects.updateZIndices(this._store.currentZIndex);
1901
+ if (!copiedObjects || copiedObjects.length === 0) {
1902
+ return;
1903
+ }
1939
1904
  const activeWorkspace = this._store.state.activeWorkspace;
1940
- if (this.store.state.copiedObjects.workspaceId !== activeWorkspace.id) {
1941
- this.store.state.copiedObjects.updateWorkspaceId(activeWorkspace.id);
1905
+ // Check if we're pasting from a different workspace
1906
+ const isDifferentWorkspace = copiedObjects.some(obj => obj.workspaceId !== activeWorkspace.id);
1907
+ // Calculate the bounding box of all copied objects
1908
+ const minX = Math.min(...copiedObjects.map(obj => obj.translateX));
1909
+ const minY = Math.min(...copiedObjects.map(obj => obj.translateY));
1910
+ // Determine the paste position
1911
+ let pasteX;
1912
+ let pasteY;
1913
+ if (x !== undefined && y !== undefined) {
1914
+ // Explicit position provided (e.g., right-click paste)
1915
+ pasteX = x;
1916
+ pasteY = y;
1917
+ }
1918
+ else if (isDifferentWorkspace) {
1919
+ // Pasting to different workspace without explicit position
1920
+ // Keep original position; will be centered by centerInViewport() later
1921
+ pasteX = minX;
1922
+ pasteY = minY;
1923
+ }
1924
+ else {
1925
+ // Same workspace paste: offset by 25 pixels from original position
1926
+ pasteX = minX + 25 / this._store.state.scale;
1927
+ pasteY = minY + 25 / this._store.state.scale;
1928
+ }
1929
+ // Calculate the offset to apply to all objects
1930
+ const offsetX = pasteX - minX;
1931
+ const offsetY = pasteY - minY;
1932
+ this.removeSelectionGroup();
1933
+ this.removeSelectionBox();
1934
+ // Create a new selection group for the pasted objects
1935
+ const selectionGroup = KritzelSelectionGroup.create(this);
1936
+ // First add all copied objects to the objectsMap with updated positions
1937
+ copiedObjects.forEach((obj, i) => {
1938
+ // Update workspace if pasting to a different workspace
1939
+ if (obj.workspaceId !== activeWorkspace.id) {
1940
+ obj.workspaceId = activeWorkspace.id;
1941
+ }
1942
+ // Update position
1943
+ obj.updatePosition(obj.translateX + offsetX, obj.translateY + offsetY);
1944
+ // Update z-index
1945
+ obj.zIndex = this._store.currentZIndex + i;
1946
+ // Add to objectsMap
1947
+ this.addObject(obj);
1948
+ // Add to selection group
1949
+ selectionGroup.addOrRemove(obj);
1950
+ });
1951
+ // Mark selection group as selected
1952
+ selectionGroup.isSelected = true;
1953
+ // Set rotation for single object
1954
+ if (copiedObjects.length === 1) {
1955
+ selectionGroup.rotation = copiedObjects[0].rotation;
1956
+ }
1957
+ // Add the selection group
1958
+ this.addSelectionGroup(selectionGroup);
1959
+ // Handle cross-workspace paste: center objects in viewport
1960
+ if (isDifferentWorkspace) {
1942
1961
  if (x !== undefined && y !== undefined) {
1943
- this._store.state.copiedObjects.updatePosition(x, y);
1962
+ // Position was explicitly provided, use it
1963
+ selectionGroup.updatePosition(x, y);
1944
1964
  }
1945
1965
  else {
1946
- this.store.state.copiedObjects.centerInViewport();
1966
+ // Center the selection group in the viewport
1967
+ selectionGroup.centerInViewport();
1947
1968
  }
1948
- this.engine.viewport.centerFitInViewport(copiedObjects);
1969
+ // Fit the viewport to show the pasted objects
1970
+ this.engine.viewport.centerFitInViewport(selectionGroup);
1949
1971
  }
1950
- const commands = [];
1951
- let previousSelectionGroup = null;
1952
- if (this._store.state.selectionGroup !== null) {
1953
- previousSelectionGroup = this._store.state.selectionGroup;
1954
- commands.push(new RemoveSelectionGroupCommand(this, this._store.state.selectionGroup));
1955
- }
1956
- const addCopiedObjectsCommands = this._store.state.copiedObjects.objects.map(obj => new AddObjectCommand(this, this, obj));
1957
- const addCopiedObjectsAsSelectionGroupCommand = new AddSelectionGroupCommand(this, this, this._store.state.copiedObjects, previousSelectionGroup);
1958
- commands.push(...addCopiedObjectsCommands, addCopiedObjectsAsSelectionGroupCommand);
1959
- this.commandManager.executeCommand(new BatchCommand(this, this, commands));
1960
1972
  this._store.state.isSelecting = false;
1961
- this._store.state.copiedObjects = this._store.state.selectionGroup.copy();
1973
+ // Update copiedObjects to the newly created objects for potential future pastes
1974
+ const newSelectionGroup = this._store.selectionGroup;
1975
+ if (newSelectionGroup) {
1976
+ this._store.state.copiedObjects = newSelectionGroup.objects.sort((a, b) => a.zIndex - b.zIndex).map(obj => obj.copy());
1977
+ }
1962
1978
  this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1979
+ this.rerender();
1963
1980
  }
1964
1981
  bringForward(object) {
1965
- const objects = object ? [object] : this._store.state.selectionGroup.objects;
1982
+ const selectionGroup = this._store.selectionGroup;
1983
+ const objects = object ? [object] : selectionGroup?.objects || [];
1966
1984
  const allNonSelectionObjectsWithoutCurrent = this._store.allNonSelectionObjects.filter(o => objects.findIndex(obj => obj.id === o.id) === -1);
1967
1985
  const max = allNonSelectionObjectsWithoutCurrent.length > 0 ? Math.max(...allNonSelectionObjectsWithoutCurrent.map(obj => obj.zIndex)) + 1 : 0;
1968
- const increaseZIndexCommands = objects.map(obj => {
1969
- if (obj.zIndex === max) {
1970
- return;
1986
+ objects.forEach(obj => {
1987
+ if (obj.zIndex !== max) {
1988
+ this.updateObject(obj, { zIndex: obj.zIndex + 1 });
1971
1989
  }
1972
- return new UpdateObjectCommand(this, this, obj, { zIndex: obj.zIndex + 1 });
1973
1990
  });
1974
- this.commandManager.executeCommand(new BatchCommand(this, this, increaseZIndexCommands));
1991
+ this.rerender();
1975
1992
  }
1976
1993
  sendBackward(object) {
1977
- const objects = object ? [object] : this._store.state.selectionGroup.objects;
1994
+ const selectionGroup = this._store.selectionGroup;
1995
+ const objects = object ? [object] : selectionGroup?.objects || [];
1978
1996
  const allNonSelectionObjectsWithoutCurrent = this._store.allNonSelectionObjects.filter(o => objects.findIndex(obj => obj.id === o.id) === -1);
1979
1997
  const min = allNonSelectionObjectsWithoutCurrent.length > 0 ? Math.min(...allNonSelectionObjectsWithoutCurrent.map(obj => obj.zIndex)) - 1 : 0;
1980
- const decreaseZIndexCommands = objects.map(obj => {
1981
- if (obj.zIndex === min) {
1982
- return;
1998
+ objects.forEach(obj => {
1999
+ if (obj.zIndex !== min) {
2000
+ this.updateObject(obj, { zIndex: obj.zIndex - 1 });
1983
2001
  }
1984
- return new UpdateObjectCommand(this, this, obj, { zIndex: obj.zIndex - 1 });
1985
2002
  });
1986
- this.commandManager.executeCommand(new BatchCommand(this, this, decreaseZIndexCommands));
2003
+ this.rerender();
1987
2004
  }
1988
2005
  bringToFront(object) {
1989
- const objects = object ? [object] : this._store.state.selectionGroup.objects;
2006
+ const selectionGroup = this._store.selectionGroup;
2007
+ const objects = object ? [object] : selectionGroup?.objects || [];
1990
2008
  const allNonSelectionObjectsWithoutCurrent = this._store.allNonSelectionObjects.filter(o => objects.findIndex(obj => obj.id === o.id) === -1);
1991
2009
  const max = Math.max(...allNonSelectionObjectsWithoutCurrent.map(obj => obj.zIndex)) + 1;
1992
- const increaseZIndexCommands = objects.map(obj => {
1993
- return new UpdateObjectCommand(this, this, obj, { zIndex: max });
2010
+ objects.forEach(obj => {
2011
+ this.updateObject(obj, { zIndex: max });
1994
2012
  });
1995
- this.commandManager.executeCommand(new BatchCommand(this, this, increaseZIndexCommands));
2013
+ this.rerender();
1996
2014
  }
1997
2015
  sendToBack(object) {
1998
- const objects = object ? [object] : this._store.state.selectionGroup.objects;
2016
+ const selectionGroup = this._store.selectionGroup;
2017
+ const objects = object ? [object] : selectionGroup?.objects || [];
1999
2018
  const allNonSelectionObjectsWithoutCurrent = this._store.allNonSelectionObjects.filter(o => objects.findIndex(obj => obj.id === o.id) === -1);
2000
2019
  const min = Math.min(...allNonSelectionObjectsWithoutCurrent.map(obj => obj.zIndex)) - 1;
2001
- const decreaseZIndexCommands = objects.map(obj => {
2002
- return new UpdateObjectCommand(this, this, obj, { zIndex: min });
2020
+ objects.forEach(obj => {
2021
+ this.updateObject(obj, { zIndex: min });
2003
2022
  });
2004
- this.commandManager.executeCommand(new BatchCommand(this, this, decreaseZIndexCommands));
2023
+ this.rerender();
2005
2024
  }
2006
2025
  selectObjects(objects) {
2007
2026
  if (objects.length === 0) {
@@ -2013,16 +2032,16 @@ class KritzelCore {
2013
2032
  selectionGroup.addOrRemove(obj);
2014
2033
  });
2015
2034
  selectionGroup.isSelected = true;
2016
- this._store.state.selectionBox = selectionGroup;
2017
2035
  if (objects.length === 1) {
2018
2036
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
2019
2037
  }
2020
- this.commandManager.executeCommand(new AddSelectionGroupCommand(this, this, selectionGroup));
2038
+ this.addSelectionGroup(selectionGroup);
2039
+ this.rerender();
2021
2040
  }
2022
2041
  selectAllObjectsInViewport() {
2023
2042
  const objectsInViewport = this._store.state.objectsMap
2024
2043
  .filter(o => o.isInViewport())
2025
- .filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KrtizelSelectionBox) && !(o instanceof KritzelContextMenu));
2044
+ .filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KritzelSelectionBox) && !(o instanceof KritzelContextMenu));
2026
2045
  if (objectsInViewport.length > 0) {
2027
2046
  const selectionGroup = KritzelSelectionGroup.create(this);
2028
2047
  objectsInViewport.forEach(obj => {
@@ -2034,30 +2053,29 @@ class KritzelCore {
2034
2053
  if (objectsInViewport.length === 1) {
2035
2054
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
2036
2055
  }
2037
- this.commandManager.executeCommand(new AddSelectionGroupCommand(this, this, selectionGroup));
2056
+ this.addSelectionGroup(selectionGroup);
2038
2057
  this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
2058
+ this.rerender();
2039
2059
  }
2040
2060
  }
2041
2061
  clearSelection() {
2042
- const command = new RemoveSelectionGroupCommand(this, this);
2043
- this.commandManager.executeCommand(command);
2044
- this._store.state.selectionGroup = null;
2045
- this._store.state.selectionBox = null;
2062
+ this.removeSelectionGroup();
2063
+ this._store.state.objectsMap.remove(o => o instanceof KritzelSelectionBox || o instanceof KritzelSelectionGroup);
2046
2064
  this._store.state.isSelecting = false;
2047
2065
  this._store.state.isResizeHandleSelected = false;
2048
2066
  this._store.state.isRotationHandleSelected = false;
2049
2067
  this.rerender();
2050
2068
  }
2051
2069
  resetActiveText() {
2052
- if (this._store.state.activeText) {
2053
- if (this._store.state.activeText.isEmpty) {
2054
- this.deleteObject(this._store.state.activeText.id, true);
2070
+ const activeText = this._store.activeText;
2071
+ if (activeText) {
2072
+ if (activeText.isEmpty) {
2073
+ this.deleteObject(activeText.id);
2055
2074
  }
2056
2075
  else {
2057
- this._store.state.activeText.save();
2076
+ activeText.save();
2058
2077
  }
2059
2078
  }
2060
- this._store.state.activeText = null;
2061
2079
  }
2062
2080
  getObjectFromPointerEvent(event, selector = '.object') {
2063
2081
  const shadowRoot = this._store.state.host?.shadowRoot;
@@ -2122,8 +2140,11 @@ const kritzelEngineCss = ":host{display:block;position:relative;height:100%;widt
2122
2140
  const KritzelEngine = class {
2123
2141
  get host() { return getElement(this); }
2124
2142
  workspace;
2143
+ syncConfig;
2125
2144
  onWorkspaceChange(newWorkspace) {
2126
- if (this.core.store.state.activeWorkspace !== newWorkspace) {
2145
+ const currentWorkspaceId = this.core.store.state.activeWorkspace?.id;
2146
+ const newWorkspaceId = newWorkspace?.id;
2147
+ if (currentWorkspaceId !== newWorkspaceId) {
2127
2148
  this.core.beforeWorkspaceChange();
2128
2149
  this.core.initializeWorkspace(newWorkspace);
2129
2150
  }
@@ -2286,15 +2307,15 @@ const KritzelEngine = class {
2286
2307
  this.core.sendToBack(object);
2287
2308
  }
2288
2309
  async undo() {
2289
- this.core.history.undo();
2310
+ this.core.undo();
2290
2311
  }
2291
2312
  async redo() {
2292
- this.core.history.redo();
2313
+ this.core.redo();
2293
2314
  }
2294
2315
  async hideContextMenu() {
2295
2316
  this.core.store.state.pointers.clear();
2296
2317
  this.core.store.state.isContextMenuVisible = false;
2297
- this.core.store.state.selectionBox = null;
2318
+ this.core.store.state.objectsMap.remove(o => o instanceof KritzelSelectionBox);
2298
2319
  this.core.store.state.isSelecting = false;
2299
2320
  this.core.store.state.isEnabled = true;
2300
2321
  this.core.rerender();
@@ -2309,24 +2330,25 @@ const KritzelEngine = class {
2309
2330
  object._core = this.core;
2310
2331
  object.scale = object.scale ? object.scale : this.core.store.state.scale;
2311
2332
  object.zIndex = this.core.store.currentZIndex;
2312
- const command = new AddObjectCommand(this.core, this, object);
2313
- this.core.commandManager.executeCommand(command);
2333
+ this.core.addObject(object);
2334
+ this.core.rerender();
2314
2335
  return object;
2315
2336
  }
2316
2337
  async updateObject(object, updatedProperties) {
2317
2338
  this.core.deselectAllObjects();
2318
- const command = new UpdateObjectCommand(this.core, this, object, updatedProperties);
2319
- this.core.commandManager.executeCommand(command);
2339
+ this.core.updateObject(object, updatedProperties);
2340
+ this.core.rerender();
2320
2341
  return object;
2321
2342
  }
2322
2343
  async removeObject(object) {
2323
2344
  this.core.deselectAllObjects();
2324
- const command = new RemoveObjectCommand(this.core, this, object);
2325
- this.core.commandManager.executeCommand(command);
2345
+ this.core.removeObject(object);
2346
+ this.core.rerender();
2326
2347
  return object;
2327
2348
  }
2328
2349
  async getSelectedObjects() {
2329
- return this.core.store.state.selectionGroup ? this.core.store.state.selectionGroup.objects : [];
2350
+ const selectionGroup = this.core.store.selectionGroup;
2351
+ return selectionGroup ? selectionGroup.objects : [];
2330
2352
  }
2331
2353
  async selectObjects(objects) {
2332
2354
  this.core.store.state.activeTool?.onDeactivate();
@@ -2345,15 +2367,14 @@ const KritzelEngine = class {
2345
2367
  }
2346
2368
  async centerObjectInViewport(object) {
2347
2369
  object.centerInViewport();
2348
- const command = new UpdateObjectCommand(this.core, this, object, object);
2349
- this.core.commandManager.executeCommand(command);
2370
+ this.core.updateObject(object, object);
2371
+ this.core.rerender();
2350
2372
  return object;
2351
2373
  }
2352
2374
  async getCopiedObjects() {
2353
- return this.core.store.state.copiedObjects?.objects || [];
2375
+ return this.core.store.state.copiedObjects || [];
2354
2376
  }
2355
2377
  async createWorkspace(workspace) {
2356
- workspace._core = this.core;
2357
2378
  await this.core.createWorkspace(workspace);
2358
2379
  this.workspacesChange.emit(this.core.store.state.workspaces);
2359
2380
  return workspace;
@@ -2367,7 +2388,7 @@ const KritzelEngine = class {
2367
2388
  this.workspacesChange.emit(this.core.store.state.workspaces);
2368
2389
  }
2369
2390
  async getWorkspaces() {
2370
- return this.core.getWorkspaces();
2391
+ return await this.core.getWorkspaces();
2371
2392
  }
2372
2393
  async getActiveWorkspace() {
2373
2394
  return this.core.store.state.activeWorkspace;
@@ -2381,7 +2402,7 @@ const KritzelEngine = class {
2381
2402
  return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.isSelecting;
2382
2403
  }
2383
2404
  get isSelectionActive() {
2384
- return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.selectionGroup !== null;
2405
+ return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.selectionGroup !== null;
2385
2406
  }
2386
2407
  constructor(hostRef) {
2387
2408
  registerInstance(this, hostRef);
@@ -2399,8 +2420,18 @@ const KritzelEngine = class {
2399
2420
  this.contextMenuHandler = new KritzelContextMenuHandler(this.core, this.globalContextMenuItems, this.objectContextMenuItems);
2400
2421
  this.keyHandler = new KritzelKeyHandler(this.core);
2401
2422
  this.viewport = new KritzelViewport(this.core, this.host);
2402
- await this.core.initializeDatabase();
2423
+ // Set sync configuration if provided
2424
+ if (this.syncConfig) {
2425
+ this.core.setSyncConfig(this.syncConfig);
2426
+ }
2427
+ // Initialize Yjs document and persistence layer
2428
+ await this.core.initializeYjs();
2429
+ // Initialize workspace (will load from Yjs if available)
2403
2430
  await this.core.initializeWorkspace(this.workspace);
2431
+ // Register callback for remote workspace changes
2432
+ this.core.appStateMap.onRemoteChange(() => {
2433
+ this.workspacesChange.emit(this.core.store.state.workspaces);
2434
+ });
2404
2435
  this._registerStateChangeListeners();
2405
2436
  if (this.core.store.state.isReady === false) {
2406
2437
  this.core.store.state.isReady = true;
@@ -2413,7 +2444,7 @@ const KritzelEngine = class {
2413
2444
  _handleActiveToolChange(activeTool) {
2414
2445
  if (!(activeTool instanceof KritzelSelectionTool)) {
2415
2446
  this.core.clearSelection();
2416
- this.core.store.state.selectionBox = null;
2447
+ this.core.store.state.objectsMap.remove(o => o instanceof KritzelSelectionBox);
2417
2448
  this.core.store.state.isSelecting = false;
2418
2449
  this.core.store.state.isResizeHandleSelected = false;
2419
2450
  this.core.store.state.isRotationHandleSelected = false;
@@ -2431,7 +2462,7 @@ const KritzelEngine = class {
2431
2462
  const baseHandleTouchSize = baseHandleSize * 2 < 14 ? 14 : baseHandleSize;
2432
2463
  const viewportCenterX = this.core.store.state.viewportWidth / 2 + this.core.store.state.translateX;
2433
2464
  const viewportCenterY = this.core.store.state.viewportHeight / 2 + this.core.store.state.translateY;
2434
- return (h(Host, { key: 'f7fc3c4c6a91ccdabb83832671e36ebf49ce56c0' }, h("div", { key: 'f6a2ce9e78a1d0e9ea0590035f5b8811f62c8633', class: "debug-panel", style: { display: this.core.store.state.debugInfo.showViewportInfo ? 'block' : 'none' } }, h("div", { key: '5752045746f275223bd42c16dd7e848adaaae9f2' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: 'd99595b135243a7b69a583be33f7b195908ec716' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: '7cecdccad47d3957370ea923f3dfbcd618b5d28e' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: '3a5ed989f2343eda92c7c81855c785dbf58fa770' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: 'b78074a29463276300ce498b2ddb328cef9026cd' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: 'd4c8dcfddfa1984eedf695d74f9401fc3284c60b' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: '566b6dc9afd904ee49e59587ed664e5f46decead' }, "Scale: ", this.core.store.state?.scale), h("div", { key: 'd3feb7a11727c4337ca75a26b3275a0b5d639961' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: '3991c34df53c7d6fd97c83b0d4b8c9fb438c88fc' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '5a4244b43871f96d08144483352064804f04e538' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: '197655c09e24d624ea4dcd312169aeb449ed57ce' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: 'a3e4a75a9853c8cee1485cbf8621377466babf90' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '171e0df3e1856e9fe8cd18be5c258c7472317453' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '66f5a56333dbac1da34e01f5ee1f577e1a964701' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: 'b869e07b76c2fa21ab5383788e81a40ffdad1b2c' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: 'd936326f8ea675e170d418f4e97a5d46057bc385' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: '8594489402204ae4a9cd1bc7795169dbfa2d633d' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: 'f7a254dc35bfe6d42c32d25d0f277b211d86b03f' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: '053ebd21504bfa3622e4b3e965e39f707c19794d' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'f330c65821326062874441355352134927760d61' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: 'f6c6902562f3e74afa3a0426e72b0c803977250b' }, "SelectedObjects: ", this.core.store.state.selectionGroup?.objects.length || 0), h("div", { key: '99a2d4280d5e79d7dd9a7a27d809e70f90eac38b' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")")), h("div", { key: 'dac21fa0ac9487b74c89ac7408e80d9fb89b4558', id: "origin", class: "origin", style: {
2465
+ return (h(Host, { key: 'b67ab4cce757661cb7b1bdc10035a3aea61cb24d' }, h("div", { key: '54160ed099438a59043ff4f5a774ee8c89a02153', class: "debug-panel", style: { display: this.core.store.state.debugInfo.showViewportInfo ? 'block' : 'none' } }, h("div", { key: '66e3a55bc530877256782073c4378b77d95ccfee' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: '841ea8bf317c3ef5ea35950f6bb2be9e6a8116cf' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: 'ec3a7797f01606308b54cf9b13bf7a3722c54287' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: '485dbc3021940fad42bae53a825206f27c76e604' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: '20fed3eb07d6599a175e43cd7e1708aa2a61cf31' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: '06522e742ac0d3d7c36b4b64307d695459b792e4' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: 'e745be888b5e1b36331359ca9fa1afc166333d13' }, "Scale: ", this.core.store.state?.scale), h("div", { key: 'f9074a0e3434aa0fb60d8d1fc1201815cb94fb7c' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: '3f96d5f90187cb0e042c4529351681b4799d9b38' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '6ca3d01c4aa817b0ccfd8bd1c5b65588006ecb5b' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: 'c2941fdce608c0a0396996aa3667f3fa18cc29a3' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: '0a99cd2e9767e4a9cb74af735a5eff5a86a9b6c4' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '0e749d3d2e131ab5984acbc7d9d91023b166ed45' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '0f102c2e704a18271e5b322814403c1cd0938356' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: 'd0c7eaa357268d4df97e50e85634e4be36e678ac' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: 'eb7b0d98fd3d4a13f152ded89a6649f408852575' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: 'bd9a16ff4537a9b6e73bff8d67222c4281a60fa0' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: 'fdeb2b546e421e9ce9d61e1527fcc79bd1cb217e' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: '9e7e93bcb5ce9c92ea9686140fc30851f6a4c66d' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'aaad9771c7286e352f99e2613616e8f023044926' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: 'fca0584ae7d2481b2ccdb71a24ad123a5efc6668' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", { key: 'a3f870ca59feb6698f2a9d4a106a694ac9b8cb3f' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")")), h("div", { key: '4616f1af54642b448806e7271b421f3d7e980dd1', id: "origin", class: "origin", style: {
2435
2466
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
2436
2467
  } }, this.core.store.state.objectsMap.allObjects()?.map(object => {
2437
2468
  return (h("div", { key: object.id, style: {
@@ -2488,7 +2519,7 @@ const KritzelEngine = class {
2488
2519
  } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && (h("div", { ref: el => object.mount(el), style: {
2489
2520
  width: '100%',
2490
2521
  height: '100%',
2491
- } })), KritzelClassHelper.isInstanceOf(object, 'KrtizelSelectionBox') && (h("div", { ref: el => object.mount(el), style: {
2522
+ } })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => object.mount(el), style: {
2492
2523
  width: '100%',
2493
2524
  height: '100%',
2494
2525
  backgroundColor: KritzelDevicesHelper.isFirefox() ? object.backgroundColor : 'transparent',
@@ -2536,15 +2567,7 @@ const KritzelEngine = class {
2536
2567
  fill: 'transparent',
2537
2568
  cursor: 'grab',
2538
2569
  }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("g", { style: { display: this.core.store.state.debugInfo.showObjectInfo ? 'block' : 'none', pointerEvents: 'none' } }, h("foreignObject", { x: object.totalWidth.toString(), y: "0", width: "400px", height: "160px", style: { minHeight: '0', minWidth: '0', display: object.isDebugInfoVisible ? 'block' : 'none' } }, h("div", { style: { width: '100%', height: '100%' } }, h("div", { style: { whitespace: 'nowrap' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap' } }, "translateY: ", object.translateY)))))));
2539
- }), h("svg", { key: "current-path", class: "object", xmlns: "http://www.w3.org/2000/svg", width: this.core.store.state.currentPath?.width, height: this.core.store.state.currentPath?.height, style: {
2540
- left: '0',
2541
- top: '0',
2542
- zIndex: this.core.store.state.currentPath?.zIndex.toString(),
2543
- position: 'absolute',
2544
- transform: this.core.store.state.currentPath?.transformationMatrix,
2545
- transformOrigin: 'top left',
2546
- overflow: 'visible',
2547
- }, viewBox: this.core.store.state.currentPath?.viewBox }, h("path", { key: 'eab427509417e6b80726436f726e6e1189b7c4fb', d: this.core.store.state.currentPath?.d, fill: this.core.store.state.currentPath?.fill, stroke: this.core.store.state.currentPath?.stroke }))), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '335cb455cfdb3e02dbc2ead1bf182d801b58e7bc', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.state.selectionGroup?.objects || [], style: {
2570
+ })), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '7907e01ea585125e8377d473d8d7d764b5e35609', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
2548
2571
  position: 'fixed',
2549
2572
  left: `${this.core.store.state.contextMenuX}px`,
2550
2573
  top: `${this.core.store.state.contextMenuY}px`,
@@ -2553,9 +2576,9 @@ const KritzelEngine = class {
2553
2576
  event.detail.action({
2554
2577
  x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
2555
2578
  y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
2556
- }, this.core.store.state.selectionGroup?.objects);
2579
+ }, this.core.store.selectionGroup?.objects);
2557
2580
  this.hideContextMenu();
2558
- }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: '8538b07072dd07a09d6256e28a98603ef5663089', core: this.core })));
2581
+ }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: '4cb3d1ce212b078514524e9edc7c22f6117e5160', core: this.core })));
2559
2582
  }
2560
2583
  static get watchers() { return {
2561
2584
  "workspace": ["onWorkspaceChange"],
@@ -2575,7 +2598,7 @@ const KritzelFont = class {
2575
2598
  size = 24;
2576
2599
  color = '#000000';
2577
2600
  render() {
2578
- return (h(Host, { key: '0a6f1d1326e9dde84a4122d79f75dc1c75ffe0fb' }, h("div", { key: '88a342d01c4150cd4fc5dacca23f7b9904edca52', class: "font-preview", style: {
2601
+ return (h(Host, { key: '0d0f0f75b64f579ca236950334fafde7f0ef2a38' }, h("div", { key: 'e71524879ded9727891bdd43f1a41ae5eef49175', class: "font-preview", style: {
2579
2602
  fontFamily: this.fontFamily,
2580
2603
  fontSize: `${this.size}px`,
2581
2604
  color: this.color
@@ -2622,7 +2645,7 @@ const KritzelFontFamily = class {
2622
2645
  label: option.label,
2623
2646
  style: { fontFamily: option.value },
2624
2647
  }));
2625
- return (h(Host, { key: '27d14ddb4a57b9cd7b936047b6ea6a9251a1ab27' }, h("kritzel-dropdown", { key: '20ea042c9a907dc1ac5e16a589a8856f87389e36', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: this.selectedFontFamily } }, h("button", { key: 'f63fed16477a327aadaeb54feefe35df1780e37d', class: "font-style-button", slot: "suffix" }, "B"), h("button", { key: '13b3089606c2e83b256ed2cec6513a9911016754', class: "font-style-button italic-text", slot: "suffix" }, "I"))));
2648
+ return (h(Host, { key: 'd05a099adf8623b8c67d68f3861c1cd401e86e2c' }, h("kritzel-dropdown", { key: 'b95af194feaaf5748bb0d584617d217e4b3b8180', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: this.selectedFontFamily } }, h("button", { key: '04a0a72f9297dc6c34a2a2019cae111d8725bcf4', class: "font-style-button", slot: "suffix" }, "B"), h("button", { key: 'f14b59f29bcce33f890b74c1fb8d1dad0ad6fd31', class: "font-style-button italic-text", slot: "suffix" }, "I"))));
2626
2649
  }
2627
2650
  };
2628
2651
  KritzelFontFamily.style = kritzelFontFamilyCss;
@@ -2643,7 +2666,7 @@ const KritzelFontSize = class {
2643
2666
  this.sizeChange.emit(size);
2644
2667
  }
2645
2668
  render() {
2646
- return (h(Host, { key: '9f3d851d443352f7437116cf91eff8d8de41e322' }, this.sizes.map(size => (h("div", { class: {
2669
+ return (h(Host, { key: '583659340d8f3bfb2ff6f64f2cd692ac07cb32d6' }, this.sizes.map(size => (h("div", { class: {
2647
2670
  'size-container': true,
2648
2671
  'selected': this.selectedSize === size,
2649
2672
  }, onClick: () => this.handleSizeClick(size) }, h("kritzel-font", { fontFamily: this.fontFamily, size: size }))))));
@@ -2738,7 +2761,7 @@ const KritzelMenu = class {
2738
2761
  this.itemCloseChildMenu.emit(event.detail);
2739
2762
  };
2740
2763
  render() {
2741
- return (h(Host, { key: 'be122cb0ecff3227d9e69997de76a73940a61860', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'ae10bec61e5c5e1a29b444cb7378f15c6692f3b6', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
2764
+ return (h(Host, { key: '211bd579000294d9edf6f85f2d7244aebe331191', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'b1c397118b1fbac934867677073661a69be1cab1', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
2742
2765
  }
2743
2766
  };
2744
2767
  KritzelMenu.style = kritzelMenuCss;
@@ -2839,12 +2862,12 @@ const KritzelMenuItem = class {
2839
2862
  ];
2840
2863
  }
2841
2864
  render() {
2842
- return (h(Host, { key: '9df3acdaff753e3ed910f848c98e8ad73e2b5f5c', tabIndex: this.item.isDisabled ? -1 : 0, class: {
2865
+ return (h(Host, { key: 'a35e1e3427568f436a36b43ba87af3710a4e83c5', tabIndex: this.item.isDisabled ? -1 : 0, class: {
2843
2866
  'selected': this.item.isSelected,
2844
2867
  'editing': this.item.isEditing,
2845
2868
  'disabled': this.item.isDisabled,
2846
2869
  'child-open': this.item.isChildMenuOpen,
2847
- }, onClick: this.handleItemSelect }, h("div", { key: 'bb73e5c0c3dd87efabcaa0b53d20c7c477b34aa1', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
2870
+ }, onClick: this.handleItemSelect }, h("div", { key: '42eef5a16b9b164839c1fe133e38ecb505c07632', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
2848
2871
  }
2849
2872
  static get watchers() { return {
2850
2873
  "item": ["onItemChange"]
@@ -3085,7 +3108,7 @@ const KritzelPortal = class {
3085
3108
  this.portal.style.left = `${left}px`;
3086
3109
  }
3087
3110
  render() {
3088
- return (h(Host, { key: '9c5cdf7126ff1148dd2364cce9d2524862e27d13', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '209a77246fedcea0c24882605487452ff5cc62ce' })));
3111
+ return (h(Host, { key: 'a906e21c1257dfc6ed21257cce150db17048f04e', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '972544f2258f8b6dc8c691f3762d5ba806a57c41' })));
3089
3112
  }
3090
3113
  static get watchers() { return {
3091
3114
  "anchor": ["anchorChanged"]
@@ -3185,7 +3208,7 @@ const KritzelSplitButton = class {
3185
3208
  this.menuScrollTop = event.target.scrollTop;
3186
3209
  };
3187
3210
  render() {
3188
- return (h(Host, { key: '4ff7809dd62c1dd60600fda592aeac43cd9bc74c', class: { mobile: this.isTouchDevice } }, h("button", { key: 'db6485fabcffdd75a25d178aca7b653af499a90c', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: '4001a4e23ef53bec2a578310de8c8b593d7b266c', name: this.buttonIcon })), h("div", { key: '8ff86d3c01a48b06afca77dd066518efa3589cb1', class: "split-divider" }), h("button", { key: 'f1c40edbec3756a7f3681de4e8d0f1981dd312a4', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: '0ddb89976632ae7454e66504f8bab3fd5072c252', name: this.dropdownIcon })), h("kritzel-portal", { key: '64531ffd6ac847fd1a99e32aceefea9f18088992', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: 'f3b86cb71e5ba39e8f98e26b3669416e2cdb4802', ref: el => (this.menuRef = el), items: this.items, onItemSelect: this.handleItemSelect, onItemSave: this.handleItemSave, onItemCancel: this.handleItemCancel, onItemToggleChildMenu: this.handleItemToggleChildMenu, onItemCloseChildMenu: this.handleItemCloseChildMenu, onClose: this.closeMenu, onScroll: this.handleScroll }))));
3211
+ return (h(Host, { key: 'd18a70b94e3d6860dfac952b26f66e5b96cc6fa0', class: { mobile: this.isTouchDevice } }, h("button", { key: 'ee65221543fd8984f94d0a0b43beb7e1d28411f2', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: '1dbdd1e4db4087564464e9586e91b48f80b88aae', name: this.buttonIcon })), h("div", { key: '78b5e0589e7a3dd0592fb2c1cdaae8732f57b129', class: "split-divider" }), h("button", { key: 'cfc5d53f06485a927608a99ea491e36b0e993fcc', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: '0e141b614cbfc758f01d21908d846d16bdce586d', name: this.dropdownIcon })), h("kritzel-portal", { key: 'b5def34dcfe5cbbf9641b1218af803937d7a77b6', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: '695f6c85a8ecd44f74ecf7752bf77d0caac69e6a', ref: el => (this.menuRef = el), items: this.items, onItemSelect: this.handleItemSelect, onItemSave: this.handleItemSave, onItemCancel: this.handleItemCancel, onItemToggleChildMenu: this.handleItemToggleChildMenu, onItemCloseChildMenu: this.handleItemCloseChildMenu, onClose: this.closeMenu, onScroll: this.handleScroll }))));
3189
3212
  }
3190
3213
  };
3191
3214
  KritzelSplitButton.style = kritzelSplitButtonCss;
@@ -3205,7 +3228,7 @@ const KritzelStrokeSize = class {
3205
3228
  this.sizeChange.emit(size);
3206
3229
  }
3207
3230
  render() {
3208
- return (h(Host, { key: '74579e34c23725e22927afe371c1f7925903720a' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
3231
+ return (h(Host, { key: '001a0ef8408d19532b57a521929c0cba54e99c52' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
3209
3232
  'size-container': true,
3210
3233
  'selected': this.selectedSize === size,
3211
3234
  }, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size }))))));
@@ -3282,23 +3305,23 @@ const KritzelTooltip = class {
3282
3305
  }
3283
3306
  }
3284
3307
  render() {
3285
- return (h(Host, { key: '72a6356a43a15a7abc9a46b0d22c3c62217791e8', style: {
3308
+ return (h(Host, { key: '8c3aeff60625f43f129afa70367cdb7a68a4b271', style: {
3286
3309
  position: 'fixed',
3287
3310
  zIndex: '9999',
3288
3311
  transition: 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out',
3289
3312
  visibility: this.isVisible ? 'visible' : 'hidden',
3290
3313
  left: !this.isMobileView ? `${this.positionX}px` : '50%',
3291
3314
  marginBottom: `${this.offsetY + this.arrowSize}px`,
3292
- } }, h("div", { key: '75f5350f23ada0eee009279eddd7d25273ad3740', class: "tooltip-content", onClick: event => event.stopPropagation() }, h("slot", { key: 'ad999154289e933cac1fdc13392de2aec78811a8' }), h("div", { key: '6be3f5c24d42898920c339be2cd2f3dd8a82fa80', class: "tooltip-arrow-wrapper", style: {
3315
+ } }, h("div", { key: 'b22b606c2a836c2c9bbe21c6b470754753ccb309', class: "tooltip-content", onClick: event => event.stopPropagation() }, h("slot", { key: '783403f4b5560012c9f6bd184a8c5eb26428e148' }), h("div", { key: 'bb98400edc5c6e05fd4ed2a476a5821f93964b8e', class: "tooltip-arrow-wrapper", style: {
3293
3316
  position: 'fixed',
3294
3317
  left: this.arrowOffset,
3295
3318
  bottom: `-${this.arrowSize * 2}px`,
3296
- } }, h("div", { key: '37397c6245dd6b0def23e2611d118e0c4f5860ef', class: "tooltip-arrow", style: {
3319
+ } }, h("div", { key: '850a058d635113a7870f25fa288a6447394c53ed', class: "tooltip-arrow", style: {
3297
3320
  borderLeft: `${this.arrowSize}px solid transparent`,
3298
3321
  borderRight: `${this.arrowSize}px solid transparent`,
3299
3322
  borderTop: `${this.arrowSize}px solid var(--kritzel-controls-tooltip-background-color, #ffffff)`,
3300
3323
  filter: 'drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2))',
3301
- } }), h("div", { key: 'dbf009c371d46ef0a36e27771758c66e817d9b22', class: "tooltip-arrow-rect", style: {
3324
+ } }), h("div", { key: 'bbb3dc2673e2dfe4443ad80540dfc9e5a25c6c06', class: "tooltip-arrow-rect", style: {
3302
3325
  position: 'relative',
3303
3326
  width: `${this.arrowSize * 2}px`,
3304
3327
  height: `${this.arrowSize}px`,
@@ -3334,7 +3357,7 @@ const KritzelUtilityPanel = class {
3334
3357
  this.redo.emit();
3335
3358
  }
3336
3359
  render() {
3337
- return (h(Host, { key: '8e2eb13668d8787827b10cee7c9daf2abdecc2c6' }, h("button", { key: '0773e7ef81bc972ba589333f4ac7e85d98737770', class: "utility-button", onClick: event => this.handleUndo(event) }, h("kritzel-icon", { key: 'fa69c1a2535d44bfb871a4d719079d0f900cc6c7', name: "undo" })), h("button", { key: 'edc28968f3ec92467d6b4aaa095a71770413d657', class: "utility-button", onClick: event => this.handleRedo(event) }, h("kritzel-icon", { key: 'd4cf72e2bda411fe9942d473c5e1ceae62a76074', name: "redo" })), h("div", { key: '8927237c6099a147495564657cdef97e7d35d7c1', class: "utility-separator" }), h("button", { key: 'e089819f7dd870165130322c3c4a9d754d4ed023', class: "utility-button" }, h("kritzel-icon", { key: 'a143770d1b3f8fdbe5c5b36c5d7eaab511cd8a4b', name: "delete", onClick: () => this.delete.emit() }))));
3360
+ return (h(Host, { key: '8109ccff01374c046d057021dfbcabdc632d829f' }, h("button", { key: '0d51cfb401974edf1a2a8810d2244f8a977c347f', class: "utility-button", onClick: event => this.handleUndo(event) }, h("kritzel-icon", { key: '1d13ee6bbf060402e0b1349d41b728875314e2e5', name: "undo" })), h("button", { key: 'f2fe59e7c99cb1550052088b507313cfaed72f29', class: "utility-button", onClick: event => this.handleRedo(event) }, h("kritzel-icon", { key: '74bf8c20f61144ab4abc5804dcd8f39917d2c966', name: "redo" })), h("div", { key: '0c9a942e786425b32e984fefdc97b1abb5077997', class: "utility-separator" }), h("button", { key: '44ca9340c2f73212332e9b3ed93ed93b8f7c6944', class: "utility-button" }, h("kritzel-icon", { key: '7b4c3d9a105e0c25b5bbc11ff1bc1cbed9833e03', name: "delete", onClick: () => this.delete.emit() }))));
3338
3361
  }
3339
3362
  };
3340
3363
  KritzelUtilityPanel.style = kritzelUtilityPanelCss;