kritzel-stencil 0.0.131 → 0.0.133

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 (362) hide show
  1. package/dist/cjs/{index-BwINBV6L.js → index-DCHCVnOl.js} +755 -701
  2. package/dist/cjs/index-DCHCVnOl.js.map +1 -0
  3. package/dist/cjs/index-nzUNdMPh.js +6 -2
  4. package/dist/cjs/index.cjs.js +1 -1
  5. package/dist/cjs/kritzel-brush-style.cjs.entry.js +32 -0
  6. package/dist/cjs/kritzel-brush-style.entry.cjs.js.map +1 -0
  7. package/dist/cjs/{kritzel-brush-style_23.cjs.entry.js → kritzel-color_22.cjs.entry.js} +1046 -874
  8. package/dist/cjs/loader.cjs.js +1 -1
  9. package/dist/cjs/stencil.cjs.js +1 -1
  10. package/dist/collection/classes/commands/add-object.command.js +6 -7
  11. package/dist/collection/classes/commands/add-object.command.js.map +1 -1
  12. package/dist/collection/classes/commands/add-selection-group.command.js +9 -9
  13. package/dist/collection/classes/commands/add-selection-group.command.js.map +1 -1
  14. package/dist/collection/classes/commands/base.command.js +3 -3
  15. package/dist/collection/classes/commands/base.command.js.map +1 -1
  16. package/dist/collection/classes/commands/batch.command.js +2 -2
  17. package/dist/collection/classes/commands/batch.command.js.map +1 -1
  18. package/dist/collection/classes/commands/move-selection-group.command.js +15 -7
  19. package/dist/collection/classes/commands/move-selection-group.command.js.map +1 -1
  20. package/dist/collection/classes/commands/remove-object.command.js +8 -9
  21. package/dist/collection/classes/commands/remove-object.command.js.map +1 -1
  22. package/dist/collection/classes/commands/remove-selection-group.command.js +7 -7
  23. package/dist/collection/classes/commands/remove-selection-group.command.js.map +1 -1
  24. package/dist/collection/classes/commands/resize-selection-group.command.js +15 -7
  25. package/dist/collection/classes/commands/resize-selection-group.command.js.map +1 -1
  26. package/dist/collection/classes/commands/rotate-selection-group.command.js +14 -12
  27. package/dist/collection/classes/commands/rotate-selection-group.command.js.map +1 -1
  28. package/dist/collection/classes/commands/update-object.command.js +6 -5
  29. package/dist/collection/classes/commands/update-object.command.js.map +1 -1
  30. package/dist/collection/classes/commands/update-viewport.command.js +11 -11
  31. package/dist/collection/classes/commands/update-viewport.command.js.map +1 -1
  32. package/dist/collection/classes/{store.class.js → core/core.class.js} +116 -145
  33. package/dist/collection/classes/core/core.class.js.map +1 -0
  34. package/dist/collection/classes/{database.class.js → core/database.class.js} +28 -20
  35. package/dist/collection/classes/core/database.class.js.map +1 -0
  36. package/dist/collection/classes/core/history.class.js +88 -0
  37. package/dist/collection/classes/core/history.class.js.map +1 -0
  38. package/dist/collection/classes/{reviver.class.js → core/reviver.class.js} +27 -23
  39. package/dist/collection/classes/core/reviver.class.js.map +1 -0
  40. package/dist/collection/classes/core/store.class.js +51 -0
  41. package/dist/collection/classes/core/store.class.js.map +1 -0
  42. package/dist/collection/classes/core/viewport.class.js +165 -0
  43. package/dist/collection/classes/core/viewport.class.js.map +1 -0
  44. package/dist/collection/classes/core/workspace.class.js +42 -0
  45. package/dist/collection/classes/core/workspace.class.js.map +1 -0
  46. package/dist/collection/classes/handlers/base.handler.js +4 -4
  47. package/dist/collection/classes/handlers/base.handler.js.map +1 -1
  48. package/dist/collection/classes/handlers/context-menu.handler.js +29 -19
  49. package/dist/collection/classes/handlers/context-menu.handler.js.map +1 -1
  50. package/dist/collection/classes/handlers/hover.handler.js +5 -5
  51. package/dist/collection/classes/handlers/hover.handler.js.map +1 -1
  52. package/dist/collection/classes/handlers/key.handler.js +38 -44
  53. package/dist/collection/classes/handlers/key.handler.js.map +1 -1
  54. package/dist/collection/classes/handlers/move.handler.js +49 -44
  55. package/dist/collection/classes/handlers/move.handler.js.map +1 -1
  56. package/dist/collection/classes/handlers/resize.handler.js +55 -60
  57. package/dist/collection/classes/handlers/resize.handler.js.map +1 -1
  58. package/dist/collection/classes/handlers/rotation.handler.js +59 -69
  59. package/dist/collection/classes/handlers/rotation.handler.js.map +1 -1
  60. package/dist/collection/classes/handlers/selection.handler.js +73 -72
  61. package/dist/collection/classes/handlers/selection.handler.js.map +1 -1
  62. package/dist/collection/classes/objects/base-object.class.js +30 -17
  63. package/dist/collection/classes/objects/base-object.class.js.map +1 -1
  64. package/dist/collection/classes/objects/custom-element.class.js +3 -3
  65. package/dist/collection/classes/objects/custom-element.class.js.map +1 -1
  66. package/dist/collection/classes/objects/image.class.js +5 -5
  67. package/dist/collection/classes/objects/image.class.js.map +1 -1
  68. package/dist/collection/classes/objects/path.class.js +7 -7
  69. package/dist/collection/classes/objects/path.class.js.map +1 -1
  70. package/dist/collection/classes/objects/selection-box.class.js +4 -4
  71. package/dist/collection/classes/objects/selection-box.class.js.map +1 -1
  72. package/dist/collection/classes/objects/selection-group.class.js +19 -20
  73. package/dist/collection/classes/objects/selection-group.class.js.map +1 -1
  74. package/dist/collection/classes/objects/text.class.js +13 -13
  75. package/dist/collection/classes/objects/text.class.js.map +1 -1
  76. package/dist/collection/classes/registries/tool.registry.js +2 -2
  77. package/dist/collection/classes/registries/tool.registry.js.map +1 -1
  78. package/dist/collection/classes/tools/base-tool.class.js +11 -5
  79. package/dist/collection/classes/tools/base-tool.class.js.map +1 -1
  80. package/dist/collection/classes/tools/brush-tool.class.js +57 -53
  81. package/dist/collection/classes/tools/brush-tool.class.js.map +1 -1
  82. package/dist/collection/classes/tools/eraser-tool.class.js +26 -26
  83. package/dist/collection/classes/tools/eraser-tool.class.js.map +1 -1
  84. package/dist/collection/classes/tools/image-tool.class.js +11 -11
  85. package/dist/collection/classes/tools/image-tool.class.js.map +1 -1
  86. package/dist/collection/classes/tools/selection-tool.class.js +39 -37
  87. package/dist/collection/classes/tools/selection-tool.class.js.map +1 -1
  88. package/dist/collection/classes/tools/text-tool.class.js +37 -37
  89. package/dist/collection/classes/tools/text-tool.class.js.map +1 -1
  90. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +28 -28
  91. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js.map +1 -1
  92. package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +7 -9
  93. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +177 -7
  94. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
  95. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +237 -232
  96. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -1
  97. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js +1 -1
  98. package/dist/collection/components/shared/kritzel-brush-style/kritzel-brush-style.js.map +1 -1
  99. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
  100. package/dist/collection/components/shared/kritzel-color/kritzel-color.js.map +1 -1
  101. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.css +5 -0
  102. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +3 -3
  103. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js.map +1 -1
  104. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js +12 -12
  105. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.js.map +1 -1
  106. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
  107. package/dist/collection/components/shared/kritzel-font/kritzel-font.js.map +1 -1
  108. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js +1 -1
  109. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js.map +1 -1
  110. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
  111. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js.map +1 -1
  112. package/dist/collection/components/shared/kritzel-icon/kritzel-icon.css +1 -0
  113. package/dist/collection/components/shared/kritzel-icon/kritzel-icon.js.map +1 -1
  114. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.css +5 -1
  115. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +2 -2
  116. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js.map +1 -1
  117. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.css +18 -7
  118. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +24 -9
  119. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js.map +1 -1
  120. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +4 -42
  121. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js.map +1 -1
  122. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.css +0 -4
  123. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +52 -10
  124. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js.map +1 -1
  125. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.css +4 -0
  126. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
  127. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js.map +1 -1
  128. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +79 -7
  129. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js.map +1 -1
  130. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +47 -15
  131. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js.map +1 -1
  132. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.css +4 -0
  133. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js +6 -6
  134. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js.map +1 -1
  135. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js +2 -2
  136. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js.map +1 -1
  137. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +12 -1
  138. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +23 -7
  139. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js.map +1 -1
  140. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.css +5 -0
  141. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  142. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js.map +1 -1
  143. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +25 -15
  144. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js.map +1 -1
  145. package/dist/collection/configs/default-engine-state.js +0 -1
  146. package/dist/collection/configs/default-engine-state.js.map +1 -1
  147. package/dist/collection/helpers/devices.helper.js +20 -0
  148. package/dist/collection/helpers/devices.helper.js.map +1 -1
  149. package/dist/collection/helpers/event.helper.js +1 -5
  150. package/dist/collection/helpers/event.helper.js.map +1 -1
  151. package/dist/collection/helpers/html.helper.js +29 -0
  152. package/dist/collection/helpers/html.helper.js.map +1 -1
  153. package/dist/collection/helpers/object.helper.js +0 -14
  154. package/dist/collection/helpers/object.helper.js.map +1 -1
  155. package/dist/collection/index.js +1 -1
  156. package/dist/collection/index.js.map +1 -1
  157. package/dist/collection/interfaces/clonable.interface.js +2 -0
  158. package/dist/collection/interfaces/clonable.interface.js.map +1 -0
  159. package/dist/collection/interfaces/engine-state.interface.js.map +1 -1
  160. package/dist/collection/interfaces/serializable.interface.js.map +1 -1
  161. package/dist/collection/types/deep-readonly.type.js +2 -0
  162. package/dist/collection/types/deep-readonly.type.js.map +1 -0
  163. package/dist/components/index.js +3 -3
  164. package/dist/components/kritzel-brush-style.js +59 -1
  165. package/dist/components/kritzel-brush-style.js.map +1 -1
  166. package/dist/components/kritzel-color-palette.js +1 -1
  167. package/dist/components/kritzel-color.js +1 -1
  168. package/dist/components/kritzel-context-menu.js +1 -1
  169. package/dist/components/kritzel-control-brush-config.js +1 -1
  170. package/dist/components/kritzel-control-text-config.js +1 -1
  171. package/dist/components/kritzel-controls.js +1 -1
  172. package/dist/components/kritzel-cursor-trail.js +1 -1
  173. package/dist/components/kritzel-dropdown.js +1 -1
  174. package/dist/components/kritzel-editor.js +80 -37
  175. package/dist/components/kritzel-editor.js.map +1 -1
  176. package/dist/components/kritzel-engine.js +1 -1
  177. package/dist/components/kritzel-font-family.js +1 -1
  178. package/dist/components/kritzel-font-size.js +1 -1
  179. package/dist/components/kritzel-font.js +1 -1
  180. package/dist/components/kritzel-icon.js +1 -1
  181. package/dist/components/kritzel-menu-item.js +1 -1
  182. package/dist/components/kritzel-menu.js +1 -1
  183. package/dist/components/kritzel-portal.js +1 -1
  184. package/dist/components/kritzel-split-button.js +1 -1
  185. package/dist/components/kritzel-stroke-size.js +1 -1
  186. package/dist/components/kritzel-tooltip.js +1 -1
  187. package/dist/components/kritzel-utility-panel.js +1 -1
  188. package/dist/components/kritzel-workspace-manager.js +1 -1
  189. package/dist/components/{p-CMJ3P0Vw.js → p-0iJh9Z6m.js} +5 -5
  190. package/dist/components/p-0iJh9Z6m.js.map +1 -0
  191. package/dist/components/p-B0kd2rUI.js +16 -0
  192. package/dist/components/p-B0kd2rUI.js.map +1 -0
  193. package/dist/components/{p-BB5R2k1o.js → p-B3LGnqFz.js} +41 -31
  194. package/dist/components/p-B3LGnqFz.js.map +1 -0
  195. package/dist/components/{p-BB0_-X42.js → p-B7kZ1_RH.js} +4 -4
  196. package/dist/components/{p-BB0_-X42.js.map → p-B7kZ1_RH.js.map} +1 -1
  197. package/dist/components/{p-t4NIsuX9.js → p-B7w19kIk.js} +15 -27
  198. package/dist/components/p-B7w19kIk.js.map +1 -0
  199. package/dist/components/{p-B1BLgWL1.js → p-BGdsAz54.js} +27 -18
  200. package/dist/components/p-BGdsAz54.js.map +1 -0
  201. package/dist/components/{p-CGmS8wnN.js → p-BKvOO7NT.js} +26 -16
  202. package/dist/components/p-BKvOO7NT.js.map +1 -0
  203. package/dist/components/{p-BhiYvSBc.js → p-BM9IjvnD.js} +3 -3
  204. package/dist/components/p-BM9IjvnD.js.map +1 -0
  205. package/dist/components/{p-BrBQUN0Q.js → p-BPsQrpzN.js} +40 -11
  206. package/dist/components/p-BPsQrpzN.js.map +1 -0
  207. package/dist/components/p-C6qB08BS.js +68 -0
  208. package/dist/components/p-C6qB08BS.js.map +1 -0
  209. package/dist/components/{p-BPz_H-EG.js → p-CM8KdFZI.js} +28 -16
  210. package/dist/components/p-CM8KdFZI.js.map +1 -0
  211. package/dist/components/{p-DHSEK3rF.js → p-CNTK3JOp.js} +174 -153
  212. package/dist/components/p-CNTK3JOp.js.map +1 -0
  213. package/dist/components/{p-DMrtdhBD.js → p-CsyM5q2M.js} +7 -7
  214. package/dist/components/p-CsyM5q2M.js.map +1 -0
  215. package/dist/components/{p-BuewJQNl.js → p-CwH-bwjb.js} +1187 -1141
  216. package/dist/components/p-CwH-bwjb.js.map +1 -0
  217. package/dist/components/{p-BgmKrd5Z.js → p-DCx3703u.js} +5 -5
  218. package/dist/components/p-DCx3703u.js.map +1 -0
  219. package/dist/components/{p-trncBp_6.js → p-DFO-6kuA.js} +15 -15
  220. package/dist/components/p-DFO-6kuA.js.map +1 -0
  221. package/dist/components/{p-BubxwvMA.js → p-Db3kxVe2.js} +24 -24
  222. package/dist/components/p-Db3kxVe2.js.map +1 -0
  223. package/dist/components/{p-BexTdWaX.js → p-Ddlbt3Bj.js} +4 -4
  224. package/dist/components/p-Ddlbt3Bj.js.map +1 -0
  225. package/dist/components/{p-CHxPWeZd.js → p-DjU7p3od.js} +11 -11
  226. package/dist/components/{p-CHxPWeZd.js.map → p-DjU7p3od.js.map} +1 -1
  227. package/dist/components/{p-BeljsQ-8.js → p-Dw4n-4zp.js} +32 -17
  228. package/dist/components/p-Dw4n-4zp.js.map +1 -0
  229. package/dist/components/{p-DxTu1aoJ.js → p-NP1Htol7.js} +7 -45
  230. package/dist/components/p-NP1Htol7.js.map +1 -0
  231. package/dist/components/p-YqK8ch2R.js +46 -0
  232. package/dist/components/p-YqK8ch2R.js.map +1 -0
  233. package/dist/components/p-l10It7Nm.js +30 -0
  234. package/dist/components/p-l10It7Nm.js.map +1 -0
  235. package/dist/components/{p-p1Jkec_q.js → p-sq9jgfX0.js} +3 -3
  236. package/dist/components/p-sq9jgfX0.js.map +1 -0
  237. package/dist/components/{p-yZ48g7-u.js → p-sreNwi0N.js} +4 -4
  238. package/dist/components/{p-yZ48g7-u.js.map → p-sreNwi0N.js.map} +1 -1
  239. package/dist/esm/{index-B-oSk-v8.js → index-DY3KqYWc.js} +756 -702
  240. package/dist/esm/index-DY3KqYWc.js.map +1 -0
  241. package/dist/esm/index-oCOlsFCN.js +6 -2
  242. package/dist/esm/index.js +1 -1
  243. package/dist/esm/kritzel-brush-style.entry.js +30 -0
  244. package/dist/esm/kritzel-brush-style.entry.js.map +1 -0
  245. package/dist/esm/{kritzel-brush-style_23.entry.js → kritzel-color_22.entry.js} +1048 -875
  246. package/dist/esm/loader.js +1 -1
  247. package/dist/esm/stencil.js +1 -1
  248. package/dist/stencil/index.esm.js +1 -1
  249. package/dist/stencil/kritzel-brush-style.entry.esm.js.map +1 -0
  250. package/dist/stencil/p-25d1e040.entry.js +2 -0
  251. package/dist/stencil/p-25d1e040.entry.js.map +1 -0
  252. package/dist/stencil/p-DY3KqYWc.js +2 -0
  253. package/dist/stencil/p-DY3KqYWc.js.map +1 -0
  254. package/dist/stencil/p-dc534b01.entry.js +2 -0
  255. package/dist/stencil/p-dc534b01.entry.js.map +1 -0
  256. package/dist/stencil/stencil.esm.js +1 -1
  257. package/dist/types/classes/commands/add-object.command.d.ts +2 -2
  258. package/dist/types/classes/commands/add-selection-group.command.d.ts +2 -1
  259. package/dist/types/classes/commands/base.command.d.ts +3 -3
  260. package/dist/types/classes/commands/batch.command.d.ts +2 -1
  261. package/dist/types/classes/commands/move-selection-group.command.d.ts +2 -1
  262. package/dist/types/classes/commands/remove-object.command.d.ts +2 -2
  263. package/dist/types/classes/commands/remove-selection-group.command.d.ts +2 -2
  264. package/dist/types/classes/commands/resize-selection-group.command.d.ts +2 -1
  265. package/dist/types/classes/commands/rotate-selection-group.command.d.ts +2 -1
  266. package/dist/types/classes/commands/update-object.command.d.ts +2 -2
  267. package/dist/types/classes/commands/update-viewport.command.d.ts +2 -1
  268. package/dist/types/classes/{store.class.d.ts → core/core.class.d.ts} +9 -19
  269. package/dist/types/classes/{database.class.d.ts → core/database.class.d.ts} +3 -2
  270. package/dist/types/classes/{history.class.d.ts → core/history.class.d.ts} +5 -5
  271. package/dist/types/classes/core/reviver.class.d.ts +6 -0
  272. package/dist/types/classes/core/store.class.d.ts +17 -0
  273. package/dist/types/classes/{viewport.class.d.ts → core/viewport.class.d.ts} +3 -3
  274. package/dist/types/classes/core/workspace.class.d.ts +24 -0
  275. package/dist/types/classes/handlers/base.handler.d.ts +3 -3
  276. package/dist/types/classes/handlers/context-menu.handler.d.ts +2 -2
  277. package/dist/types/classes/handlers/hover.handler.d.ts +2 -2
  278. package/dist/types/classes/handlers/key.handler.d.ts +2 -2
  279. package/dist/types/classes/handlers/move.handler.d.ts +4 -2
  280. package/dist/types/classes/handlers/resize.handler.d.ts +3 -2
  281. package/dist/types/classes/handlers/rotation.handler.d.ts +6 -2
  282. package/dist/types/classes/handlers/selection.handler.d.ts +2 -2
  283. package/dist/types/classes/objects/base-object.class.d.ts +8 -5
  284. package/dist/types/classes/objects/custom-element.class.d.ts +2 -2
  285. package/dist/types/classes/objects/image.class.d.ts +2 -2
  286. package/dist/types/classes/objects/path.class.d.ts +2 -2
  287. package/dist/types/classes/objects/selection-box.class.d.ts +2 -2
  288. package/dist/types/classes/objects/selection-group.class.d.ts +2 -2
  289. package/dist/types/classes/objects/text.class.d.ts +2 -2
  290. package/dist/types/classes/registries/tool.registry.d.ts +2 -2
  291. package/dist/types/classes/tools/base-tool.class.d.ts +8 -4
  292. package/dist/types/classes/tools/brush-tool.class.d.ts +2 -2
  293. package/dist/types/classes/tools/eraser-tool.class.d.ts +2 -2
  294. package/dist/types/classes/tools/image-tool.class.d.ts +2 -2
  295. package/dist/types/classes/tools/selection-tool.class.d.ts +2 -2
  296. package/dist/types/classes/tools/text-tool.class.d.ts +2 -2
  297. package/dist/types/components/core/kritzel-cursor-trail/kritzel-cursor-trail.d.ts +5 -5
  298. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +13 -3
  299. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +21 -22
  300. package/dist/types/components/shared/kritzel-dropdown/kritzel-dropdown.d.ts +2 -2
  301. package/dist/types/components/shared/kritzel-menu-item/kritzel-menu-item.d.ts +2 -0
  302. package/dist/types/components/shared/kritzel-portal/kritzel-portal.d.ts +0 -1
  303. package/dist/types/components/shared/kritzel-split-button/kritzel-split-button.d.ts +4 -2
  304. package/dist/types/components/shared/kritzel-tooltip/kritzel-tooltip.d.ts +8 -2
  305. package/dist/types/components/ui/kritzel-context-menu/kritzel-context-menu.d.ts +5 -3
  306. package/dist/types/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.d.ts +1 -1
  307. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +3 -1
  308. package/dist/types/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.d.ts +3 -2
  309. package/dist/types/components.d.ts +41 -12
  310. package/dist/types/helpers/devices.helper.d.ts +4 -0
  311. package/dist/types/helpers/event.helper.d.ts +1 -1
  312. package/dist/types/helpers/html.helper.d.ts +1 -0
  313. package/dist/types/helpers/object.helper.d.ts +0 -2
  314. package/dist/types/index.d.ts +1 -1
  315. package/dist/types/interfaces/clonable.interface.d.ts +3 -0
  316. package/dist/types/interfaces/engine-state.interface.d.ts +1 -2
  317. package/dist/types/interfaces/serializable.interface.d.ts +2 -1
  318. package/dist/types/types/deep-readonly.type.d.ts +7 -0
  319. package/package.json +3 -2
  320. package/dist/cjs/index-BwINBV6L.js.map +0 -1
  321. package/dist/collection/classes/database.class.js.map +0 -1
  322. package/dist/collection/classes/history.class.js +0 -88
  323. package/dist/collection/classes/history.class.js.map +0 -1
  324. package/dist/collection/classes/reviver.class.js.map +0 -1
  325. package/dist/collection/classes/store.class.js.map +0 -1
  326. package/dist/collection/classes/viewport.class.js +0 -153
  327. package/dist/collection/classes/viewport.class.js.map +0 -1
  328. package/dist/collection/classes/workspace.class.js +0 -15
  329. package/dist/collection/classes/workspace.class.js.map +0 -1
  330. package/dist/components/p-B1BLgWL1.js.map +0 -1
  331. package/dist/components/p-BB5R2k1o.js.map +0 -1
  332. package/dist/components/p-BPz_H-EG.js.map +0 -1
  333. package/dist/components/p-B_lb1FGi.js +0 -19
  334. package/dist/components/p-B_lb1FGi.js.map +0 -1
  335. package/dist/components/p-BeljsQ-8.js.map +0 -1
  336. package/dist/components/p-BexTdWaX.js.map +0 -1
  337. package/dist/components/p-BgmKrd5Z.js.map +0 -1
  338. package/dist/components/p-BhiYvSBc.js.map +0 -1
  339. package/dist/components/p-BrBQUN0Q.js.map +0 -1
  340. package/dist/components/p-BubxwvMA.js.map +0 -1
  341. package/dist/components/p-BuewJQNl.js.map +0 -1
  342. package/dist/components/p-CGmS8wnN.js.map +0 -1
  343. package/dist/components/p-CJKA5zIE.js +0 -10
  344. package/dist/components/p-CJKA5zIE.js.map +0 -1
  345. package/dist/components/p-CMJ3P0Vw.js.map +0 -1
  346. package/dist/components/p-DHSEK3rF.js.map +0 -1
  347. package/dist/components/p-DMrtdhBD.js.map +0 -1
  348. package/dist/components/p-DnUKql15.js +0 -30
  349. package/dist/components/p-DnUKql15.js.map +0 -1
  350. package/dist/components/p-DxTu1aoJ.js.map +0 -1
  351. package/dist/components/p-p1Jkec_q.js.map +0 -1
  352. package/dist/components/p-rIRXQdie.js +0 -64
  353. package/dist/components/p-rIRXQdie.js.map +0 -1
  354. package/dist/components/p-t4NIsuX9.js.map +0 -1
  355. package/dist/components/p-trncBp_6.js.map +0 -1
  356. package/dist/esm/index-B-oSk-v8.js.map +0 -1
  357. package/dist/stencil/p-3bb80782.entry.js +0 -2
  358. package/dist/stencil/p-3bb80782.entry.js.map +0 -1
  359. package/dist/stencil/p-B-oSk-v8.js +0 -2
  360. package/dist/stencil/p-B-oSk-v8.js.map +0 -1
  361. package/dist/types/classes/reviver.class.d.ts +0 -6
  362. package/dist/types/classes/workspace.class.d.ts +0 -16
@@ -1,31 +1,5 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-oCOlsFCN.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 KritzelKeyboardHelper, h as KritzelEventHelper, i as KritzelBaseCommand, j as KritzelSelectionGroup, k as KrtizelSelectionBox, l as KritzelWorkspace, O as ObjectHelper, m as KritzelReviver, R as RemoveSelectionGroupCommand, n as RemoveObjectCommand, B as BatchCommand, A as AddObjectCommand, o as AddSelectionGroupCommand, p as KritzelToolRegistry, U as UpdateObjectCommand, q as KritzelBaseHandler, r as KritzelBaseTool } from './index-B-oSk-v8.js';
3
-
4
- const kritzelBrushStyleCss = ":host{display:flex;align-items:flex-start;gap:8px;padding:8px;box-sizing:border-box;width:100%}.brush-style-button{display:flex;justify-content:center;align-items:center;width:42px;height:32px;padding:0;border:none;outline:none;background:none;cursor:default;border-radius:0;color:var(--control-text-color);font-weight:bold;-webkit-tap-highlight-color:transparent}.font-style-button:not(:last-child){border-right:1px solid #333333}.font-style-button:hover{background-color:var(--control-hover-bg)}.font-style-button:active{background-color:var(--control-active-bg)}.font-style-button.selected,.font-style-button.selected:hover,.font-style-button.selected:active{background-color:var(--control-selected-bg);color:var(--control-selected-color)}";
5
-
6
- const KritzelBrushStyle = class {
7
- constructor(hostRef) {
8
- registerInstance(this, hostRef);
9
- this.typeChange = createEvent(this, "typeChange");
10
- }
11
- type = 'pen';
12
- brushOptions = [
13
- { value: 'pen', label: 'Pen' },
14
- { value: 'highlighter', label: 'Highlighter' },
15
- ];
16
- typeChange;
17
- handleDropdownValueChange(event) {
18
- this.typeChange.emit(event.detail);
19
- }
20
- render() {
21
- const dropdownOptions = this.brushOptions.map(option => ({
22
- value: option.value,
23
- label: option.label,
24
- }));
25
- return (h(Host, { key: 'd7af382fe6f613aa16a5146785990ad2faa17f60' }, h("kritzel-dropdown", { key: '6d6d330d415c210058834b2968774b3db2ab7fc4', options: dropdownOptions, value: this.type, onValueChanged: event => this.handleDropdownValueChange(event) }, h("button", { key: 'c9fb33795b8e25f68c1d2ae248dc82a6de29e199', class: "brush-style-button", slot: "prefix" }, h("kritzel-icon", { key: '975c95b545a1c27ae2984405ac298592eec9743d', name: this.type, size: 16 })))));
26
- }
27
- };
28
- KritzelBrushStyle.style = kritzelBrushStyleCss;
1
+ import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-oCOlsFCN.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 KritzelEventHelper, j as KritzelBaseHandler, k as KritzelToolRegistry, l as KritzelSelectionGroup, B as BatchCommand, R as RemoveSelectionGroupCommand, A as AddSelectionGroupCommand, m as KritzelBaseCommand, n as KrtizelSelectionBox, O as ObjectHelper, o as KritzelReviver, p as RemoveObjectCommand, q as AddObjectCommand, U as UpdateObjectCommand, r as KritzelBaseTool } from './index-DY3KqYWc.js';
29
3
 
30
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)}";
31
5
 
@@ -61,13 +35,13 @@ const KritzelColor = class {
61
35
  }
62
36
  render() {
63
37
  const isColorVeryLight = this.isLightColor(this.value);
64
- return (h(Host, { key: '1468f3502f7d10d182ac72a05ce4b1e520353f8a' }, h("div", { key: 'd30d47667b1b72a970c4ee0da887dd59a663eae7', class: "checkerboard-bg", style: {
38
+ return (h(Host, { key: '198dba41e1600d76faace18de78191d2b7a551ec' }, h("div", { key: 'ee690cffb7925e09cb2c51022eec607247a4849f', class: "checkerboard-bg", style: {
65
39
  width: `${this.size}px`,
66
40
  height: `${this.size}px`,
67
41
  borderRadius: '50%',
68
42
  display: 'inline-block',
69
43
  position: 'relative',
70
- } }, h("div", { key: '073fd85967e53b609103a9fe47028bcda849e5ec', class: {
44
+ } }, h("div", { key: '66cc8df8fabd008db8c00942994875e3e8d722ce', class: {
71
45
  'color-circle': true,
72
46
  'white': isColorVeryLight,
73
47
  }, style: {
@@ -84,7 +58,7 @@ const KritzelColor = class {
84
58
  };
85
59
  KritzelColor.style = kritzelColorCss;
86
60
 
87
- const kritzelColorPaletteCss = ":host{display:flex;align-items:flex-start;gap:8px;padding:8px;width:100%;box-sizing:border-box}.color-grid{width:100%;display:grid;grid-template-columns:repeat(6, 32px);gap:8px;justify-items:center;overflow:hidden;height:40px;transition:height 0.1s ease-in-out}.color-grid.expanded{height:500px}.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}.color-container:hover{background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.color-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-color-palette-selected-background-color)}";
61
+ const kritzelColorPaletteCss = ":host{display:flex;align-items:flex-start;gap:8px;padding:8px;width:100%;box-sizing:border-box}.color-grid{width:100%;display:grid;grid-template-columns:repeat(6, 32px);gap:8px;justify-items:center;overflow:hidden;height:40px;transition:height 0.1s ease-in-out}.color-grid.expanded{height:500px}.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}.color-container:focus-visible{outline:var(--kritzel-color-palette-focus-outline, 2px auto #e3e3e3)}.color-container:hover{background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.color-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-color-palette-selected-background-color)}";
88
62
 
89
63
  const KritzelColorPalette = class {
90
64
  constructor(hostRef) {
@@ -110,12 +84,12 @@ const KritzelColorPalette = class {
110
84
  render() {
111
85
  const displayedColors = this.isExpanded ? this.colors : this.colors.slice(0, 6);
112
86
  const expandedHeight = this.isExpanded ? this.calculateHeight() : '32px';
113
- return (h(Host, { key: 'dddc32b0904800092d45727e833181af32eb8766' }, h("div", { key: '293cbed8e9c62b5f409b7dcdca0df5de9d65b758', class: {
87
+ return (h(Host, { key: '2ead7cd530ce181856e5f582f086a22a1fe69390' }, h("div", { key: 'fcc75b267f36e271d50615bfde42a29c28aa2536', class: {
114
88
  'color-grid': true,
115
89
  'expanded': this.isExpanded,
116
90
  }, style: {
117
- height: expandedHeight
118
- } }, displayedColors.map(color => (h("div", { class: {
91
+ height: expandedHeight,
92
+ } }, displayedColors.map(color => (h("div", { tabIndex: 0, class: {
119
93
  'color-container': true,
120
94
  'selected': this.selectedColor === color,
121
95
  }, onClick: () => this.handleColorClick(color) }, h("kritzel-color", { value: color })))))));
@@ -129,16 +103,25 @@ const KritzelContextMenu = class {
129
103
  constructor(hostRef) {
130
104
  registerInstance(this, hostRef);
131
105
  this.actionSelected = createEvent(this, "actionSelected");
106
+ this.close = createEvent(this, "close");
132
107
  }
108
+ get host() { return getElement(this); }
133
109
  items;
110
+ onItemsChanged() {
111
+ this.updateMenuItems();
112
+ }
134
113
  objects;
135
114
  actionSelected;
136
- get hostElement() { return getElement(this); }
115
+ close;
137
116
  processedItems = [];
138
- componentWillLoad() {
139
- this.updateMenuItems();
117
+ handleOutsideClick(event) {
118
+ event.preventDefault();
119
+ const path = event.composedPath();
120
+ if (!path.includes(this.host)) {
121
+ this.close.emit();
122
+ }
140
123
  }
141
- onItemsChanged() {
124
+ componentWillLoad() {
142
125
  this.updateMenuItems();
143
126
  }
144
127
  handleItemClick(item, isDisabled) {
@@ -146,15 +129,6 @@ const KritzelContextMenu = class {
146
129
  this.actionSelected.emit(item);
147
130
  }
148
131
  }
149
- async evaluateProperty(value, defaultValue) {
150
- if (typeof value === 'boolean') {
151
- return value;
152
- }
153
- if (typeof value === 'function') {
154
- return await Promise.resolve(value(null, this.objects));
155
- }
156
- return defaultValue;
157
- }
158
132
  async updateMenuItems() {
159
133
  const processed = [];
160
134
  for (const item of this.items) {
@@ -166,8 +140,17 @@ const KritzelContextMenu = class {
166
140
  }
167
141
  this.processedItems = processed;
168
142
  }
143
+ async evaluateProperty(value, defaultValue) {
144
+ if (typeof value === 'boolean') {
145
+ return value;
146
+ }
147
+ if (typeof value === 'function') {
148
+ return await Promise.resolve(value(null, this.objects));
149
+ }
150
+ return defaultValue;
151
+ }
169
152
  render() {
170
- return (h(Host, { key: '96569454f806a6d17380315b4d0200236fe22550' }, h("div", { key: '0e5899a2901e1e9ab9d657824e105121ce785bdc', 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), onTouchStart: () => this.handleItemClick(item, isDisabled), disabled: isDisabled }, item.icon && h("kritzel-icon", { name: item.icon, size: 16 }), h("span", { class: "label" }, item.label)))))));
153
+ return (h(Host, { key: 'ff72bd31f6c0f3193674710bccab829f14e011d3' }, h("div", { key: '80cd7a99dc9bb1fb9ec4edb09a9bacde70dde7c3', 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)))))));
171
154
  }
172
155
  static get watchers() { return {
173
156
  "items": ["onItemsChanged"]
@@ -175,7 +158,7 @@ const KritzelContextMenu = class {
175
158
  };
176
159
  KritzelContextMenu.style = kritzelContextMenuCss;
177
160
 
178
- const kritzelControlBrushConfigCss = ":host{display:flex;flex-direction:column;width:100%}.expand-toggle{background:none;border:none;cursor:pointer;font-size:14px;line-height:1;padding:8px;color:var(--kritzel-color-palette-expand-toggle-color, #666666)}.expand-toggle:hover{color:var(--kritzel-color-palette-expand-toggle-hover-color, #333333)}";
161
+ const kritzelControlBrushConfigCss = ":host{display:flex;flex-direction:column;width:100%}.expand-toggle{background:none;border:none;cursor:pointer;font-size:14px;line-height:1;padding:8px;color:var(--kritzel-color-palette-expand-toggle-color, #666666)}.expand-toggle:focus-visible{outline:var(--kritzel-color-palette-focus-outline, 2px auto #e3e3e3)}.expand-toggle:hover{color:var(--kritzel-color-palette-expand-toggle-hover-color, #333333)}";
179
162
 
180
163
  const KritzelControlBrushConfig = class {
181
164
  constructor(hostRef) {
@@ -183,12 +166,12 @@ const KritzelControlBrushConfig = class {
183
166
  this.toolChange = createEvent(this, "toolChange");
184
167
  }
185
168
  tool;
186
- isExpanded = false;
187
- toolChange;
188
- palette = [];
189
169
  handleToolChange(newTool) {
190
170
  this.palette = newTool.palettes[newTool.type];
191
171
  }
172
+ isExpanded = false;
173
+ toolChange;
174
+ palette = [];
192
175
  componentWillLoad() {
193
176
  this.palette = this.tool.palettes[this.tool.type];
194
177
  }
@@ -210,14 +193,14 @@ const KritzelControlBrushConfig = class {
210
193
  this.toolChange.emit(this.tool);
211
194
  }
212
195
  render() {
213
- return (h(Host, { key: 'a1f04aba4ed04e91c7b375e0f88bcff4fea1cba4' }, h("div", { key: 'c7cd734c96498c8cd6a27321fb6d11773e7aa8a9', style: {
196
+ return (h(Host, { key: '8fe8c0564f491121c0c44c6ff4083034f92dbb67' }, h("div", { key: '3e8a69b827785976768bfc1e809126bee7c48c62', style: {
214
197
  display: 'flex',
215
198
  flexDirection: 'row',
216
- alignItems: 'center',
199
+ alignItems: this.isExpanded ? 'flex-start' : 'center',
217
200
  justifyContent: 'flex-start',
218
201
  width: '100%',
219
202
  gap: '8px',
220
- } }, h("kritzel-brush-style", { key: '67958dc2a34302eb23fabbafea3c7dc7863f1984', type: this.tool.type, onTypeChange: event => this.handleTypeChange(event) }), h("button", { key: '5c84a72d9f337dff253a161abe19acb832275272', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand', style: this.palette.length > 6 ? { visibillity: 'visible' } : { visibility: 'hidden' } }, h("kritzel-icon", { key: 'b3e0c44db35b53a584757e18b507df09f30bfa8a', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-color-palette", { key: 'eb098094ae69aa5901244f9686a3eb990271c07d', colors: this.palette, selectedColor: this.tool.color, isExpanded: this.isExpanded, isOpaque: true, onColorChange: color => this.handleColorChange(color) }), h("kritzel-stroke-size", { key: '18ae184b282ca2ec6511a6ac0065914edf66f91b', selectedSize: this.tool.size, onSizeChange: event => this.handleSizeChange(event) })));
203
+ } }, 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) })));
221
204
  }
222
205
  static get watchers() { return {
223
206
  "tool": ["handleToolChange"]
@@ -251,14 +234,14 @@ const KritzelControlTextConfig = class {
251
234
  this.toolChange.emit(this.tool);
252
235
  }
253
236
  render() {
254
- return (h(Host, { key: 'a5c0e3eb4343637d758888d7d2a0843549fa0c25' }, h("div", { key: '1d4d42af117ed9da1a91d1747a7d6f6531e0de9b', style: {
237
+ return (h(Host, { key: '3695b187943af25566885d63257ae3de9f405ea5' }, h("div", { key: '7bb146ae3c188478ba17f18f70fd170ce3536308', style: {
255
238
  display: 'flex',
256
239
  flexDirection: 'row',
257
240
  alignItems: 'center',
258
241
  justifyContent: 'flex-start',
259
242
  width: '100%',
260
243
  gap: '8px',
261
- } }, h("kritzel-font-family", { key: 'b19e1edcbc7bafb0829d3e173d33cff37d2a5959', selectedFontFamily: this.tool.fontFamily, onFontFamilyChange: event => this.handleFamilyChange(event) }), h("button", { key: 'ca3dce970ee5dd1a7c8c617127777859b45380c4', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand' }, h("kritzel-icon", { key: '241d82cd06db8d20794a369a4df6e6a71531131a', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-color-palette", { key: 'ec82e5c09046e70e904cc1ec9716c53bec9cac2b', colors: this.tool.palette, selectedColor: this.tool.fontColor, isExpanded: this.isExpanded, onColorChange: event => this.handleColorChange(event) }), h("kritzel-font-size", { key: '1cbddf6e6de21bd62f3803cca9e21ef9e01f15c0', selectedSize: this.tool.fontSize, fontFamily: this.tool.fontFamily, onSizeChange: event => this.handleSizeChange(event) })));
244
+ } }, 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) })));
262
245
  }
263
246
  };
264
247
  KritzelControlTextConfig.style = kritzelControlTextConfigCss;
@@ -267,15 +250,36 @@ class KritzelDevicesHelper {
267
250
  static isTouchDevice() {
268
251
  return window.matchMedia('(any-pointer: coarse)').matches;
269
252
  }
253
+ static isAndroid() {
254
+ return /android/i.test(navigator.userAgent);
255
+ }
256
+ static isIOS() {
257
+ return /iPad|iPhone|iPod/.test(navigator.userAgent);
258
+ }
259
+ static detectOS() {
260
+ if (this.isIOS()) {
261
+ return 'iOS';
262
+ }
263
+ else if (this.isAndroid()) {
264
+ return 'Android';
265
+ }
266
+ else {
267
+ return 'Other';
268
+ }
269
+ }
270
+ static isFirefox() {
271
+ return /firefox/i.test(navigator.userAgent);
272
+ }
270
273
  }
271
274
 
272
- 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: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-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}.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:66px;left:50%;transform:translateX(-50%);z-index:10001}";
275
+ 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}";
273
276
 
274
277
  const KritzelControls = class {
275
278
  constructor(hostRef) {
276
279
  registerInstance(this, hostRef);
277
280
  this.isControlsReady = createEvent(this, "isControlsReady");
278
281
  }
282
+ get host() { return getElement(this); }
279
283
  controls = [];
280
284
  activeControl = null;
281
285
  isUtilityPanelVisible = true;
@@ -283,7 +287,6 @@ const KritzelControls = class {
283
287
  firstConfig = null;
284
288
  isTooltipVisible = false;
285
289
  isTouchDevice = KritzelDevicesHelper.isTouchDevice();
286
- get host() { return getElement(this); }
287
290
  handleDocumentClick(event) {
288
291
  const element = event.target;
289
292
  if (!this.kritzelEngine || element.closest('.kritzel-tooltip')) {
@@ -300,12 +303,12 @@ const KritzelControls = class {
300
303
  }
301
304
  async handleActiveToolChange(event) {
302
305
  this.activeControl = this.controls.find(control => control.tool === event.detail) || null;
303
- await this.kritzelEngine?.setFocus();
304
306
  }
305
307
  async closeTooltip() {
306
308
  this.isTooltipVisible = false;
307
309
  }
308
310
  kritzelEngine = null;
311
+ tooltipRef = null;
309
312
  get activeToolAsTextTool() {
310
313
  return this.activeControl?.tool;
311
314
  }
@@ -352,21 +355,33 @@ const KritzelControls = class {
352
355
  handleConfigClick(event) {
353
356
  event.stopPropagation();
354
357
  this.isTooltipVisible = !this.isTooltipVisible;
355
- this.kritzelEngine?.disable();
358
+ if (this.isTooltipVisible) {
359
+ this.kritzelEngine?.disable();
360
+ }
361
+ else {
362
+ this.kritzelEngine?.enable();
363
+ }
364
+ setTimeout(() => {
365
+ this.tooltipRef?.focusContent();
366
+ }, 100);
356
367
  }
357
368
  async handleToolChange(event) {
358
369
  this.activeControl = { ...this.activeControl, tool: event.detail };
359
370
  await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
360
371
  }
372
+ handleTooltipClosed() {
373
+ this.isTooltipVisible = false;
374
+ this.kritzelEngine?.enable();
375
+ }
361
376
  render() {
362
377
  const hasNoConfig = this.activeControl?.config === undefined || this.activeControl?.config === null;
363
- return (h(Host, { key: '7ab1f3e176848cb9a34be7e7b90e13c2a861d78b', class: {
378
+ return (h(Host, { key: 'a463310d88265b71097f838bf775abdcabc99225', class: {
364
379
  mobile: this.isTouchDevice,
365
- } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: 'f168b27cb9cc3a1a7d0028055cd58c60cec9776f', style: {
380
+ } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '267e9c26b41a52c655209dbaa8c85cbd72323577', style: {
366
381
  position: 'absolute',
367
382
  bottom: '56px',
368
383
  left: '12px',
369
- }, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '9e568217b23632d73b051350d7f795f0cd7ab9ed', class: "kritzel-controls" }, this.controls.map(control => {
384
+ }, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: 'c55773245c925e1b972f3e83cb4d8f1c93ebe995', class: "kritzel-controls" }, this.controls.map(control => {
370
385
  if (control.type === 'tool') {
371
386
  return (h("button", { class: {
372
387
  'kritzel-control': true,
@@ -377,7 +392,11 @@ const KritzelControls = class {
377
392
  return h("div", { class: "kritzel-divider", key: control.name });
378
393
  }
379
394
  if (control.type === 'config' && control.name === this.firstConfig?.name && this.activeControl) {
380
- return (h("div", { class: "kritzel-config-container", key: control.name }, h("kritzel-tooltip", { isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container') }, h("div", { style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (h("kritzel-control-brush-config", { tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (h("kritzel-control-text-config", { tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), h("div", { class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), style: {
395
+ return (h("div", { class: "kritzel-config-container", key: control.name }, h("kritzel-tooltip", { ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, h("div", { style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (h("kritzel-control-brush-config", { tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (h("kritzel-control-text-config", { tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), h("div", { tabIndex: 0, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
396
+ if (event.key === 'Enter') {
397
+ this.handleConfigClick?.(event);
398
+ }
399
+ }, style: {
381
400
  cursor: this.activeControl.config ? 'pointer' : 'default',
382
401
  pointerEvents: hasNoConfig ? 'none' : 'auto',
383
402
  } }, this.activeControl.tool instanceof KritzelBrushTool && (h("div", { class: "color-container" }, h("kritzel-color", { value: this.activeToolAsBrushTool?.color, size: this.activeToolAsBrushTool?.size, style: {
@@ -397,26 +416,9 @@ const KritzelCursorTrail = class {
397
416
  constructor(hostRef) {
398
417
  registerInstance(this, hostRef);
399
418
  }
400
- store;
419
+ core;
401
420
  cursorTrailPoints = [];
402
421
  isLeftButtonDown = false;
403
- trailCleanupIntervalId;
404
- TRAIL_DURATION_MS = 100;
405
- MAX_TRAIL_POINTS = 50;
406
- componentDidLoad() {
407
- this.trailCleanupIntervalId = window.setInterval(() => {
408
- const now = Date.now();
409
- const newTrailPoints = this.cursorTrailPoints.filter(p => now - p.timestamp < this.TRAIL_DURATION_MS);
410
- if (newTrailPoints.length !== this.cursorTrailPoints.length) {
411
- this.cursorTrailPoints = newTrailPoints;
412
- }
413
- }, 50);
414
- }
415
- disconnectedCallback() {
416
- if (this.trailCleanupIntervalId) {
417
- window.clearInterval(this.trailCleanupIntervalId);
418
- }
419
- }
420
422
  handleMouseDown(ev) {
421
423
  if (ev.pointerType === 'mouse') {
422
424
  if (ev.button === KritzelMouseButton.Left) {
@@ -425,7 +427,7 @@ const KritzelCursorTrail = class {
425
427
  }
426
428
  }
427
429
  if (ev.pointerType === 'touch') {
428
- if (this.store.state.pointers.size === 1) {
430
+ if (this.core.store.state.pointers.size === 1) {
429
431
  this.isLeftButtonDown = true;
430
432
  this.cursorTrailPoints = [];
431
433
  }
@@ -452,14 +454,31 @@ const KritzelCursorTrail = class {
452
454
  }
453
455
  }
454
456
  if (ev.pointerType === 'touch') {
455
- if (this.store.state.pointers.size === 0) {
457
+ if (this.core.store.state.pointers.size === 0) {
456
458
  this.isLeftButtonDown = false;
457
459
  this.cursorTrailPoints = [];
458
460
  }
459
461
  }
460
462
  }
463
+ trailCleanupIntervalId;
464
+ TRAIL_DURATION_MS = 100;
465
+ MAX_TRAIL_POINTS = 50;
466
+ componentDidLoad() {
467
+ this.trailCleanupIntervalId = window.setInterval(() => {
468
+ const now = Date.now();
469
+ const newTrailPoints = this.cursorTrailPoints.filter(p => now - p.timestamp < this.TRAIL_DURATION_MS);
470
+ if (newTrailPoints.length !== this.cursorTrailPoints.length) {
471
+ this.cursorTrailPoints = newTrailPoints;
472
+ }
473
+ }, 50);
474
+ }
475
+ disconnectedCallback() {
476
+ if (this.trailCleanupIntervalId) {
477
+ window.clearInterval(this.trailCleanupIntervalId);
478
+ }
479
+ }
461
480
  render() {
462
- return (h(Host, { key: 'c519ab89ffb793de887a870bafe8772f7584f097' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: 'db7ac0975c5a39c0b68d8fd4af4edd4d15f439f3', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
481
+ 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: {
463
482
  position: 'absolute',
464
483
  left: '0',
465
484
  top: '0',
@@ -490,7 +509,15 @@ const KritzelDropdown = class {
490
509
  this.valueChanged = createEvent(this, "valueChanged");
491
510
  }
492
511
  options = [];
512
+ optionsChanged() {
513
+ this.updateInternalValue(this.internalValue, true);
514
+ }
493
515
  value;
516
+ externalValueChanged(newValue) {
517
+ if (newValue !== this.internalValue) {
518
+ this.updateInternalValue(newValue, false);
519
+ }
520
+ }
494
521
  width;
495
522
  selectStyles = {};
496
523
  internalValue;
@@ -504,14 +531,6 @@ const KritzelDropdown = class {
504
531
  this.evaluateSuffixContent();
505
532
  this.evaluatePrefixContent();
506
533
  }
507
- externalValueChanged(newValue) {
508
- if (newValue !== this.internalValue) {
509
- this.updateInternalValue(newValue, false);
510
- }
511
- }
512
- optionsChanged() {
513
- this.updateInternalValue(this.internalValue, true);
514
- }
515
534
  updateInternalValue(proposedValue, emitChange) {
516
535
  let finalValue = proposedValue;
517
536
  if (this.options && this.options.length > 0) {
@@ -569,11 +588,11 @@ const KritzelDropdown = class {
569
588
  'has-suffix-border': this.hasSuffixContent,
570
589
  'has-prefix-border': this.hasPrefixContent,
571
590
  };
572
- return (h(Host, { key: '32c5f5a4f807c1e316c91b795c005b8d30ce6189' }, h("div", { key: 'b1cbeff18e688da4a2f7472be290b9527a619f07', class: "dropdown-wrapper" }, h("slot", { key: 'b3bbb7e21c6f5620cab41aa4b1c7206b6c75fd86', name: "prefix", ref: el => this.prefixSlotElement = el, onSlotchange: this.evaluatePrefixContent }), h("select", { key: '8b2dcdc125bee59cf29fce7c980b755e78d5816e', class: selectClasses, style: { ...this.selectStyles, width: this.width }, onInput: this.handleSelectChange }, this.options.map(option => (h("option", { value: option.value, style: option.style, selected: option.value === this.internalValue }, option.label)))), h("slot", { key: '8d83f0dea41ac959bf2392948efef33bb70d0154', name: "suffix", ref: el => this.suffixSlotElement = el, onSlotchange: this.evaluateSuffixContent }))));
591
+ return (h(Host, { key: 'f24911715685ced571843ba7be6631248c8519b7' }, h("div", { key: '520fdb74afdef8bd5228f76074e51981f44b910d', class: "dropdown-wrapper" }, h("slot", { key: 'cf6628437946b57ad0b27c066639e0b64b5a28f8', name: "prefix", ref: el => (this.prefixSlotElement = el), onSlotchange: this.evaluatePrefixContent }), h("select", { key: '3203ccd5b9c8b84e8f41bddfcb07786e879f0035', class: selectClasses, style: { ...this.selectStyles, width: this.width }, onInput: this.handleSelectChange }, this.options.map(option => (h("option", { value: option.value, style: option.style, selected: option.value === this.internalValue }, option.label)))), h("slot", { key: 'd0abb52e082db81860c09d2c48b7c065adb406f3', name: "suffix", ref: el => (this.suffixSlotElement = el), onSlotchange: this.evaluateSuffixContent }))));
573
592
  }
574
593
  static get watchers() { return {
575
- "value": ["externalValueChanged"],
576
- "options": ["optionsChanged"]
594
+ "options": ["optionsChanged"],
595
+ "value": ["externalValueChanged"]
577
596
  }; }
578
597
  };
579
598
  KritzelDropdown.style = kritzelDropdownCss;
@@ -628,13 +647,14 @@ KritzelIconRegistry.registerIcons({
628
647
  const ABSOLUTE_SCALE_MAX = 1000;
629
648
  const ABSOLUTE_SCALE_MIN = 0.0001;
630
649
 
631
- const kritzelEditorCss = "kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}kritzel-workspace-manager{position:absolute;top:14px;left:14px}kritzel-split-button{position:absolute;top:14px;left:14px;z-index:1}kritzel-controls{position:absolute;bottom:28px}";
650
+ const kritzelEditorCss = "kritzel-editor{display:flex;margin:0;position:relative;overflow:hidden;width:100%;height:100%;align-items:center;justify-content:center;touch-action:manipulation;user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}kritzel-workspace-manager{position:absolute;top:var(--kritzel-editor-workspace-manager-top, 14px);left:var(--kritzel-editor-workspace-manager-left, 14px)}kritzel-controls{position:absolute;bottom:var(--kritzel-editor-controls-bottom, 14px);transition:transform var(--kritzel-editor-controls-transition-duration, 0.1s) var(--kritzel-editor-controls-transition, ease-in-out)}kritzel-controls.keyboard-open{transform:var(--kritzel-editor-controls-transform, translateY(300%))}";
632
651
 
633
652
  const KritzelEditor = class {
634
653
  constructor(hostRef) {
635
654
  registerInstance(this, hostRef);
636
655
  this.isReady = createEvent(this, "isReady");
637
656
  }
657
+ get host() { return getElement(this); }
638
658
  scaleMax = ABSOLUTE_SCALE_MAX;
639
659
  scaleMin = ABSOLUTE_SCALE_MIN;
640
660
  controls = [
@@ -718,7 +738,6 @@ const KritzelEditor = class {
718
738
  isControlsVisible = true;
719
739
  isUtilityPanelVisible = true;
720
740
  isReady;
721
- get host() { return getElement(this); }
722
741
  isEngineReady = false;
723
742
  isControlsReady = false;
724
743
  isWorkspaceManagerReady = false;
@@ -735,6 +754,11 @@ const KritzelEditor = class {
735
754
  this.checkIsReady();
736
755
  }
737
756
  }
757
+ handleTouchStart(event) {
758
+ if (event.cancelable) {
759
+ event.preventDefault();
760
+ }
761
+ }
738
762
  async getObjectById(id) {
739
763
  return this.engineRef.getObjectById(id);
740
764
  }
@@ -762,10 +786,21 @@ const KritzelEditor = class {
762
786
  async centerObjectInViewport(object) {
763
787
  return this.engineRef.centerObjectInViewport(object);
764
788
  }
765
- handleTouchStart(event) {
766
- if (event.cancelable) {
767
- event.preventDefault();
768
- }
789
+ async createWorkspace(name, viewport) {
790
+ const workspace = new KritzelWorkspace(`workspace-${Date.now()}`, name, viewport);
791
+ return this.engineRef.createWorkspace(workspace);
792
+ }
793
+ async updateWorkspace(workspace) {
794
+ return this.engineRef.updateWorkspace(workspace);
795
+ }
796
+ async deleteWorkspace(workspace) {
797
+ return this.engineRef.deleteWorkspace(workspace);
798
+ }
799
+ async getWorkspaces() {
800
+ return this.engineRef.getWorkspaces();
801
+ }
802
+ async getActiveWorkspace() {
803
+ return this.engineRef.getActiveWorkspace();
769
804
  }
770
805
  engineRef;
771
806
  controlsRef;
@@ -773,6 +808,7 @@ const KritzelEditor = class {
773
808
  componentDidLoad() {
774
809
  this.registerCustomSvgIcons();
775
810
  this.listenForMobileKeyboard();
811
+ this.setOsSpecificCssVariables();
776
812
  }
777
813
  async checkIsReady() {
778
814
  await customElements.whenDefined('kritzel-editor');
@@ -796,12 +832,37 @@ const KritzelEditor = class {
796
832
  }
797
833
  listenForMobileKeyboard() {
798
834
  KritzelKeyboardHelper.onKeyboardVisibleChanged(isOpen => {
799
- console.log('Mobile keyboard visibility changed:', isOpen);
800
835
  this.isVirtualKeyboardOpen = isOpen;
801
836
  });
802
837
  }
838
+ setOsSpecificCssVariables() {
839
+ const os = KritzelDevicesHelper.detectOS();
840
+ switch (os) {
841
+ case 'iOS':
842
+ // iOS specific adjustments
843
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-top', '14px');
844
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-left', '14px');
845
+ this.host.style.setProperty('--kritzel-editor-controls-bottom', '14px');
846
+ this.host.style.setProperty('--kritzel-editor-controls-transition', 'cubic-bezier(0.25, 0.1, 0.25, 1.0)');
847
+ this.host.style.setProperty('--kritzel-editor-controls-transform', 'translateY(200%)');
848
+ this.host.style.setProperty('--kritzel-editor-controls-transition-duration', '0.25s');
849
+ break;
850
+ case 'Android':
851
+ // Android specific adjustments
852
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-top', '14px');
853
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-left', '14px');
854
+ this.host.style.setProperty('--kritzel-editor-controls-bottom', '24px');
855
+ break;
856
+ default:
857
+ // Default for Windows/Linux
858
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-top', '14px');
859
+ this.host.style.setProperty('--kritzel-editor-workspace-manager-left', '14px');
860
+ this.host.style.setProperty('--kritzel-editor-controls-bottom', '14px');
861
+ break;
862
+ }
863
+ }
803
864
  render() {
804
- return (h(Host, { key: '0f51215c0ede25bf8edfbf1420fc8d6c64175b8a' }, h("kritzel-workspace-manager", { key: '14affeb4c161a401d9cca32d0681d576b67b5199', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => this.activeWorkspace = event.detail, onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: '0e96fdbfbe412ea0a0bae49c693190b71e78f112', 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: '6098132ddf95b5dd4b1a1a6492b31f0ef43693c4', style: { display: this.isVirtualKeyboardOpen ? 'none' : (this.isControlsVisible ? 'flex' : 'none') }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, onIsControlsReady: () => (this.isControlsReady = true) })));
865
+ return (h(Host, { key: '17c4e1ce489a5cd359972e67105019ad64703b19' }, h("kritzel-workspace-manager", { key: '963f62afe326d33eccdabda804bc3e260aafc306', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: 'f60f67d06ce73f5f86716fc0ec68408c71100d82', 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: '1dc25c1bbb50978cfac3cdaa2d3ae0a32ca7c4f7', 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) })));
805
866
  }
806
867
  static get watchers() { return {
807
868
  "isEngineReady": ["onIsEngineReady"],
@@ -811,117 +872,119 @@ const KritzelEditor = class {
811
872
  KritzelEditor.style = kritzelEditorCss;
812
873
 
813
874
  class KritzelViewport {
814
- _store;
875
+ _core;
815
876
  initialTouchDistance = 0;
816
877
  startX = 0;
817
878
  startY = 0;
818
- constructor(store, host) {
819
- this._store = store;
820
- this._store.state.host = host;
821
- this._store.state.viewportWidth = host.clientWidth;
822
- this._store.state.viewportHeight = host.clientHeight;
823
- this._store.state.startX = 0;
824
- this._store.state.startY = 0;
825
- this._store.state.translateX = 0;
826
- this._store.state.translateY = 0;
879
+ constructor(core, host) {
880
+ this._core = core;
881
+ this._core.store.setState('host', host);
882
+ this._core.store.setState('viewportWidth', host.clientWidth);
883
+ this._core.store.setState('viewportHeight', host.clientHeight);
884
+ this._core.store.setState('startX', 0);
885
+ this._core.store.setState('startY', 0);
886
+ this._core.store.setState('translateX', 0);
887
+ this._core.store.setState('translateY', 0);
827
888
  }
828
889
  handleResize() {
829
- this._store.state.viewportWidth = this._store.state.host.clientWidth;
830
- this._store.state.viewportHeight = this._store.state.host.clientHeight;
831
- this._store.state.hasViewportChanged = true;
832
- this._store.rerender();
890
+ this._core.store.setState('viewportWidth', this._core.store.state.host.clientWidth);
891
+ this._core.store.setState('viewportHeight', this._core.store.state.host.clientHeight);
892
+ this._core.store.setState('hasViewportChanged', true);
893
+ this._core.rerender();
833
894
  }
834
895
  handlePointerDown(event) {
835
896
  if (event.pointerType === 'mouse') {
836
- const adjustedClientX = event.clientX - this._store.offsetX;
837
- const adjustedClientY = event.clientY - this._store.offsetY;
897
+ const adjustedClientX = event.clientX - this._core.store.offsetX;
898
+ const adjustedClientY = event.clientY - this._core.store.offsetY;
838
899
  if (event.button === KritzelMouseButton.Right) {
839
- this._store.state.isPanning = true;
840
- this._store.state.startX = adjustedClientX;
841
- this._store.state.startY = adjustedClientY;
900
+ this._core.store.setState('isPanning', true);
901
+ this._core.store.setState('startX', adjustedClientX);
902
+ this._core.store.setState('startY', adjustedClientY);
842
903
  }
843
904
  }
844
905
  if (event.pointerType === 'touch') {
845
- const activePointers = Array.from(this._store.state.pointers.values());
906
+ const activePointers = Array.from(this._core.store.state.pointers.values());
846
907
  if (activePointers.length === 2) {
847
- this._store.state.currentPath = null;
848
- this._store.state.isScaling = true;
849
- const firstTouchX = activePointers[0].clientX - this._store.offsetX;
850
- const firstTouchY = activePointers[0].clientY - this._store.offsetY;
851
- const secondTouchX = activePointers[1].clientX - this._store.offsetX;
852
- const secondTouchY = activePointers[1].clientY - this._store.offsetY;
908
+ this._core.store.setState('currentPath', null);
909
+ this._core.store.setState('isScaling', true);
910
+ const firstTouchX = activePointers[0].clientX - this._core.store.offsetX;
911
+ const firstTouchY = activePointers[0].clientY - this._core.store.offsetY;
912
+ const secondTouchX = activePointers[1].clientX - this._core.store.offsetX;
913
+ const secondTouchY = activePointers[1].clientY - this._core.store.offsetY;
853
914
  this.initialTouchDistance = Math.sqrt(Math.pow(firstTouchX - secondTouchX, 2) + Math.pow(firstTouchY - secondTouchY, 2));
854
915
  this.startX = (firstTouchX + secondTouchX) / 2;
855
916
  this.startY = (firstTouchY + secondTouchY) / 2;
856
- this._store.rerender();
917
+ this._core.rerender();
857
918
  }
858
919
  }
859
920
  }
860
921
  handlePointerMove(event) {
861
922
  if (event.pointerType === 'mouse') {
862
- const hostRect = this._store.state.host.getBoundingClientRect();
923
+ const hostRect = this._core.store.state.host.getBoundingClientRect();
863
924
  const xRelativeToHost = event.clientX - hostRect.left;
864
925
  const yRelativeToHost = event.clientY - hostRect.top;
865
- this._store.state.pointerX = (xRelativeToHost - this._store.state.translateX) / this._store.state.scale;
866
- this._store.state.pointerY = (yRelativeToHost - this._store.state.translateY) / this._store.state.scale;
867
- if (this._store.state.isPanning) {
868
- this._store.state.translateX -= this._store.state.startX - xRelativeToHost;
869
- this._store.state.translateY -= this._store.state.startY - yRelativeToHost;
870
- this._store.state.startX = xRelativeToHost;
871
- this._store.state.startY = yRelativeToHost;
872
- this._store.state.hasViewportChanged = true;
873
- this._store.state.skipContextMenu = true;
874
- this._store.rerender();
875
- this._store.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
926
+ this._core.store.setState('pointerX', (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale);
927
+ this._core.store.setState('pointerY', (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale);
928
+ if (this._core.store.state.isPanning) {
929
+ const dx = xRelativeToHost - this._core.store.state.startX;
930
+ const dy = yRelativeToHost - this._core.store.state.startY;
931
+ this._core.store.setState('translateX', this._core.store.state.translateX + dx);
932
+ this._core.store.setState('translateY', this._core.store.state.translateY + dy);
933
+ this._core.store.setState('startX', xRelativeToHost);
934
+ this._core.store.setState('startY', yRelativeToHost);
935
+ this._core.store.setState('hasViewportChanged', true);
936
+ this._core.store.setState('skipContextMenu', true);
937
+ this._core.rerender();
938
+ this._core.updateWorkspaceViewport(this._core.store.state.translateX, this._core.store.state.translateY, this._core.store.state.scale);
876
939
  }
877
940
  }
878
941
  if (event.pointerType === 'touch') {
879
- const hostRect = this._store.state.host.getBoundingClientRect();
942
+ const hostRect = this._core.store.state.host.getBoundingClientRect();
880
943
  const xRelativeToHost = event.clientX - hostRect.left;
881
944
  const yRelativeToHost = event.clientY - hostRect.top;
882
- this._store.state.pointerX = (xRelativeToHost - this._store.state.translateX) / this._store.state.scale;
883
- this._store.state.pointerY = (yRelativeToHost - this._store.state.translateY) / this._store.state.scale;
884
- const activePointers = Array.from(this._store.state.pointers.values());
945
+ this._core.store.setState('pointerX', (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale);
946
+ this._core.store.setState('pointerY', (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale);
947
+ const activePointers = Array.from(this._core.store.state.pointers.values());
885
948
  if (activePointers.length === 2) {
886
- const firstTouchX = activePointers[0].clientX - this._store.offsetX;
887
- const firstTouchY = activePointers[0].clientY - this._store.offsetY;
888
- const secondTouchX = activePointers[1].clientX - this._store.offsetX;
889
- const secondTouchY = activePointers[1].clientY - this._store.offsetY;
949
+ const firstTouchX = activePointers[0].clientX - this._core.store.offsetX;
950
+ const firstTouchY = activePointers[0].clientY - this._core.store.offsetY;
951
+ const secondTouchX = activePointers[1].clientX - this._core.store.offsetX;
952
+ const secondTouchY = activePointers[1].clientY - this._core.store.offsetY;
890
953
  const currentTouchDistance = Math.sqrt(Math.pow(firstTouchX - secondTouchX, 2) + Math.pow(firstTouchY - secondTouchY, 2));
891
954
  const midpointX = (firstTouchX + secondTouchX) / 2;
892
955
  const midpointY = (firstTouchY + secondTouchY) / 2;
893
956
  const scaleRatio = currentTouchDistance / this.initialTouchDistance;
894
- const newScale = this._store.state.scale * scaleRatio;
895
- if (newScale > this._store.state.scaleMax || newScale < this._store.state.scaleMin) {
896
- this._store.state.translateX += midpointX - this.startX;
897
- this._store.state.translateY += midpointY - this.startY;
957
+ const newScale = this._core.store.state.scale * scaleRatio;
958
+ if (newScale > this._core.store.state.scaleMax || newScale < this._core.store.state.scaleMin) {
959
+ this._core.store.setState('translateX', this._core.store.state.translateX + midpointX - this.startX);
960
+ this._core.store.setState('translateY', this._core.store.state.translateY + midpointY - this.startY);
898
961
  }
899
962
  else {
900
- const translateXAdjustment = (midpointX - this._store.state.translateX) * (scaleRatio - 1);
901
- const translateYAdjustment = (midpointY - this._store.state.translateY) * (scaleRatio - 1);
902
- this._store.state.translateX += midpointX - this.startX - translateXAdjustment;
903
- this._store.state.translateY += midpointY - this.startY - translateYAdjustment;
904
- this._store.state.scale = newScale;
963
+ const translateXAdjustment = (midpointX - this._core.store.state.translateX) * (scaleRatio - 1);
964
+ const translateYAdjustment = (midpointY - this._core.store.state.translateY) * (scaleRatio - 1);
965
+ this._core.store.setState('translateX', this._core.store.state.translateX + midpointX - this.startX - translateXAdjustment);
966
+ this._core.store.setState('translateY', this._core.store.state.translateY + midpointY - this.startY - translateYAdjustment);
967
+ this._core.store.setState('scale', newScale);
905
968
  this.initialTouchDistance = currentTouchDistance;
906
969
  }
907
970
  this.startX = midpointX;
908
971
  this.startY = midpointY;
909
- this._store.state.hasViewportChanged = true;
910
- this._store.rerender();
911
- this._store.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
972
+ this._core.store.setState('hasViewportChanged', true);
973
+ this._core.rerender();
974
+ this._core.updateWorkspaceViewport(this._core.store.state.translateX, this._core.store.state.translateY, this._core.store.state.scale);
912
975
  }
913
976
  }
914
977
  }
915
978
  handlePointerUp(event) {
916
979
  if (event.pointerType === 'mouse') {
917
- if (this._store.state.isPanning) {
918
- this._store.state.isPanning = false;
919
- this._store.rerender();
980
+ if (this._core.store.state.isPanning) {
981
+ this._core.store.setState('isPanning', false);
982
+ this._core.rerender();
920
983
  }
921
984
  }
922
985
  if (event.pointerType === 'touch') {
923
- this._store.state.isScaling = false;
924
- this._store.rerender();
986
+ this._core.store.setState('isScaling', false);
987
+ this._core.rerender();
925
988
  }
926
989
  }
927
990
  handleWheel(event) {
@@ -934,188 +997,169 @@ class KritzelViewport {
934
997
  }
935
998
  }
936
999
  handleZoom(event) {
937
- const rect = this._store.state.host.getBoundingClientRect();
1000
+ this._core.store.setState('isScaling', true);
1001
+ const rect = this._core.store.state.host.getBoundingClientRect();
938
1002
  const xRelativeToHost = event.clientX - rect.left;
939
1003
  const yRelativeToHost = event.clientY - rect.top;
940
- this._store.state.pointerX = (xRelativeToHost - this._store.state.translateX) / this._store.state.scale;
941
- this._store.state.pointerY = (yRelativeToHost - this._store.state.translateY) / this._store.state.scale;
942
- const delta = event.deltaY > 0 ? -this._store.state.scaleStep * this._store.state.scale : this._store.state.scaleStep * this._store.state.scale;
943
- const newScale = Math.min(this._store.state.scaleMax, Math.max(this._store.state.scaleMin, this._store.state.scale + delta));
944
- const scaleRatio = newScale / this._store.state.scale;
945
- const translateXAdjustment = (xRelativeToHost - this._store.state.translateX) * (scaleRatio - 1);
946
- const translateYAdjustment = (yRelativeToHost - this._store.state.translateY) * (scaleRatio - 1);
947
- this._store.state.scale = newScale;
948
- this._store.state.translateX -= translateXAdjustment;
949
- this._store.state.translateY -= translateYAdjustment;
950
- this._store.state.hasViewportChanged = true;
951
- this._store.rerender();
952
- this._store.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
1004
+ this._core.store.setState('pointerX', (xRelativeToHost - this._core.store.state.translateX) / this._core.store.state.scale);
1005
+ this._core.store.setState('pointerY', (yRelativeToHost - this._core.store.state.translateY) / this._core.store.state.scale);
1006
+ const delta = event.deltaY > 0 ? -this._core.store.state.scaleStep * this._core.store.state.scale : this._core.store.state.scaleStep * this._core.store.state.scale;
1007
+ const newScale = Math.min(this._core.store.state.scaleMax, Math.max(this._core.store.state.scaleMin, this._core.store.state.scale + delta));
1008
+ const scaleRatio = newScale / this._core.store.state.scale;
1009
+ const translateXAdjustment = (xRelativeToHost - this._core.store.state.translateX) * (scaleRatio - 1);
1010
+ const translateYAdjustment = (yRelativeToHost - this._core.store.state.translateY) * (scaleRatio - 1);
1011
+ this._core.store.setState('scale', newScale);
1012
+ this._core.store.setState('translateX', this._core.store.state.translateX - translateXAdjustment);
1013
+ this._core.store.setState('translateY', this._core.store.state.translateY - translateYAdjustment);
1014
+ this._core.store.setState('hasViewportChanged', true);
1015
+ this._core.rerender();
1016
+ this._core.updateWorkspaceViewport(this._core.store.state.translateX, this._core.store.state.translateY, this._core.store.state.scale);
1017
+ setTimeout(() => {
1018
+ this._core.store.setState('isScaling', false);
1019
+ this._core.rerender();
1020
+ }, 300);
953
1021
  }
954
1022
  handlePan(event) {
1023
+ this._core.store.setState('isPanning', true);
955
1024
  const panSpeed = 0.8;
956
- this._store.state.translateX -= event.deltaX * panSpeed;
957
- this._store.state.translateY -= event.deltaY * panSpeed;
958
- this._store.state.hasViewportChanged = true;
959
- this._store.rerender();
960
- this._store.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
961
- }
962
- }
963
-
964
- class UpdateViewportCommand extends KritzelBaseCommand {
965
- currentViewport;
966
- previousViewport;
967
- constructor(store, initiator, previousViewport, skipHistory = false) {
968
- super(store, initiator, skipHistory);
969
- this.previousViewport = previousViewport;
970
- this.currentViewport = {
971
- scale: this._store.state.scale,
972
- translateX: this._store.state.translateX,
973
- translateY: this._store.state.translateY,
974
- };
975
- }
976
- execute() {
977
- this._store.state.scale = this.currentViewport.scale;
978
- this._store.state.translateX = this.currentViewport.translateX;
979
- this._store.state.translateY = this.currentViewport.translateY;
980
- }
981
- undo() {
982
- this._store.state.scale = this.previousViewport.scale;
983
- this._store.state.translateX = this.previousViewport.translateX;
984
- this._store.state.translateY = this.previousViewport.translateY;
1025
+ this._core.store.setState('translateX', this._core.store.state.translateX - event.deltaX * panSpeed);
1026
+ this._core.store.setState('translateY', this._core.store.state.translateY - event.deltaY * panSpeed);
1027
+ this._core.store.setState('hasViewportChanged', true);
1028
+ this._core.rerender();
1029
+ this._core.updateWorkspaceViewport(this._core.store.state.translateX, this._core.store.state.translateY, this._core.store.state.scale);
1030
+ setTimeout(() => {
1031
+ this._core.store.setState('isPanning', false);
1032
+ this._core.rerender();
1033
+ }, 300);
985
1034
  }
986
1035
  }
987
1036
 
988
- class KritzelCircularBuffer {
989
- buffer;
990
- capacity;
991
- head = 0;
992
- tail = 0;
993
- size = 0;
994
- constructor(capacity) {
995
- this.capacity = capacity;
996
- this.buffer = new Array(capacity).fill(null);
1037
+ class KritzelKeyHandler extends KritzelBaseHandler {
1038
+ constructor(core) {
1039
+ super(core);
997
1040
  }
998
- add(item) {
999
- this.buffer[this.head] = item;
1000
- this.head = (this.head + 1) % this.capacity;
1001
- if (this.size < this.capacity) {
1002
- this.size++;
1041
+ handleKeyDown(event) {
1042
+ this._core.store.setState('isCtrlKeyPressed', event.ctrlKey);
1043
+ if (this._core.store.state.isCtrlKeyPressed) {
1044
+ event.preventDefault();
1003
1045
  }
1004
- else {
1005
- this.tail = (this.tail + 1) % this.capacity;
1046
+ if (event.key === 'Escape' && this._core.store.state.selectionGroup) {
1047
+ this._core.clearSelection();
1006
1048
  }
1007
- }
1008
- pop() {
1009
- if (this.size === 0) {
1010
- return null;
1049
+ if (event.key === 'Delete' && this._core.store.state.selectionGroup) {
1050
+ this._core.delete();
1011
1051
  }
1012
- this.head = (this.head - 1 + this.capacity) % this.capacity;
1013
- const item = this.buffer[this.head];
1014
- this.buffer[this.head] = null;
1015
- this.size--;
1016
- return item;
1017
- }
1018
- peek() {
1019
- if (this.size === 0) {
1020
- return null;
1052
+ if (event.key === 'z' && event.ctrlKey) {
1053
+ this._core.history.undo();
1054
+ }
1055
+ if (event.key === 'y' && event.ctrlKey) {
1056
+ this._core.history.redo();
1057
+ }
1058
+ if (event.key === 's' && event.ctrlKey) {
1059
+ this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1060
+ this._core.deselectAllObjects();
1061
+ }
1062
+ if (event.key === 'b' && event.ctrlKey) {
1063
+ this._core.store.setState('activeTool', KritzelToolRegistry.getTool('brush'));
1064
+ this._core.deselectAllObjects();
1065
+ }
1066
+ if (event.key === 'e' && event.ctrlKey) {
1067
+ this._core.store.setState('activeTool', KritzelToolRegistry.getTool('eraser'));
1068
+ this._core.deselectAllObjects();
1069
+ }
1070
+ if (event.key === 'i' && event.ctrlKey) {
1071
+ this._core.store.setState('activeTool', KritzelToolRegistry.getTool('image'));
1072
+ this._core.deselectAllObjects();
1073
+ }
1074
+ if (event.key === 'x' && event.ctrlKey) {
1075
+ this._core.store.setState('activeTool', KritzelToolRegistry.getTool('text'));
1076
+ this._core.deselectAllObjects();
1077
+ }
1078
+ if (event.key === 'c' && event.ctrlKey && this._core.store.state.selectionGroup) {
1079
+ this._core.copy();
1080
+ this._core.rerender();
1081
+ }
1082
+ if (event.key === 'v' && event.ctrlKey && this._core.store.state.copiedObjects) {
1083
+ this._core.paste();
1084
+ }
1085
+ if (event.key === '+' && event.ctrlKey && this._core.store.state.selectionGroup) {
1086
+ this._core.bringForward();
1087
+ }
1088
+ if (event.key === '-' && event.ctrlKey && this._core.store.state.selectionGroup) {
1089
+ this._core.sendBackward();
1090
+ }
1091
+ if (event.key === '*' && event.shiftKey && this._core.store.state.selectionGroup) {
1092
+ this._core.bringToFront();
1093
+ }
1094
+ if (event.key === '_' && event.shiftKey && this._core.store.state.selectionGroup) {
1095
+ this._core.sendToBack();
1096
+ }
1097
+ if (event.key === 'a' && event.ctrlKey && this._core.store.state.activeText) {
1098
+ this._core.store.state.activeText.selectAll();
1099
+ }
1100
+ if (event.key === 'v' && event.ctrlKey && this._core.store.state.activeText) {
1101
+ this._core.store.state.activeText.insertFromClipboard();
1021
1102
  }
1022
- const lastIndex = (this.head - 1 + this.capacity) % this.capacity;
1023
- return this.buffer[lastIndex];
1024
- }
1025
- isEmpty() {
1026
- return this.size === 0;
1027
1103
  }
1028
- clear() {
1029
- this.buffer.fill(null);
1030
- this.head = 0;
1031
- this.tail = 0;
1032
- this.size = 0;
1104
+ handleKeyUp(event) {
1105
+ this._core.store.setState('isCtrlKeyPressed', event.ctrlKey);
1033
1106
  }
1034
1107
  }
1035
1108
 
1036
- class KritzelHistory {
1037
- _store;
1038
- undoStack;
1039
- redoStack;
1040
- previousViewport;
1041
- constructor(store) {
1042
- this._store = store;
1043
- this.undoStack = new KritzelCircularBuffer(this._store.state.historyBufferSize);
1044
- this.redoStack = new KritzelCircularBuffer(this._store.state.historyBufferSize);
1045
- this.previousViewport = {
1046
- scale: this._store.state.scale,
1047
- scaleStep: this._store.state.scaleStep,
1048
- translateX: this._store.state.translateX,
1049
- translateY: this._store.state.translateY,
1050
- };
1051
- }
1052
- reset() {
1053
- this.undoStack.clear();
1054
- this.redoStack.clear();
1055
- this.previousViewport = {
1056
- scale: this._store.state.scale,
1057
- scaleStep: this._store.state.scaleStep,
1058
- translateX: this._store.state.translateX,
1059
- translateY: this._store.state.translateY
1060
- };
1109
+ class KritzelContextMenuHandler extends KritzelBaseHandler {
1110
+ globalContextMenuItems = [];
1111
+ objectContextMenuItems = [];
1112
+ constructor(core, globalContextMenuItems, objectContextMenuItems) {
1113
+ super(core);
1114
+ this.globalContextMenuItems = globalContextMenuItems;
1115
+ this.objectContextMenuItems = objectContextMenuItems;
1061
1116
  }
1062
- executeCommand(command) {
1063
- if (this._store.state.hasViewportChanged) {
1064
- this.addUpdateViewportCommand();
1065
- }
1066
- command.execute();
1067
- if (command.skipHistory === false) {
1068
- if (this._store.state.debugInfo.logCommands) {
1069
- console.info('add', command);
1070
- }
1071
- this.undoStack.add(command);
1072
- if (this.redoStack.isEmpty() === false) {
1073
- this.redoStack.clear();
1074
- }
1117
+ handleContextMenu(event) {
1118
+ if (!(this._core.store.state.activeTool instanceof KritzelSelectionTool)) {
1119
+ return;
1075
1120
  }
1076
- this._store.rerender();
1077
- }
1078
- undo() {
1079
- if (this._store.state.hasViewportChanged) {
1080
- const command = new UpdateViewportCommand(this._store, this, this.previousViewport);
1081
- command.undo();
1082
- this._store.state.hasViewportChanged = false;
1083
- this._store.rerender();
1121
+ if (this._core.store.state.skipContextMenu) {
1122
+ this._core.store.setState('skipContextMenu', false);
1084
1123
  return;
1085
1124
  }
1086
- const command = this.undoStack.pop();
1087
- if (command) {
1088
- command.undo();
1089
- if (this._store.state.debugInfo.logCommands)
1090
- console.info('undo', command);
1091
- this.redoStack.add(command);
1125
+ const selectedObject = this._core.getObjectFromPointerEvent(event, '.object');
1126
+ if (selectedObject && !(selectedObject instanceof KritzelSelectionGroup)) {
1127
+ const selectionGroup = KritzelSelectionGroup.create(this._core);
1128
+ selectionGroup.addOrRemove(selectedObject);
1129
+ selectionGroup.isSelected = true;
1130
+ selectionGroup.rotation = selectedObject.rotation;
1131
+ this._core.store.setState('isSelecting', false);
1132
+ const batch = new BatchCommand(this._core, this, [
1133
+ new RemoveSelectionGroupCommand(this._core, this._core.store.state.selectionGroup),
1134
+ new AddSelectionGroupCommand(this._core, this, selectionGroup),
1135
+ ]);
1136
+ this._core.history.executeCommand(batch);
1137
+ }
1138
+ this._core.store.setState('contextMenuItems', this._core.store.state.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems);
1139
+ let x = event.clientX - this._core.store.offsetX;
1140
+ let y = event.clientY - this._core.store.offsetY;
1141
+ const menuWidthEstimate = 150;
1142
+ const menuHeightEstimate = 200;
1143
+ const margin = 10;
1144
+ if (x + menuWidthEstimate > window.innerWidth - margin) {
1145
+ x = window.innerWidth - menuWidthEstimate - margin;
1092
1146
  }
1093
- this._store.rerender();
1094
- }
1095
- redo() {
1096
- const command = this.redoStack.pop();
1097
- if (command) {
1098
- command.execute();
1099
- if (this._store.state.debugInfo.logCommands)
1100
- console.info('redo', command);
1101
- this.undoStack.add(command);
1147
+ if (y + menuHeightEstimate > window.innerHeight - margin) {
1148
+ y = window.innerHeight - menuHeightEstimate - margin;
1102
1149
  }
1103
- this._store.rerender();
1150
+ x = Math.max(margin, x);
1151
+ y = Math.max(margin, y);
1152
+ this._core.store.setState('contextMenuX', x);
1153
+ this._core.store.setState('contextMenuY', y);
1154
+ this._core.store.setState('isContextMenuVisible', true);
1155
+ this._core.store.setState('isEnabled', false);
1156
+ this._core.rerender();
1104
1157
  }
1105
- addUpdateViewportCommand() {
1106
- const command = new UpdateViewportCommand(this._store, this, this.previousViewport);
1107
- command.execute();
1108
- this.undoStack.add(command);
1109
- if (this.redoStack.isEmpty() === false) {
1110
- this.redoStack.clear();
1111
- }
1112
- this._store.state.hasViewportChanged = false;
1113
- this.previousViewport = {
1114
- scale: this._store.state.scale,
1115
- scaleStep: this._store.state.scaleStep,
1116
- translateX: this._store.state.translateX,
1117
- translateY: this._store.state.translateY,
1118
- };
1158
+ }
1159
+
1160
+ class KritzelClassHelper {
1161
+ static isInstanceOf(object, className) {
1162
+ return !!object && object.__class__ === className;
1119
1163
  }
1120
1164
  }
1121
1165
 
@@ -1134,7 +1178,6 @@ const DEFAULT_ENGINE_STATE = {
1134
1178
  isEnabled: true,
1135
1179
  isScaling: false,
1136
1180
  isPanning: false,
1137
- isFocused: false,
1138
1181
  isSelecting: false,
1139
1182
  isResizing: false,
1140
1183
  isResizeHandleSelected: false,
@@ -1197,7 +1240,7 @@ class KritzelDatabase {
1197
1240
  return;
1198
1241
  }
1199
1242
  if (this.isLoggingEnabled) {
1200
- console.log(`[IndexedDB] Opening database: ${this.dbName}, version: ${this.dbVersion}`);
1243
+ console.info(`[IndexedDB] Opening database: ${this.dbName}, version: ${this.dbVersion}`);
1201
1244
  }
1202
1245
  const request = indexedDB.open(this.dbName, this.dbVersion);
1203
1246
  request.onerror = () => {
@@ -1207,25 +1250,25 @@ class KritzelDatabase {
1207
1250
  request.onsuccess = () => {
1208
1251
  this.db = request.result;
1209
1252
  if (this.isLoggingEnabled) {
1210
- console.log(`[IndexedDB] Database opened successfully.`);
1253
+ console.info(`[IndexedDB] Database opened successfully.`);
1211
1254
  }
1212
1255
  resolve();
1213
1256
  };
1214
1257
  request.onupgradeneeded = event => {
1215
1258
  if (this.isLoggingEnabled) {
1216
- console.log(`[IndexedDB] Upgrade needed for database: ${this.dbName}`);
1259
+ console.info(`[IndexedDB] Upgrade needed for database: ${this.dbName}`);
1217
1260
  }
1218
1261
  const db = event.target.result;
1219
1262
  stores.forEach(storeConfig => {
1220
1263
  if (!db.objectStoreNames.contains(storeConfig.name)) {
1221
1264
  if (this.isLoggingEnabled) {
1222
- console.log(`[IndexedDB] Creating store: ${storeConfig.name}`);
1265
+ console.info(`[IndexedDB] Creating store: ${storeConfig.name}`);
1223
1266
  }
1224
1267
  const store = db.createObjectStore(storeConfig.name, storeConfig.options);
1225
1268
  if (storeConfig.indices) {
1226
1269
  storeConfig.indices.forEach(index => {
1227
1270
  if (this.isLoggingEnabled) {
1228
- console.log(`[IndexedDB] Creating index: ${index.name} on store: ${storeConfig.name}`);
1271
+ console.info(`[IndexedDB] Creating index: ${index.name} on store: ${storeConfig.name}`);
1229
1272
  }
1230
1273
  store.createIndex(index.name, index.keyPath, index.options);
1231
1274
  });
@@ -1238,7 +1281,7 @@ class KritzelDatabase {
1238
1281
  close() {
1239
1282
  if (this.db) {
1240
1283
  if (this.isLoggingEnabled) {
1241
- console.log(`[IndexedDB] Closing database: ${this.dbName}`);
1284
+ console.info(`[IndexedDB] Closing database: ${this.dbName}`);
1242
1285
  }
1243
1286
  this.db.close();
1244
1287
  this.db = null;
@@ -1246,43 +1289,51 @@ class KritzelDatabase {
1246
1289
  }
1247
1290
  async add(storeName, item) {
1248
1291
  if (this.isLoggingEnabled) {
1249
- console.log('[IndexedDB] Add:', { storeName, item });
1292
+ console.info('[IndexedDB] Add:', { storeName, item });
1293
+ }
1294
+ if (item.serialize === undefined) {
1295
+ throw new Error('Item does not implement KritzelSerializable interface.');
1250
1296
  }
1251
- return this.executeTransaction(storeName, 'readwrite', store => store.add(item));
1297
+ const serializedItem = item.serialize();
1298
+ return this.executeTransaction(storeName, 'readwrite', store => store.add(serializedItem));
1252
1299
  }
1253
1300
  async get(storeName, key) {
1254
1301
  if (this.isLoggingEnabled) {
1255
- console.log('[IndexedDB] Get:', { storeName, key });
1302
+ console.info('[IndexedDB] Get:', { storeName, key });
1256
1303
  }
1257
1304
  return this.executeTransaction(storeName, 'readonly', store => store.get(key));
1258
1305
  }
1259
1306
  async getAll(storeName) {
1260
1307
  if (this.isLoggingEnabled) {
1261
- console.log('[IndexedDB] GetAll:', { storeName });
1308
+ console.info('[IndexedDB] GetAll:', { storeName });
1262
1309
  }
1263
1310
  return this.executeTransaction(storeName, 'readonly', store => store.getAll());
1264
1311
  }
1265
1312
  async update(storeName, item) {
1266
1313
  if (this.isLoggingEnabled) {
1267
- console.log('[IndexedDB] Update:', { storeName, item });
1314
+ console.info('[IndexedDB] Update:', { storeName, item });
1268
1315
  }
1269
- return this.executeTransaction(storeName, 'readwrite', store => store.put(item));
1316
+ if (item.serialize === undefined) {
1317
+ throw new Error('Item does not implement KritzelSerializable interface.');
1318
+ }
1319
+ const serializedItem = item.serialize();
1320
+ return this.executeTransaction(storeName, 'readwrite', store => store.put(serializedItem));
1270
1321
  }
1271
1322
  async delete(storeName, key) {
1272
1323
  if (this.isLoggingEnabled) {
1273
- console.log('[IndexedDB] Delete:', { storeName, key });
1324
+ console.info('[IndexedDB] Delete:', { storeName, key });
1274
1325
  }
1275
1326
  return this.executeTransaction(storeName, 'readwrite', store => store.delete(key));
1276
1327
  }
1277
1328
  async deleteByRange(storeName, range) {
1278
1329
  if (this.isLoggingEnabled) {
1279
- console.log('[IndexedDB] DeleteByRange:', { storeName, range });
1330
+ console.info('[IndexedDB] DeleteByRange:', { storeName, range });
1280
1331
  }
1281
1332
  return this.executeTransaction(storeName, 'readwrite', store => store.delete(range));
1282
1333
  }
1283
1334
  async getAllByRange(storeName, range) {
1284
1335
  if (this.isLoggingEnabled) {
1285
- console.log('[IndexedDB] GetAllByRange:', { storeName, range });
1336
+ console.info('[IndexedDB] GetAllByRange:', { storeName, range });
1286
1337
  }
1287
1338
  return this.executeTransaction(storeName, 'readonly', store => {
1288
1339
  return store.getAll(range);
@@ -1290,7 +1341,7 @@ class KritzelDatabase {
1290
1341
  }
1291
1342
  async getAllByIndex(storeName, indexName, query) {
1292
1343
  if (this.isLoggingEnabled) {
1293
- console.log('[IndexedDB] GetAllByIndex:', { storeName, indexName, query });
1344
+ console.info('[IndexedDB] GetAllByIndex:', { storeName, indexName, query });
1294
1345
  }
1295
1346
  return this.executeTransaction(storeName, 'readonly', store => {
1296
1347
  const index = store.index(indexName);
@@ -1326,7 +1377,7 @@ class KritzelDatabase {
1326
1377
  }
1327
1378
  const storeNames = await this.extractStoreNamesFromActions(actions);
1328
1379
  if (this.isLoggingEnabled) {
1329
- console.log('[IndexedDB] Starting batch transaction:', { storeNames });
1380
+ console.info('[IndexedDB] Starting batch transaction:', { storeNames });
1330
1381
  }
1331
1382
  return new Promise((resolve, reject) => {
1332
1383
  const transaction = this.db.transaction(storeNames, 'readwrite');
@@ -1344,13 +1395,13 @@ class KritzelDatabase {
1344
1395
  executeTransaction: (storeName, mode, action) => {
1345
1396
  return new Promise((resolveRequest, rejectRequest) => {
1346
1397
  if (this.isLoggingEnabled) {
1347
- console.log('[IndexedDB] Executing batch action:', { storeName, mode });
1398
+ console.info('[IndexedDB] Executing batch action:', { storeName, mode });
1348
1399
  }
1349
1400
  const store = transaction.objectStore(storeName);
1350
1401
  const request = action(store);
1351
1402
  request.onsuccess = () => {
1352
1403
  if (this.isLoggingEnabled) {
1353
- console.log('[IndexedDB] Batch action request successful:', { result: request.result });
1404
+ console.info('[IndexedDB] Batch action request successful:', { result: request.result });
1354
1405
  }
1355
1406
  resolveRequest(request.result);
1356
1407
  };
@@ -1363,7 +1414,7 @@ class KritzelDatabase {
1363
1414
  };
1364
1415
  transaction.oncomplete = () => {
1365
1416
  if (this.isLoggingEnabled) {
1366
- console.log('[IndexedDB] Batch transaction complete.');
1417
+ console.info('[IndexedDB] Batch transaction complete.');
1367
1418
  }
1368
1419
  Promise.all(promises).then(() => resolve(results));
1369
1420
  };
@@ -1408,6 +1459,164 @@ class KritzelDatabase {
1408
1459
  }
1409
1460
  }
1410
1461
 
1462
+ class UpdateViewportCommand extends KritzelBaseCommand {
1463
+ currentViewport;
1464
+ previousViewport;
1465
+ constructor(core, initiator, previousViewport, skipHistory = false) {
1466
+ super(core, initiator, skipHistory);
1467
+ this.previousViewport = previousViewport;
1468
+ this.currentViewport = {
1469
+ scale: this._core.store.state.scale,
1470
+ translateX: this._core.store.state.translateX,
1471
+ translateY: this._core.store.state.translateY,
1472
+ };
1473
+ }
1474
+ execute() {
1475
+ this._core.store.setState('scale', this.currentViewport.scale);
1476
+ this._core.store.setState('translateX', this.currentViewport.translateX);
1477
+ this._core.store.setState('translateY', this.currentViewport.translateY);
1478
+ }
1479
+ undo() {
1480
+ this._core.store.setState('scale', this.previousViewport.scale);
1481
+ this._core.store.setState('translateX', this.previousViewport.translateX);
1482
+ this._core.store.setState('translateY', this.previousViewport.translateY);
1483
+ }
1484
+ }
1485
+
1486
+ class KritzelCircularBuffer {
1487
+ buffer;
1488
+ capacity;
1489
+ head = 0;
1490
+ tail = 0;
1491
+ size = 0;
1492
+ constructor(capacity) {
1493
+ this.capacity = capacity;
1494
+ this.buffer = new Array(capacity).fill(null);
1495
+ }
1496
+ add(item) {
1497
+ this.buffer[this.head] = item;
1498
+ this.head = (this.head + 1) % this.capacity;
1499
+ if (this.size < this.capacity) {
1500
+ this.size++;
1501
+ }
1502
+ else {
1503
+ this.tail = (this.tail + 1) % this.capacity;
1504
+ }
1505
+ }
1506
+ pop() {
1507
+ if (this.size === 0) {
1508
+ return null;
1509
+ }
1510
+ this.head = (this.head - 1 + this.capacity) % this.capacity;
1511
+ const item = this.buffer[this.head];
1512
+ this.buffer[this.head] = null;
1513
+ this.size--;
1514
+ return item;
1515
+ }
1516
+ peek() {
1517
+ if (this.size === 0) {
1518
+ return null;
1519
+ }
1520
+ const lastIndex = (this.head - 1 + this.capacity) % this.capacity;
1521
+ return this.buffer[lastIndex];
1522
+ }
1523
+ isEmpty() {
1524
+ return this.size === 0;
1525
+ }
1526
+ clear() {
1527
+ this.buffer.fill(null);
1528
+ this.head = 0;
1529
+ this.tail = 0;
1530
+ this.size = 0;
1531
+ }
1532
+ }
1533
+
1534
+ class KritzelHistory {
1535
+ _core;
1536
+ undoStack;
1537
+ redoStack;
1538
+ previousViewport;
1539
+ constructor(core) {
1540
+ this._core = core;
1541
+ this.undoStack = new KritzelCircularBuffer(this._core.store.state.historyBufferSize);
1542
+ this.redoStack = new KritzelCircularBuffer(this._core.store.state.historyBufferSize);
1543
+ this.previousViewport = {
1544
+ scale: this._core.store.state.scale,
1545
+ scaleStep: this._core.store.state.scaleStep,
1546
+ translateX: this._core.store.state.translateX,
1547
+ translateY: this._core.store.state.translateY,
1548
+ };
1549
+ }
1550
+ reset() {
1551
+ this.undoStack.clear();
1552
+ this.redoStack.clear();
1553
+ this.previousViewport = {
1554
+ scale: this._core.store.state.scale,
1555
+ scaleStep: this._core.store.state.scaleStep,
1556
+ translateX: this._core.store.state.translateX,
1557
+ translateY: this._core.store.state.translateY
1558
+ };
1559
+ }
1560
+ executeCommand(command) {
1561
+ if (this._core.store.state.hasViewportChanged) {
1562
+ this.addUpdateViewportCommand();
1563
+ }
1564
+ command.execute();
1565
+ if (command.skipHistory === false) {
1566
+ if (this._core.store.state.debugInfo.logCommands) {
1567
+ console.info('add', command);
1568
+ }
1569
+ this.undoStack.add(command);
1570
+ if (this.redoStack.isEmpty() === false) {
1571
+ this.redoStack.clear();
1572
+ }
1573
+ }
1574
+ this._core.rerender();
1575
+ }
1576
+ undo() {
1577
+ if (this._core.store.state.hasViewportChanged) {
1578
+ const command = new UpdateViewportCommand(this._core, this, this.previousViewport);
1579
+ command.undo();
1580
+ this._core.store.setState('hasViewportChanged', false);
1581
+ this._core.rerender();
1582
+ return;
1583
+ }
1584
+ const command = this.undoStack.pop();
1585
+ if (command) {
1586
+ command.undo();
1587
+ if (this._core.store.state.debugInfo.logCommands)
1588
+ console.info('undo', command);
1589
+ this.redoStack.add(command);
1590
+ }
1591
+ this._core.rerender();
1592
+ }
1593
+ redo() {
1594
+ const command = this.redoStack.pop();
1595
+ if (command) {
1596
+ command.execute();
1597
+ if (this._core.store.state.debugInfo.logCommands)
1598
+ console.info('redo', command);
1599
+ this.undoStack.add(command);
1600
+ }
1601
+ this._core.rerender();
1602
+ }
1603
+ addUpdateViewportCommand() {
1604
+ const command = new UpdateViewportCommand(this._core, this, this.previousViewport);
1605
+ command.execute();
1606
+ this.undoStack.add(command);
1607
+ if (this.redoStack.isEmpty() === false) {
1608
+ this.redoStack.clear();
1609
+ }
1610
+ this._core.store.setState('hasViewportChanged', false);
1611
+ this.previousViewport = {
1612
+ scale: this._core.store.state.scale,
1613
+ scaleStep: this._core.store.state.scaleStep,
1614
+ translateX: this._core.store.state.translateX,
1615
+ translateY: this._core.store.state.translateY,
1616
+ };
1617
+ }
1618
+ }
1619
+
1411
1620
  class KritzelObjectMap {
1412
1621
  map;
1413
1622
  constructor() {
@@ -1452,18 +1661,8 @@ class KritzelObjectMap {
1452
1661
  }
1453
1662
 
1454
1663
  class KritzelStore {
1455
- _kritzelEngine;
1456
1664
  _state;
1457
- _history;
1458
- _database;
1459
1665
  _listeners = new Map();
1460
- objects = [];
1461
- get history() {
1462
- return this._history;
1463
- }
1464
- get database() {
1465
- return this._database;
1466
- }
1467
1666
  get state() {
1468
1667
  return this._state;
1469
1668
  }
@@ -1479,18 +1678,58 @@ class KritzelStore {
1479
1678
  get offsetX() {
1480
1679
  return this._state.host.getBoundingClientRect().left;
1481
1680
  }
1482
- get offsetY() {
1483
- return this._state.host.getBoundingClientRect().top;
1681
+ get offsetY() {
1682
+ return this._state.host.getBoundingClientRect().top;
1683
+ }
1684
+ get isDisabled() {
1685
+ return this._state.isEnabled === false || this._state.isReady === false || this._state.activeWorkspace === null;
1686
+ }
1687
+ constructor(state) {
1688
+ this._state = state;
1689
+ this._state.objectsMap = new KritzelObjectMap();
1690
+ }
1691
+ onStateChange(property, listener) {
1692
+ if (!this._listeners.has(property)) {
1693
+ this._listeners.set(property, new Set());
1694
+ }
1695
+ this._listeners.get(property).add(listener);
1696
+ }
1697
+ getState(property) {
1698
+ return this._state[property];
1699
+ }
1700
+ setState(property, value) {
1701
+ const oldValue = this._state[property];
1702
+ if (oldValue !== value) {
1703
+ this._state[property] = value;
1704
+ if (this._listeners.has(property)) {
1705
+ this._listeners.get(property).forEach(listener => listener(value, oldValue, String(property)));
1706
+ }
1707
+ }
1708
+ }
1709
+ }
1710
+
1711
+ class KritzelCore {
1712
+ _kritzelEngine;
1713
+ _store;
1714
+ _history;
1715
+ _database;
1716
+ get engine() {
1717
+ return this._kritzelEngine;
1718
+ }
1719
+ get history() {
1720
+ return this._history;
1721
+ }
1722
+ get database() {
1723
+ return this._database;
1484
1724
  }
1485
- get isDisabled() {
1486
- return this._state.isEnabled === false || this._state.isReady === false || this._state.activeWorkspace === null;
1725
+ get store() {
1726
+ return this._store;
1487
1727
  }
1488
1728
  constructor(kritzelEngine) {
1489
- this._state = DEFAULT_ENGINE_STATE;
1490
1729
  this._kritzelEngine = kritzelEngine;
1730
+ this._store = new KritzelStore(DEFAULT_ENGINE_STATE);
1491
1731
  this._history = new KritzelHistory(this);
1492
- this._database = new KritzelDatabase('kritzelDB', 1, this._state.debugInfo.logDatabase);
1493
- this._state.objectsMap = new KritzelObjectMap();
1732
+ this._database = new KritzelDatabase('kritzelDB', 1, this._store.state.debugInfo.logDatabase);
1494
1733
  }
1495
1734
  async initializeDatabase() {
1496
1735
  await this._database.open([
@@ -1506,52 +1745,50 @@ class KritzelStore {
1506
1745
  const workspaces = await this.getWorkspaces();
1507
1746
  const mostRecentWorkspace = [...workspaces].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];
1508
1747
  const fallbackWorkspace = new KritzelWorkspace(ObjectHelper.generateUUID(), 'New Workspace');
1509
- this._state.activeWorkspace = workspace ?? mostRecentWorkspace ?? fallbackWorkspace;
1510
- const isExistingWorkspace = await this.getWorkspace(this._state.activeWorkspace.id);
1748
+ this._store.setState('activeWorkspace', workspace ?? mostRecentWorkspace ?? fallbackWorkspace);
1749
+ const isExistingWorkspace = await this.getWorkspace(this._store.state.activeWorkspace.id);
1511
1750
  if (isExistingWorkspace) {
1512
- await this.updateWorkspace(this._state.activeWorkspace);
1751
+ await this.updateWorkspace(this._store.state.activeWorkspace);
1513
1752
  }
1514
1753
  else {
1515
- await this.createWorkspace(this._state.activeWorkspace);
1754
+ await this.createWorkspace(this._store.state.activeWorkspace);
1516
1755
  }
1517
- this._state.workspaces = await this.getWorkspaces();
1518
- this.state.translateX = this._state.activeWorkspace.viewport.translateX;
1519
- this.state.translateY = this._state.activeWorkspace.viewport.translateY;
1520
- this.state.scale = this._state.activeWorkspace.viewport.scale;
1521
- await this.initializeWorkspaceObjects(this._state.activeWorkspace.id);
1756
+ this._store.setState('workspaces', await this.getWorkspaces());
1757
+ this._store.setState('translateX', this._store.state.activeWorkspace.viewport.translateX);
1758
+ this._store.setState('translateY', this._store.state.activeWorkspace.viewport.translateY);
1759
+ this._store.setState('scale', this._store.state.activeWorkspace.viewport.scale);
1760
+ await this.initializeWorkspaceObjects(this._store.state.activeWorkspace.id);
1522
1761
  }
1523
1762
  async initializeWorkspaceObjects(workspaceId) {
1524
- this._state.objectsMap.reset();
1763
+ this._store.state.objectsMap.reset();
1525
1764
  this._history.reset();
1526
1765
  const objectsFromDb = await this._database.getAllByRange('objects', IDBKeyRange.bound([workspaceId], [workspaceId, '\uffff']));
1527
1766
  const reviver = new KritzelReviver(this);
1528
1767
  objectsFromDb.forEach(element => {
1529
1768
  const revivedObject = reviver.revive(element);
1530
- this._state.objectsMap.insert(revivedObject);
1769
+ this._store.state.objectsMap.insert(revivedObject);
1531
1770
  });
1532
1771
  this.rerender();
1533
1772
  }
1534
1773
  async updateWorkspaceViewport(translateX, translateY, scale) {
1535
- if (!this.state.activeWorkspace) {
1774
+ const activeWorkspace = this._store.state.activeWorkspace;
1775
+ if (!activeWorkspace) {
1536
1776
  throw new Error('Workspace not initialized');
1537
1777
  }
1538
- this.state.activeWorkspace.viewport = {
1539
- translateX,
1540
- translateY,
1541
- scale,
1542
- };
1543
- this.state.activeWorkspace.updatedAt = new Date();
1544
- await this._database.update('workspaces', this.state.activeWorkspace);
1778
+ activeWorkspace.viewport = { translateX, translateY, scale };
1779
+ activeWorkspace.updatedAt = new Date();
1780
+ await this._database.update('workspaces', activeWorkspace);
1545
1781
  }
1546
1782
  async addObjectToDatabase(object) {
1547
1783
  if (!this._database) {
1548
1784
  throw new Error('Database not initialized');
1549
1785
  }
1550
- if (!this.state.activeWorkspace) {
1786
+ const activeWorkspace = this._store.state.activeWorkspace;
1787
+ if (!activeWorkspace) {
1551
1788
  throw new Error('Workspace not initialized');
1552
1789
  }
1553
- this.state.activeWorkspace.updatedAt = new Date();
1554
- await this._database.batch([db => db.add('objects', object), db => db.update('workspaces', this.state.activeWorkspace)]).catch(err => {
1790
+ activeWorkspace.updatedAt = new Date();
1791
+ await this._database.batch([db => db.add('objects', object), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1555
1792
  console.error('Error adding object to database:', err);
1556
1793
  });
1557
1794
  }
@@ -1559,11 +1796,12 @@ class KritzelStore {
1559
1796
  if (!this._database) {
1560
1797
  throw new Error('Database not initialized');
1561
1798
  }
1562
- if (!this.state.activeWorkspace) {
1799
+ const activeWorkspace = this._store.state.activeWorkspace;
1800
+ if (!activeWorkspace) {
1563
1801
  throw new Error('Workspace not initialized');
1564
1802
  }
1565
- this.state.activeWorkspace.updatedAt = new Date();
1566
- await this._database.batch([db => db.update('objects', object), db => db.update('workspaces', this.state.activeWorkspace)]).catch(err => {
1803
+ activeWorkspace.updatedAt = new Date();
1804
+ await this._database.batch([db => db.update('objects', object), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1567
1805
  console.error('Error updating object in database:', err);
1568
1806
  });
1569
1807
  }
@@ -1571,25 +1809,28 @@ class KritzelStore {
1571
1809
  if (!this._database) {
1572
1810
  throw new Error('Database not initialized');
1573
1811
  }
1574
- if (!this.state.activeWorkspace) {
1812
+ const activeWorkspace = this._store.state.activeWorkspace;
1813
+ if (!activeWorkspace) {
1575
1814
  throw new Error('Workspace not initialized');
1576
1815
  }
1577
- this.state.activeWorkspace.updatedAt = new Date();
1578
- await this._database.batch([db => db.delete('objects', [this.state.activeWorkspace.id, objectId]), db => db.update('workspaces', this.state.activeWorkspace)]).catch(err => {
1816
+ activeWorkspace.updatedAt = new Date();
1817
+ await this._database.batch([db => db.delete('objects', [activeWorkspace.id, objectId]), db => db.update('workspaces', activeWorkspace)]).catch(err => {
1579
1818
  console.error('Error deleting object from database:', err);
1580
1819
  });
1581
1820
  }
1582
- getWorkspace(id) {
1821
+ async getWorkspace(id) {
1583
1822
  if (!this._database) {
1584
1823
  throw new Error('Database not initialized');
1585
1824
  }
1586
- return this._database.get('workspaces', id);
1825
+ const reviver = new KritzelReviver(this);
1826
+ return this._database.get('workspaces', id).then(rawWorkspace => (rawWorkspace ? reviver.revive(rawWorkspace) : null));
1587
1827
  }
1588
- getWorkspaces() {
1828
+ async getWorkspaces() {
1589
1829
  if (!this._database) {
1590
1830
  throw new Error('Database not initialized');
1591
1831
  }
1592
- return this._database.getAll('workspaces');
1832
+ const reviver = new KritzelReviver(this);
1833
+ return this._database.getAll('workspaces').then(rawWorkspaces => rawWorkspaces.map(ws => reviver.revive(ws)));
1593
1834
  }
1594
1835
  async createWorkspace(workspace) {
1595
1836
  if (!this._database) {
@@ -1598,7 +1839,7 @@ class KritzelStore {
1598
1839
  workspace.createdAt = new Date();
1599
1840
  workspace.updatedAt = new Date();
1600
1841
  await this._database.add('workspaces', workspace);
1601
- this.state.workspaces.push(workspace);
1842
+ this._store.state.workspaces.push(workspace);
1602
1843
  }
1603
1844
  async updateWorkspace(workspace) {
1604
1845
  if (!this._database) {
@@ -1606,9 +1847,11 @@ class KritzelStore {
1606
1847
  }
1607
1848
  workspace.updatedAt = new Date();
1608
1849
  await this._database.update('workspaces', workspace);
1609
- const index = this.state.workspaces.findIndex(w => w.id === workspace.id);
1850
+ const workspaces = this._store.state.workspaces;
1851
+ const index = workspaces.findIndex(w => w.id === workspace.id);
1610
1852
  if (index !== -1) {
1611
- this.state.workspaces[index] = workspace;
1853
+ workspaces[index] = workspace;
1854
+ this._store.setState('workspaces', workspaces);
1612
1855
  }
1613
1856
  }
1614
1857
  async deleteWorkspace(workspace) {
@@ -1618,7 +1861,7 @@ class KritzelStore {
1618
1861
  const objectRange = IDBKeyRange.bound([workspace.id], [workspace.id, '\uffff']);
1619
1862
  await this._database.deleteByRange('objects', objectRange);
1620
1863
  await this._database.delete('workspaces', workspace.id);
1621
- this.state.workspaces = this.state.workspaces.filter(ws => ws.id !== workspace.id);
1864
+ this._store.setState('workspaces', this._store.state.workspaces.filter(ws => ws.id !== workspace.id));
1622
1865
  }
1623
1866
  rerender() {
1624
1867
  if (this._kritzelEngine) {
@@ -1626,7 +1869,7 @@ class KritzelStore {
1626
1869
  }
1627
1870
  }
1628
1871
  findObjectById(id) {
1629
- for (const object of this.allObjects) {
1872
+ for (const object of this._store.allObjects) {
1630
1873
  if (object.id === id) {
1631
1874
  return object;
1632
1875
  }
@@ -1634,33 +1877,18 @@ class KritzelStore {
1634
1877
  return null;
1635
1878
  }
1636
1879
  deselectAllObjects() {
1637
- if (this._state.selectionGroup) {
1880
+ if (this._store.state.selectionGroup) {
1638
1881
  this._history.executeCommand(new RemoveSelectionGroupCommand(this, this));
1639
1882
  }
1640
1883
  }
1641
- onStateChange(property, listener) {
1642
- if (!this._listeners.has(property)) {
1643
- this._listeners.set(property, new Set());
1644
- }
1645
- this._listeners.get(property).add(listener);
1646
- }
1647
- setState(property, value) {
1648
- const oldValue = this._state[property];
1649
- if (oldValue !== value) {
1650
- this._state[property] = value;
1651
- if (this._listeners.has(property)) {
1652
- this._listeners.get(property).forEach(listener => listener(value, oldValue, String(property)));
1653
- }
1654
- }
1655
- }
1656
1884
  delete() {
1657
- if (!this.state.selectionGroup) {
1885
+ if (!this._store.state.selectionGroup) {
1658
1886
  return;
1659
1887
  }
1660
- const deleteSelectedObjectsCommand = this.state.selectionGroup.objects.map(obj => new RemoveObjectCommand(this, this.state.selectionGroup, obj));
1661
- const removeSelectionGroupCommand = new RemoveSelectionGroupCommand(this, this.state.selectionGroup);
1888
+ const deleteSelectedObjectsCommand = this._store.state.selectionGroup.objects.map(obj => new RemoveObjectCommand(this, this._store.state.selectionGroup, obj));
1889
+ const removeSelectionGroupCommand = new RemoveSelectionGroupCommand(this, this._store.state.selectionGroup);
1662
1890
  const commands = [...deleteSelectedObjectsCommand, removeSelectionGroupCommand];
1663
- this.history.executeCommand(new BatchCommand(this, this.state.selectionGroup, commands));
1891
+ this.history.executeCommand(new BatchCommand(this, this._store.state.selectionGroup, commands));
1664
1892
  }
1665
1893
  deleteObject(id, skipHistory = false) {
1666
1894
  const object = this.findObjectById(id);
@@ -1670,28 +1898,30 @@ class KritzelStore {
1670
1898
  }
1671
1899
  }
1672
1900
  copy() {
1673
- this.state.copiedObjects = this.state.selectionGroup.copy();
1901
+ this._store.setState('copiedObjects', this._store.state.selectionGroup.copy());
1674
1902
  }
1675
1903
  paste(x, y) {
1676
- this.state.copiedObjects.isSelected = true;
1677
- const adjustedX = x !== undefined ? x : this.state.copiedObjects.translateX + 25;
1678
- const adjustedY = y !== undefined ? y : this.state.copiedObjects.translateY + 25;
1679
- this.state.copiedObjects.updatePosition(adjustedX, adjustedY);
1904
+ const copiedObjects = this._store.state.copiedObjects;
1905
+ copiedObjects.isSelected = true;
1906
+ this._store.setState('copiedObjects', copiedObjects);
1907
+ const adjustedX = x !== undefined ? x : this._store.state.copiedObjects.translateX + 25 / this._store.state.scale;
1908
+ const adjustedY = y !== undefined ? y : this._store.state.copiedObjects.translateY + 25 / this._store.state.scale;
1909
+ this._store.state.copiedObjects.updatePosition(adjustedX, adjustedY);
1680
1910
  const commands = [];
1681
- if (this.state.selectionGroup !== null) {
1682
- commands.push(new RemoveSelectionGroupCommand(this, this.state.selectionGroup));
1911
+ if (this._store.state.selectionGroup !== null) {
1912
+ commands.push(new RemoveSelectionGroupCommand(this, this._store.state.selectionGroup));
1683
1913
  }
1684
- const addCopiedObjectsCommands = this.state.copiedObjects.objects.map(obj => new AddObjectCommand(this, this, obj));
1685
- const addCopiedObjectsAsSelectionGroupCommand = new AddSelectionGroupCommand(this, this, this.state.copiedObjects);
1914
+ const addCopiedObjectsCommands = this._store.state.copiedObjects.objects.map(obj => new AddObjectCommand(this, this, obj));
1915
+ const addCopiedObjectsAsSelectionGroupCommand = new AddSelectionGroupCommand(this, this, this._store.state.copiedObjects);
1686
1916
  commands.push(...addCopiedObjectsCommands, addCopiedObjectsAsSelectionGroupCommand);
1687
1917
  this.history.executeCommand(new BatchCommand(this, this, commands));
1688
- this.state.isSelecting = false;
1689
- this.state.copiedObjects = this.state.selectionGroup.copy();
1690
- this.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1918
+ this._store.setState('isSelecting', false);
1919
+ this._store.setState('copiedObjects', this._store.state.selectionGroup.copy());
1920
+ this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1691
1921
  }
1692
1922
  bringForward(object) {
1693
- const max = this.allObjects.length + 1;
1694
- const objects = object ? [object] : this.state.selectionGroup.objects;
1923
+ const max = this._store.allObjects.length + 1;
1924
+ const objects = object ? [object] : this._store.state.selectionGroup.objects;
1695
1925
  const increaseZIndexCommands = objects.map(obj => {
1696
1926
  if (obj.zIndex === max) {
1697
1927
  return;
@@ -1702,7 +1932,7 @@ class KritzelStore {
1702
1932
  }
1703
1933
  sendBackward(object) {
1704
1934
  const min = 0;
1705
- const objects = object ? [object] : this.state.selectionGroup.objects;
1935
+ const objects = object ? [object] : this._store.state.selectionGroup.objects;
1706
1936
  const decreaseZIndexCommands = objects.map(obj => {
1707
1937
  if (obj.zIndex === min) {
1708
1938
  return;
@@ -1712,16 +1942,16 @@ class KritzelStore {
1712
1942
  this.history.executeCommand(new BatchCommand(this, this, decreaseZIndexCommands));
1713
1943
  }
1714
1944
  bringToFront(object) {
1715
- const max = Math.max(...this.allObjects.map(obj => obj.zIndex)) + 1;
1716
- const objects = object ? [object] : this.state.selectionGroup.objects;
1945
+ const max = Math.max(...this._store.allObjects.map(obj => obj.zIndex)) + 1;
1946
+ const objects = object ? [object] : this._store.state.selectionGroup.objects;
1717
1947
  const increaseZIndexCommands = objects.map(obj => {
1718
1948
  return new UpdateObjectCommand(this, this, obj, { zIndex: max });
1719
1949
  });
1720
1950
  this.history.executeCommand(new BatchCommand(this, this, increaseZIndexCommands));
1721
1951
  }
1722
1952
  sendToBack(object) {
1723
- const min = Math.min(...this.allObjects.map(obj => obj.zIndex)) - 1;
1724
- const objects = object ? [object] : this.state.selectionGroup.objects;
1953
+ const min = Math.min(...this._store.allObjects.map(obj => obj.zIndex)) - 1;
1954
+ const objects = object ? [object] : this._store.state.selectionGroup.objects;
1725
1955
  const decreaseZIndexCommands = objects.map(obj => {
1726
1956
  return new UpdateObjectCommand(this, this, obj, { zIndex: min });
1727
1957
  });
@@ -1737,14 +1967,14 @@ class KritzelStore {
1737
1967
  selectionGroup.addOrRemove(obj);
1738
1968
  });
1739
1969
  selectionGroup.isSelected = true;
1740
- this.state.selectionGroup = selectionGroup;
1970
+ this._store.setState('selectionGroup', selectionGroup);
1741
1971
  if (objects.length === 1) {
1742
1972
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
1743
1973
  }
1744
1974
  this.history.executeCommand(new AddSelectionGroupCommand(this, this, selectionGroup));
1745
1975
  }
1746
1976
  selectAllObjectsInViewport() {
1747
- const objectsInViewport = this._state.objectsMap
1977
+ const objectsInViewport = this._store.state.objectsMap
1748
1978
  .filter(o => o.isInViewport())
1749
1979
  .filter(o => !(o instanceof KritzelSelectionGroup) && !(o instanceof KrtizelSelectionBox) && !(o instanceof KritzelContextMenu));
1750
1980
  if (objectsInViewport.length > 0) {
@@ -1754,31 +1984,31 @@ class KritzelStore {
1754
1984
  selectionGroup.addOrRemove(obj);
1755
1985
  });
1756
1986
  selectionGroup.isSelected = true;
1757
- this.state.isSelecting = false;
1987
+ this._store.setState('isSelecting', false);
1758
1988
  if (objectsInViewport.length === 1) {
1759
1989
  selectionGroup.rotation = selectionGroup.objects[0].rotation;
1760
1990
  }
1761
1991
  this.history.executeCommand(new AddSelectionGroupCommand(this, this, selectionGroup));
1762
- this.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1992
+ this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1763
1993
  }
1764
1994
  }
1765
1995
  clearSelection() {
1766
- const command = new RemoveSelectionGroupCommand(this, this.state.selectionGroup);
1996
+ const command = new RemoveSelectionGroupCommand(this, this._store.state.selectionGroup);
1767
1997
  this.history.executeCommand(command);
1768
- this.state.selectionGroup = null;
1769
- this.state.selectionBox = null;
1770
- this.state.isSelecting = false;
1771
- this.state.isResizeHandleSelected = false;
1772
- this.state.isRotationHandleSelected = false;
1998
+ this._store.setState('selectionGroup', null);
1999
+ this._store.setState('selectionBox', null);
2000
+ this._store.setState('isSelecting', false);
2001
+ this._store.setState('isResizeHandleSelected', false);
2002
+ this._store.setState('isRotationHandleSelected', false);
1773
2003
  }
1774
2004
  resetActiveText() {
1775
- if (this.state.activeText && this.state.activeText.value === ' ') {
1776
- this.deleteObject(this.state.activeText.id, true);
2005
+ if (this._store.state.activeText && this._store.state.activeText.value === ' ') {
2006
+ this.deleteObject(this._store.state.activeText.id, true);
1777
2007
  }
1778
- this.state.activeText = null;
2008
+ this._store.setState('activeText', null);
1779
2009
  }
1780
2010
  getObjectFromPointerEvent(event, selector = '.object') {
1781
- const shadowRoot = this.state.host?.shadowRoot;
2011
+ const shadowRoot = this._store.state.host?.shadowRoot;
1782
2012
  if (!shadowRoot)
1783
2013
  return null;
1784
2014
  const clientX = event.clientX;
@@ -1788,12 +2018,14 @@ class KritzelStore {
1788
2018
  return null;
1789
2019
  const selectedObject = elementAtPoint.closest(selector);
1790
2020
  if (selectedObject) {
1791
- return this.allObjects.find(object => selectedObject.id === object.id);
2021
+ const foundObject = this._store.allObjects.find(object => selectedObject.id === object.id);
2022
+ const isHit = foundObject?.hitTest(clientX, clientY);
2023
+ return isHit ? foundObject : null;
1792
2024
  }
1793
2025
  return null;
1794
2026
  }
1795
2027
  getObjectsFromPointerEvent(event, selector = '.object') {
1796
- const shadowRoot = this.state.host?.shadowRoot;
2028
+ const shadowRoot = this._store.state.host?.shadowRoot;
1797
2029
  if (!shadowRoot)
1798
2030
  return [];
1799
2031
  const clientX = event.clientX;
@@ -1809,288 +2041,119 @@ class KritzelStore {
1809
2041
  }
1810
2042
  });
1811
2043
  if (objectIds.size > 0) {
1812
- return this.allObjects.filter(object => objectIds.has(object.id)).sort((a, b) => b.zIndex - a.zIndex);
2044
+ return this._store.allObjects.filter(object => objectIds.has(object.id)).sort((a, b) => b.zIndex - a.zIndex);
1813
2045
  }
1814
2046
  return [];
1815
2047
  }
1816
2048
  getCanvasPoint(event) {
1817
- if (!this.state.host) {
2049
+ if (!this._store.state.host) {
1818
2050
  return { x: 0, y: 0 };
1819
2051
  }
1820
- // Get the position of the kritzel-engine host element relative to the viewport
1821
- const hostRect = this.state.host.getBoundingClientRect();
1822
- // 1. Make the pointer coordinates relative to the host element
2052
+ const hostRect = this._store.state.host.getBoundingClientRect();
1823
2053
  const xRelativeToHost = event.clientX - hostRect.left;
1824
2054
  const yRelativeToHost = event.clientY - hostRect.top;
1825
- // 2. Reverse the translation applied to the #origin div
1826
- const xWithoutTranslate = xRelativeToHost - this.state.translateX;
1827
- const yWithoutTranslate = yRelativeToHost - this.state.translateY;
1828
- // 3. Reverse the scaling to get the final world coordinates
1829
- const worldX = xWithoutTranslate / this.state.scale;
1830
- const worldY = yWithoutTranslate / this.state.scale;
2055
+ const xWithoutTranslate = xRelativeToHost - this._store.state.translateX;
2056
+ const yWithoutTranslate = yRelativeToHost - this._store.state.translateY;
2057
+ const worldX = xWithoutTranslate / this._store.state.scale;
2058
+ const worldY = yWithoutTranslate / this._store.state.scale;
1831
2059
  return { x: worldX, y: worldY };
1832
2060
  }
1833
2061
  }
1834
2062
 
1835
- class KritzelKeyHandler extends KritzelBaseHandler {
1836
- constructor(store) {
1837
- super(store);
1838
- }
1839
- handleKeyDown(event) {
1840
- if (this._store.state.isFocused === false) {
1841
- return;
1842
- }
1843
- this._store.state.isCtrlKeyPressed = event.ctrlKey;
1844
- if (this._store.state.isCtrlKeyPressed) {
1845
- event.preventDefault();
1846
- }
1847
- if (event.key === 'Escape' && this._store.state.selectionGroup) {
1848
- this._store.clearSelection();
1849
- }
1850
- if (event.key === 'Delete' && this._store.state.selectionGroup) {
1851
- this._store.delete();
1852
- }
1853
- if (event.key === 'z' && event.ctrlKey) {
1854
- this._store.history.undo();
1855
- }
1856
- if (event.key === 'y' && event.ctrlKey) {
1857
- this._store.history.redo();
1858
- }
1859
- if (event.key === 's' && event.ctrlKey) {
1860
- this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1861
- this._store.deselectAllObjects();
1862
- }
1863
- if (event.key === 'b' && event.ctrlKey) {
1864
- this._store.setState('activeTool', KritzelToolRegistry.getTool('brush'));
1865
- this._store.deselectAllObjects();
1866
- }
1867
- if (event.key === 'e' && event.ctrlKey) {
1868
- this._store.setState('activeTool', KritzelToolRegistry.getTool('eraser'));
1869
- this._store.deselectAllObjects();
1870
- }
1871
- if (event.key === 'i' && event.ctrlKey) {
1872
- this._store.setState('activeTool', KritzelToolRegistry.getTool('image'));
1873
- this._store.deselectAllObjects();
1874
- }
1875
- if (event.key === 'x' && event.ctrlKey) {
1876
- this._store.setState('activeTool', KritzelToolRegistry.getTool('text'));
1877
- this._store.deselectAllObjects();
1878
- }
1879
- if (event.key === 'c' && event.ctrlKey && this._store.state.selectionGroup) {
1880
- this._store.copy();
1881
- this._store.rerender();
1882
- }
1883
- if (event.key === 'v' && event.ctrlKey && this._store.state.copiedObjects) {
1884
- this._store.paste();
1885
- }
1886
- if (event.key === '+' && event.ctrlKey && this._store.state.selectionGroup) {
1887
- this._store.bringForward();
1888
- }
1889
- if (event.key === '-' && event.ctrlKey && this._store.state.selectionGroup) {
1890
- this._store.sendBackward();
1891
- }
1892
- if (event.key === '*' && event.shiftKey && this._store.state.selectionGroup) {
1893
- this._store.bringToFront();
1894
- }
1895
- if (event.key === '_' && event.shiftKey && this._store.state.selectionGroup) {
1896
- this._store.sendToBack();
1897
- }
1898
- if (event.key === 'a' && event.ctrlKey && this._store.state.activeText) {
1899
- this._store.state.activeText.selectAll();
1900
- }
1901
- if (event.key === 'v' && event.ctrlKey && this._store.state.activeText) {
1902
- this._store.state.activeText.insertFromClipboard();
1903
- }
1904
- }
1905
- handleKeyUp(event) {
1906
- if (this._store.state.isFocused === false) {
1907
- return;
1908
- }
1909
- this._store.state.isCtrlKeyPressed = event.ctrlKey;
1910
- }
1911
- }
1912
-
1913
- class KritzelContextMenuHandler extends KritzelBaseHandler {
1914
- globalContextMenuItems = [];
1915
- objectContextMenuItems = [];
1916
- constructor(store, globalContextMenuItems, objectContextMenuItems) {
1917
- super(store);
1918
- this.globalContextMenuItems = globalContextMenuItems;
1919
- this.objectContextMenuItems = objectContextMenuItems;
1920
- }
1921
- handleContextMenu(event) {
1922
- if (this._store.state.skipContextMenu) {
1923
- this._store.state.skipContextMenu = false;
1924
- return;
1925
- }
1926
- const selectedObject = this._store.getObjectFromPointerEvent(event, '.object');
1927
- if (selectedObject && !(selectedObject instanceof KritzelSelectionGroup)) {
1928
- this._store.state.selectionGroup = KritzelSelectionGroup.create(this._store);
1929
- this._store.state.selectionGroup.addOrRemove(selectedObject);
1930
- this._store.state.selectionGroup.isSelected = true;
1931
- this._store.state.selectionGroup.rotation = selectedObject.rotation;
1932
- this._store.state.isSelecting = false;
1933
- this._store.history.executeCommand(new AddSelectionGroupCommand(this._store, this, this._store.state.selectionGroup));
1934
- }
1935
- this._store.state.contextMenuItems = this._store.state.selectionGroup ? this.objectContextMenuItems : this.globalContextMenuItems;
1936
- let x = event.clientX - this._store.offsetX;
1937
- let y = event.clientY - this._store.offsetY;
1938
- const menuWidthEstimate = 150;
1939
- const menuHeightEstimate = 200;
1940
- const margin = 10;
1941
- if (x + menuWidthEstimate > window.innerWidth - margin) {
1942
- x = window.innerWidth - menuWidthEstimate - margin;
1943
- }
1944
- if (y + menuHeightEstimate > window.innerHeight - margin) {
1945
- y = window.innerHeight - menuHeightEstimate - margin;
1946
- }
1947
- x = Math.max(margin, x);
1948
- y = Math.max(margin, y);
1949
- this._store.state.contextMenuX = x;
1950
- this._store.state.contextMenuY = y;
1951
- this._store.state.isContextMenuVisible = true;
1952
- this._store.state.isEnabled = false;
1953
- this._store.rerender();
1954
- }
1955
- }
1956
-
1957
- class KritzelClassHelper {
1958
- static isInstanceOf(object, className) {
1959
- return !!object && object.__class__ === className;
1960
- }
1961
- }
1962
-
1963
2063
  const kritzelEngineCss = ":host{display:block;position:relative;height:100%;width:100%;overflow:hidden;background-color:var(--kritzel-engine-background-color, #ffffff)}:host,:host *{touch-action:none;user-select:none}.debug-panel{position:absolute;pointer-events:none;top:0;right:0}.origin{position:relative;top:0;left:0;height:0;width:0;pointer-events:none;-webkit-transform-origin:top left;-moz-transform-origin:top left;transform-origin:top left;overflow:visible}.object{overflow:visible}textarea{all:unset;box-sizing:border-box;outline:none !important;border:none !important;overflow:visible}.resize-handle-overlay.top-left,.resize-handle-overlay.bottom-right{cursor:nwse-resize}.resize-handle-overlay.top-right,.resize-handle-overlay.bottom-left{cursor:nesw-resize}.rotation-handle-overlay{cursor:grab}";
1964
2064
 
1965
2065
  const KritzelEngine = class {
2066
+ get host() { return getElement(this); }
1966
2067
  workspace;
2068
+ onWorkspaceChange(newWorkspace) {
2069
+ if (this.core.store.state.activeWorkspace !== newWorkspace) {
2070
+ this.core.initializeWorkspace(newWorkspace);
2071
+ }
2072
+ }
1967
2073
  activeTool;
1968
2074
  globalContextMenuItems;
1969
2075
  objectContextMenuItems;
1970
2076
  scaleMax = ABSOLUTE_SCALE_MAX;
1971
- scaleMin = ABSOLUTE_SCALE_MIN;
1972
- isEngineReady;
1973
- activeToolChange;
1974
- workspacesChange;
1975
- get host() { return getElement(this); }
1976
- forceUpdate = 0;
1977
- onWorkspaceChange(newWorkspace) {
1978
- if (newWorkspace) {
1979
- this.store.initializeWorkspace(newWorkspace);
1980
- }
1981
- }
1982
2077
  validateScaleMax(newValue) {
1983
2078
  if (newValue > ABSOLUTE_SCALE_MAX) {
1984
2079
  console.warn(`scaleMax cannot be greater than ${ABSOLUTE_SCALE_MAX}.`);
1985
2080
  this.scaleMax = ABSOLUTE_SCALE_MAX;
1986
- this.store.state.scaleMax = this.scaleMax;
2081
+ this.core.store.setState('scaleMax', this.scaleMax);
1987
2082
  }
1988
2083
  else {
1989
- this.store.state.scaleMax = newValue;
2084
+ this.core.store.setState('scaleMax', newValue);
1990
2085
  }
1991
2086
  }
2087
+ scaleMin = ABSOLUTE_SCALE_MIN;
1992
2088
  validateScaleMin(newValue) {
1993
2089
  if (newValue < ABSOLUTE_SCALE_MIN) {
1994
2090
  console.warn(`scaleMin cannot be less than ${ABSOLUTE_SCALE_MIN}.`);
1995
2091
  this.scaleMin = ABSOLUTE_SCALE_MIN;
1996
- this.store.state.scaleMin = this.scaleMin;
2092
+ this.core.store.setState('scaleMin', this.scaleMin);
1997
2093
  }
1998
2094
  else {
1999
- this.store.state.scaleMin = newValue;
2000
- }
2001
- }
2002
- store;
2003
- viewport;
2004
- contextMenuHandler;
2005
- keyHandler;
2006
- contextMenuElement = null;
2007
- get isSelecting() {
2008
- return this.store.state.activeTool instanceof KritzelSelectionTool && this.store.state.isSelecting;
2009
- }
2010
- get isSelectionActive() {
2011
- return this.store.state.activeTool instanceof KritzelSelectionTool && this.store.state.selectionGroup !== null;
2012
- }
2013
- constructor(hostRef) {
2014
- registerInstance(this, hostRef);
2015
- this.isEngineReady = createEvent(this, "isEngineReady");
2016
- this.activeToolChange = createEvent(this, "activeToolChange");
2017
- this.workspacesChange = createEvent(this, "workspacesChange");
2018
- this.store = new KritzelStore(this);
2019
- }
2020
- componentWillLoad() {
2021
- this.validateScaleMax(this.scaleMax);
2022
- this.validateScaleMin(this.scaleMin);
2023
- }
2024
- async componentDidLoad() {
2025
- this.contextMenuHandler = new KritzelContextMenuHandler(this.store, this.globalContextMenuItems, this.objectContextMenuItems);
2026
- this.keyHandler = new KritzelKeyHandler(this.store);
2027
- this.viewport = new KritzelViewport(this.store, this.host);
2028
- this._registerStateChangeListeners();
2029
- await this.store.initializeDatabase();
2030
- await this.store.initializeWorkspace(this.workspace);
2031
- if (this.store.state.isReady === false) {
2032
- this.store.state.isReady = true;
2033
- this.isEngineReady.emit(this.store.state);
2095
+ this.core.store.setState('scaleMin', newValue);
2034
2096
  }
2035
2097
  }
2098
+ isEngineReady;
2099
+ activeToolChange;
2100
+ workspacesChange;
2101
+ longpress;
2102
+ forceUpdate = 0;
2036
2103
  handleWheel(ev) {
2037
- if (this.store.isDisabled) {
2104
+ if (this.core.store.isDisabled) {
2038
2105
  return;
2039
2106
  }
2040
- if (this.store.state.isContextMenuVisible) {
2107
+ if (this.core.store.state.isContextMenuVisible) {
2041
2108
  this.hideContextMenu();
2042
2109
  }
2043
2110
  this.viewport.handleWheel(ev);
2044
- this.store.state?.activeTool?.handleWheel(ev);
2111
+ this.core.store.state?.activeTool?.handleWheel(ev);
2045
2112
  }
2046
2113
  handlePointerDown(ev) {
2047
- if (this.store.isDisabled) {
2114
+ if (this.core.store.isDisabled) {
2048
2115
  return;
2049
2116
  }
2050
- if (KritzelEventHelper.isPointerEventOnContextMenu(ev) === false && this.store.state.isContextMenuVisible) {
2051
- this.hideContextMenu();
2052
- return;
2117
+ if (KritzelDevicesHelper.isTouchDevice()) {
2118
+ KritzelEventHelper.onLongPress(ev, (event) => this.longpress.emit(event));
2053
2119
  }
2054
- KritzelEventHelper.onLongTouchPress(ev, (event) => {
2055
- if (!(this.store.state.activeTool instanceof KritzelSelectionTool)) {
2056
- return;
2057
- }
2058
- this.contextMenuHandler.handleContextMenu(event);
2059
- });
2060
2120
  this.host.setPointerCapture(ev.pointerId);
2061
- this.store.state.pointers.set(ev.pointerId, ev);
2121
+ this.core.store.state.pointers.set(ev.pointerId, ev);
2062
2122
  this.viewport.handlePointerDown(ev);
2063
- this.store.state?.activeTool?.handlePointerDown(ev);
2123
+ this.core.store.state?.activeTool?.handlePointerDown(ev);
2064
2124
  }
2065
2125
  handlePointerMove(ev) {
2066
- if (this.store.isDisabled) {
2126
+ if (this.core.store.isDisabled) {
2067
2127
  return;
2068
2128
  }
2069
- this.store.state.pointers.set(ev.pointerId, ev);
2129
+ this.core.store.state.pointers.set(ev.pointerId, ev);
2070
2130
  this.viewport.handlePointerMove(ev);
2071
- this.store.state?.activeTool?.handlePointerMove(ev);
2131
+ this.core.store.state?.activeTool?.handlePointerMove(ev);
2072
2132
  }
2073
2133
  handlePointerUp(ev) {
2074
- if (this.store.isDisabled) {
2134
+ if (this.core.store.isDisabled) {
2075
2135
  return;
2076
2136
  }
2077
- this.store.state.pointers.delete(ev.pointerId);
2137
+ this.core.store.state.pointers.delete(ev.pointerId);
2078
2138
  this.host.releasePointerCapture(ev.pointerId);
2079
2139
  this.viewport.handlePointerUp(ev);
2080
- this.store.state?.activeTool?.handlePointerUp(ev);
2140
+ this.core.store.state?.activeTool?.handlePointerUp(ev);
2081
2141
  }
2082
2142
  handlePointerCancel(ev) {
2083
- if (this.store.isDisabled) {
2143
+ if (this.core.store.isDisabled) {
2084
2144
  return;
2085
2145
  }
2086
2146
  this.host.releasePointerCapture(ev.pointerId);
2087
- this.store.state.pointers.delete(ev.pointerId);
2147
+ this.core.store.state.pointers.delete(ev.pointerId);
2088
2148
  this.viewport.handlePointerUp(ev);
2089
- this.store.state?.activeTool?.handlePointerUp(ev);
2149
+ this.core.store.state?.activeTool?.handlePointerUp(ev);
2150
+ }
2151
+ handleLongPress(ev) {
2152
+ this.contextMenuHandler.handleContextMenu(ev.detail);
2090
2153
  }
2091
2154
  handleContextMenu(ev) {
2092
2155
  ev.preventDefault();
2093
- if (this.store.isDisabled) {
2156
+ if (this.core.store.isDisabled) {
2094
2157
  return;
2095
2158
  }
2096
2159
  if (ev.pointerType === 'touch') {
@@ -2107,26 +2170,12 @@ const KritzelEngine = class {
2107
2170
  handleKeyUp(ev) {
2108
2171
  this.keyHandler.handleKeyUp(ev);
2109
2172
  }
2110
- updateFocus(ev) {
2111
- if (this.store.isDisabled) {
2112
- return;
2113
- }
2114
- const rect = this.store.state.host.getBoundingClientRect();
2115
- const isInside = ev.clientX >= rect.left && ev.clientX <= rect.right && ev.clientY >= rect.top && ev.clientY <= rect.bottom;
2116
- const path = ev.composedPath();
2117
- const kritzelEngineElement = this.host.closest('kritzel-engine');
2118
- const isInKritzelEngine = path.includes(kritzelEngineElement || this.host);
2119
- this.store.setState('isFocused', isInside && isInKritzelEngine);
2120
- }
2121
- handleClick() {
2122
- this.enable();
2123
- }
2124
2173
  async registerTool(toolName, toolClass, toolConfig) {
2125
2174
  if (typeof toolClass !== 'function' || !(toolClass.prototype instanceof KritzelBaseTool)) {
2126
2175
  console.error(`Failed to register tool "${toolName}": Tool class must be a constructor function`);
2127
2176
  return null;
2128
2177
  }
2129
- const registeredTool = KritzelToolRegistry.registerTool(toolName, toolClass, this.store);
2178
+ const registeredTool = KritzelToolRegistry.registerTool(toolName, toolClass, this.core);
2130
2179
  if (toolConfig) {
2131
2180
  Object.entries(toolConfig).forEach(([key, value]) => {
2132
2181
  registeredTool[key] = value;
@@ -2135,153 +2184,188 @@ const KritzelEngine = class {
2135
2184
  return Promise.resolve(registeredTool);
2136
2185
  }
2137
2186
  async changeActiveTool(tool) {
2138
- this.store.state.activeTool?.onDeactivate();
2139
- this.store.setState('activeTool', tool);
2140
- this.store.deselectAllObjects();
2187
+ this.core.store.state.activeTool?.onDeactivate();
2188
+ this.core.store.setState('activeTool', tool);
2189
+ this.core.deselectAllObjects();
2141
2190
  tool?.onActivate();
2142
2191
  }
2143
- async setFocus() {
2144
- this.host.focus();
2145
- this.store.state.isFocused = true;
2146
- }
2147
2192
  async disable() {
2148
- this.store.state.isEnabled = false;
2149
- this.forceUpdate++;
2193
+ this.core.store.setState('isEnabled', false);
2194
+ this.core.rerender();
2150
2195
  }
2151
2196
  async enable() {
2152
- this.store.state.isEnabled = true;
2153
- this.forceUpdate++;
2197
+ this.core.store.setState('isEnabled', true);
2198
+ this.core.rerender();
2154
2199
  }
2155
2200
  async delete() {
2156
- this.store.delete();
2201
+ this.core.delete();
2157
2202
  }
2158
2203
  async copy() {
2159
- this.store.copy();
2204
+ this.core.copy();
2160
2205
  }
2161
2206
  async paste(x, y) {
2162
- this.store.paste(x, y);
2207
+ this.core.paste(x, y);
2163
2208
  }
2164
2209
  async bringForward(object) {
2165
- this.store.bringForward(object);
2210
+ this.core.bringForward(object);
2166
2211
  }
2167
2212
  async sendBackward(object) {
2168
- this.store.sendBackward(object);
2213
+ this.core.sendBackward(object);
2169
2214
  }
2170
2215
  async bringToFront(object) {
2171
- this.store.bringToFront(object);
2216
+ this.core.bringToFront(object);
2172
2217
  }
2173
2218
  async sendToBack(object) {
2174
- this.store.sendToBack(object);
2219
+ this.core.sendToBack(object);
2175
2220
  }
2176
2221
  async undo() {
2177
- this.store.history.undo();
2222
+ this.core.history.undo();
2178
2223
  }
2179
2224
  async redo() {
2180
- this.store.history.redo();
2225
+ this.core.history.redo();
2181
2226
  }
2182
2227
  async hideContextMenu() {
2183
- this.store.state.pointers.clear();
2184
- this.store.state.isContextMenuVisible = false;
2185
- this.store.state.selectionBox = null;
2186
- this.store.state.isSelecting = false;
2228
+ this.core.store.state.pointers.clear();
2229
+ this.core.store.setState('isContextMenuVisible', false);
2230
+ this.core.store.setState('selectionBox', null);
2231
+ this.core.store.setState('isSelecting', false);
2232
+ this.core.store.setState('isEnabled', true);
2233
+ this.core.rerender();
2187
2234
  }
2188
2235
  async getObjectById(id) {
2189
- const object = this.store.objects.find(obj => obj.id === id);
2236
+ const object = this.core.store.allObjects.find(obj => obj.id === id);
2190
2237
  return object || null;
2191
2238
  }
2192
2239
  async addObject(object) {
2193
- this.store.deselectAllObjects();
2240
+ this.core.deselectAllObjects();
2194
2241
  object.id = object.generateId();
2195
- object._store = this.store;
2196
- object.scale = object.scale ? object.scale : this.store.state.scale;
2197
- object.zIndex = this.store.currentZIndex;
2198
- const command = new AddObjectCommand(this.store, this, object);
2199
- this.store.history.executeCommand(command);
2242
+ object._core = this.core;
2243
+ object.scale = object.scale ? object.scale : this.core.store.state.scale;
2244
+ object.zIndex = this.core.store.currentZIndex;
2245
+ const command = new AddObjectCommand(this.core, this, object);
2246
+ this.core.history.executeCommand(command);
2200
2247
  return object;
2201
2248
  }
2202
2249
  async updateObject(object, updatedProperties) {
2203
- this.store.deselectAllObjects();
2204
- const command = new UpdateObjectCommand(this.store, this, object, updatedProperties);
2205
- this.store.history.executeCommand(command);
2250
+ this.core.deselectAllObjects();
2251
+ const command = new UpdateObjectCommand(this.core, this, object, updatedProperties);
2252
+ this.core.history.executeCommand(command);
2206
2253
  return object;
2207
2254
  }
2208
2255
  async removeObject(object) {
2209
- this.store.deselectAllObjects();
2210
- const command = new RemoveObjectCommand(this.store, this, object);
2211
- this.store.history.executeCommand(command);
2256
+ this.core.deselectAllObjects();
2257
+ const command = new RemoveObjectCommand(this.core, this, object);
2258
+ this.core.history.executeCommand(command);
2212
2259
  return object;
2213
2260
  }
2214
2261
  async getSelectedObjects() {
2215
- return this.store.state.selectionGroup ? this.store.state.selectionGroup.objects : [];
2262
+ return this.core.store.state.selectionGroup ? this.core.store.state.selectionGroup.objects : [];
2216
2263
  }
2217
2264
  async selectObjects(objects) {
2218
- this.store.state.activeTool?.onDeactivate();
2219
- this.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
2220
- this.store.deselectAllObjects();
2221
- this.store.selectObjects(objects);
2265
+ this.core.store.state.activeTool?.onDeactivate();
2266
+ this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
2267
+ this.core.deselectAllObjects();
2268
+ this.core.selectObjects(objects);
2222
2269
  }
2223
2270
  async selectAllObjectsInViewport() {
2224
- this.store.state.activeTool?.onDeactivate();
2225
- this.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
2226
- this.store.deselectAllObjects();
2227
- this.store.selectAllObjectsInViewport();
2271
+ this.core.store.state.activeTool?.onDeactivate();
2272
+ this.core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
2273
+ this.core.deselectAllObjects();
2274
+ this.core.selectAllObjectsInViewport();
2228
2275
  }
2229
2276
  async clearSelection() {
2230
- this.store.clearSelection();
2277
+ this.core.clearSelection();
2231
2278
  }
2232
2279
  async centerObjectInViewport(object) {
2233
2280
  object.centerInViewport();
2234
- const command = new UpdateObjectCommand(this.store, this, object, object);
2235
- this.store.history.executeCommand(command);
2281
+ const command = new UpdateObjectCommand(this.core, this, object, object);
2282
+ this.core.history.executeCommand(command);
2236
2283
  return object;
2237
2284
  }
2238
2285
  async getCopiedObjects() {
2239
- return this.store.state.copiedObjects?.objects || [];
2286
+ return this.core.store.state.copiedObjects?.objects || [];
2240
2287
  }
2241
2288
  async createWorkspace(workspace) {
2242
- return this.store.createWorkspace(workspace).then(() => {
2243
- this.workspacesChange.emit(this.store.state.workspaces);
2244
- });
2289
+ workspace._core = this.core;
2290
+ await this.core.createWorkspace(workspace);
2291
+ this.workspacesChange.emit(this.core.store.state.workspaces);
2292
+ return workspace;
2245
2293
  }
2246
2294
  async updateWorkspace(workspace) {
2247
- return this.store.updateWorkspace(workspace).then(() => {
2248
- this.workspacesChange.emit(this.store.state.workspaces);
2249
- });
2295
+ await this.core.updateWorkspace(workspace);
2296
+ this.workspacesChange.emit(this.core.store.state.workspaces);
2250
2297
  }
2251
2298
  async deleteWorkspace(workspace) {
2252
- return this.store.deleteWorkspace(workspace).then(async () => {
2253
- this.workspacesChange.emit(this.store.state.workspaces);
2254
- });
2299
+ await this.core.deleteWorkspace(workspace);
2300
+ this.workspacesChange.emit(this.core.store.state.workspaces);
2255
2301
  }
2256
2302
  async getWorkspaces() {
2257
- return this.store.getWorkspaces();
2303
+ return this.core.getWorkspaces();
2304
+ }
2305
+ async getActiveWorkspace() {
2306
+ return this.core.store.state.activeWorkspace;
2307
+ }
2308
+ core;
2309
+ viewport;
2310
+ contextMenuHandler;
2311
+ keyHandler;
2312
+ contextMenuElement = null;
2313
+ get isSelecting() {
2314
+ return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.isSelecting;
2315
+ }
2316
+ get isSelectionActive() {
2317
+ return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.selectionGroup !== null;
2318
+ }
2319
+ constructor(hostRef) {
2320
+ registerInstance(this, hostRef);
2321
+ this.isEngineReady = createEvent(this, "isEngineReady");
2322
+ this.activeToolChange = createEvent(this, "activeToolChange");
2323
+ this.workspacesChange = createEvent(this, "workspacesChange");
2324
+ this.longpress = createEvent(this, "longpress");
2325
+ this.core = new KritzelCore(this);
2326
+ }
2327
+ componentWillLoad() {
2328
+ this.validateScaleMax(this.scaleMax);
2329
+ this.validateScaleMin(this.scaleMin);
2330
+ }
2331
+ async componentDidLoad() {
2332
+ this.contextMenuHandler = new KritzelContextMenuHandler(this.core, this.globalContextMenuItems, this.objectContextMenuItems);
2333
+ this.keyHandler = new KritzelKeyHandler(this.core);
2334
+ this.viewport = new KritzelViewport(this.core, this.host);
2335
+ await this.core.initializeDatabase();
2336
+ await this.core.initializeWorkspace(this.workspace);
2337
+ this._registerStateChangeListeners();
2338
+ if (this.core.store.state.isReady === false) {
2339
+ this.core.store.setState('isReady', true);
2340
+ this.isEngineReady.emit(this.core.store.state);
2341
+ }
2258
2342
  }
2259
2343
  _registerStateChangeListeners() {
2260
- this.store.onStateChange('activeTool', this._handleActiveToolChange.bind(this));
2261
- this.store.onStateChange('isFocused', this._handleIsFocusedChange.bind(this));
2344
+ this.core.store.onStateChange('activeTool', this._handleActiveToolChange.bind(this));
2262
2345
  }
2263
2346
  _handleActiveToolChange(activeTool) {
2264
2347
  if (!(activeTool instanceof KritzelSelectionTool)) {
2265
- this.store.clearSelection();
2348
+ this.core.clearSelection();
2266
2349
  }
2267
- this.store.state.skipContextMenu = false;
2350
+ this.core.store.setState('skipContextMenu', false);
2268
2351
  this.activeToolChange.emit(activeTool);
2269
2352
  KritzelKeyboardHelper.forceHideKeyboard();
2270
2353
  }
2271
- _handleIsFocusedChange(isFocused) {
2272
- if (!isFocused) {
2273
- this.store.resetActiveText();
2274
- }
2275
- }
2276
2354
  render() {
2277
2355
  const computedStyle = window.getComputedStyle(this.host);
2278
2356
  const baseHandleSizePx = computedStyle.getPropertyValue('--kritzel-selection-handle-size').trim() || '6px';
2279
2357
  const baseHandleSize = parseFloat(baseHandleSizePx);
2280
2358
  const baseHandleTouchSize = baseHandleSize * 2 < 14 ? 14 : baseHandleSize;
2281
- return (h(Host, { key: 'fd353ff17bcde1a9ab646b6f463d1c6ce00a3dff' }, h("div", { key: '45bc2af8f1a3a2bfa3aa76a478c7bf208027da0c', class: "debug-panel", style: { display: this.store.state.debugInfo.showViewportInfo ? 'block' : 'none' } }, h("div", { key: '50e932febc35c7dbe852ad99d96ca4f0e0b742fc' }, "ActiveWorkspaceId: ", this.store.state?.activeWorkspace?.id), h("div", { key: 'af94b5061f0803588fece6cccdf540f46f13ca05' }, "ActiveWorkspaceName: ", this.store.state?.activeWorkspace?.name), h("div", { key: '89c0d21ce94f4eda72153554fadbd6942e785edc' }, "TranslateX: ", this.store.state?.translateX), h("div", { key: '340b5165265241972a7a940268c7940063ba8c12' }, "TranslateY: ", this.store.state?.translateY), h("div", { key: '428054b3ea4a1c327f03d6b37bfe6331dea6c57b' }, "ViewportWidth: ", this.store.state?.viewportWidth), h("div", { key: 'd67420ef633627413066a28b8ef9ac43c520015d' }, "ViewportHeight: ", this.store.state?.viewportHeight), h("div", { key: 'dedf9eb89c79fa496f7b6d0df9c646898f66b3d4' }, "ObjectsInViewport. ", this.store.objects.length), h("div", { key: '59bb8416941fd84305f2892f24098f6f4a084401' }, "Scale: ", this.store.state?.scale), h("div", { key: '6705a4cec22e4e33f75e296e17bc2952a3d1cba7' }, "ActiveTool: ", this.store.state?.activeTool?.name), h("div", { key: 'ca22e0a377a11fdca851b38f1bf425648cd3b9dd' }, "HasViewportChanged: ", this.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '57508b9ee24a5af631e6bb1eace404c39af14f82' }, "IsEnabled: ", this.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: 'f6cea367b5007f767afb25a033215abda734de9d' }, "IsScaling: ", this.store.state?.isScaling ? 'true' : 'false'), h("div", { key: '4386ef749facd2e54da7f58aa2713b87ed76f2df' }, "IsPanning: ", this.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '1713185b36a50dfe0f9efa0c92394222db80a377' }, "IsFocused: ", this.store.state.isFocused ? 'true' : 'false'), h("div", { key: '5104f428b808e7d843712302ad2e58b619876bee' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '2cb3b27a00627188e7082fa94169eb961a1ae6ed' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: '7407656e61be665f27e706738faa6d318e2c1d04' }, "IsResizeHandleSelected: ", this.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: '701bf05c25cb3d3728af6602f694e6064627ea59' }, "IsRotationHandleSelected: ", this.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: '772c345ea9c64ef800fdbb26919f1a54ca889025' }, "IsDrawing: ", this.store.state.isDrawing ? 'true' : 'false'), h("div", { key: 'dc687c8ba24182b8b61979ad334b989d3be72ec6' }, "IsWriting: ", this.store.state.isWriting ? 'true' : 'false'), h("div", { key: '10cbc575a7905396a76eca4e7b56be719755aeb4' }, "PointerX: ", this.store.state?.pointerX), h("div", { key: '4f21199328ffadddcc58b7d6b102a89e5079f676' }, "PointerY: ", this.store.state?.pointerY), h("div", { key: 'ac705f38cb323b8dc8cbf95f875657c5dec5c9ae' }, "SelectedObjects: ", this.store.state.selectionGroup?.objects.length || 0)), h("div", { key: '2ca55c53246e64520af6720a3f87d2357295ca7f', id: "origin", class: "origin", style: {
2282
- transform: `matrix(${this.store.state?.scale}, 0, 0, ${this.store.state?.scale}, ${this.store.state?.translateX}, ${this.store.state?.translateY})`,
2283
- } }, this.store.state.objectsMap.allObjects()?.map(object => {
2284
- return (h("div", { key: object.id, style: { display: object.isInViewport() ? 'block' : 'none', transform: object?.transformationMatrix, transformOrigin: 'top left', zIndex: object.zIndex.toString(), position: 'absolute' } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", id: object.id, class: "object", style: {
2359
+ return (h(Host, { key: 'da47553aad7abf8b5daab177c6933a9177b91089' }, h("div", { key: '4e64b43bfb85a61154d36ca8ecd3518d61445d50', class: "debug-panel", style: { display: this.core.store.state.debugInfo.showViewportInfo ? 'block' : 'none' } }, h("div", { key: '21742da9258a2b929b81c0ca6c8f37f41b228ad4' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: 'de31fcf57b0faf8fad2bb39336eeea35dbec35ca' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: 'a2cb298a867f92349b5e1fb556ee5f9c6110f1c7' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: '28697bfcecf9f8b4b1972a90cd02855767433047' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: '7fb25f6e9c9b8dea11832dbd311d2cc0b981cbeb' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: '92aeade312b3d28e4c9b0e1c7ca55f6932fd23d9' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: 'a4fd8090acaf094e44fdc2e72fcc388695b412c4' }, "Scale: ", this.core.store.state?.scale), h("div", { key: '6ff28100b64bafdffcb8fe9d49cd041a6a374817' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: '12a61ad3d070563eb721d0d4068143962914b2bc' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '437309daa2af1a64c9b9d3548fe12e075dd4a8bd' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: 'e6841095c220ebf081604c548729f085ec9d17bd' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: 'b07316a528782f7560c2e42f7bd9edd473cc256c' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '7160a5aa21c4cdbf2b523f620c819ad541a2e466' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '9ad29a686bc76b47d4c5040121b468428ade437a' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: '68f240aa7d7188996647afd0df73d63a253e18a1' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: '260010c089bdf0e8fd8c2406c39394ef79a85262' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: '6b07975c781801b0a7d7727d0666a6765aa9e889' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: '83c949c9ed26c3d445421ba1f965a742f5fc149f' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: '1687122785d3370da5d91a975dd56f11aebc81c1' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'a28e152a0510c9e3eef5624de1b5512baf45b37c' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: '09e5a0157002fe95a46415d32a3eb17be8d959a9' }, "SelectedObjects: ", this.core.store.state.selectionGroup?.objects.length || 0)), h("div", { key: '5228fbae773f30d91b129c257ef08adca10a6a70', id: "origin", class: "origin", style: {
2360
+ transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
2361
+ } }, this.core.store.state.objectsMap.allObjects()?.map(object => {
2362
+ return (h("div", { key: object.id, style: {
2363
+ display: object.isInViewport() ? 'block' : 'none',
2364
+ transform: object?.transformationMatrix,
2365
+ transformOrigin: 'top left',
2366
+ zIndex: object.zIndex.toString(),
2367
+ position: 'absolute',
2368
+ } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", id: object.id, class: "object", style: {
2285
2369
  height: object?.totalHeight.toString(),
2286
2370
  width: object?.totalWidth.toString(),
2287
2371
  left: '0',
@@ -2338,69 +2422,71 @@ const KritzelEngine = class {
2338
2422
  } })), KritzelClassHelper.isInstanceOf(object, 'KrtizelSelectionBox') && (h("div", { ref: el => (el ? object.mount(el) : object.unmount()), style: {
2339
2423
  width: '100%',
2340
2424
  height: '100%',
2425
+ backgroundColor: KritzelDevicesHelper.isFirefox() ? object.backgroundColor : 'transparent',
2426
+ borderWidth: KritzelDevicesHelper.isFirefox() ? object.borderWidth + 'px' : '0',
2427
+ borderStyle: KritzelDevicesHelper.isFirefox() ? 'solid' : 'none',
2428
+ borderColor: KritzelDevicesHelper.isFirefox() ? object.borderColor : 'transparent',
2341
2429
  } }))), h("line", { x1: "0", y1: "0", x2: object.totalWidth, y2: "0", style: {
2342
2430
  stroke: 'var(--kritzel-selection-border-color, #007AFF)',
2343
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.store.state?.scale})`,
2431
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2344
2432
  strokeLinecap: 'square',
2345
2433
  }, visibility: object.isSelected ? 'visible' : 'hidden' }), h("line", { x1: "0", y1: "0", x2: "0", y2: object.totalHeight, style: {
2346
2434
  stroke: 'var(--kritzel-selection-border-color, #007AFF)',
2347
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.store.state?.scale})`,
2435
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2348
2436
  strokeLinecap: 'square',
2349
2437
  }, visibility: object.isSelected ? 'visible' : 'hidden' }), h("line", { x1: "0", y1: object.totalHeight, x2: object.totalWidth, y2: object.totalHeight, style: {
2350
2438
  stroke: 'var(--kritzel-selection-border-color, #007AFF)',
2351
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.store.state?.scale})`,
2439
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2352
2440
  strokeLinecap: 'square',
2353
2441
  }, visibility: object.isSelected ? 'visible' : 'hidden' }), h("line", { x1: object.totalWidth, y1: "0", x2: object.totalWidth, y2: object.totalHeight, style: {
2354
2442
  stroke: 'var(--kritzel-selection-border-color, #007AFF)',
2355
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.store.state?.scale})`,
2443
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2356
2444
  strokeLinecap: 'square',
2357
- }, visibility: object.isSelected ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle top-left", cx: "0", cy: "0", r: `${(baseHandleSize * object.scale) / this.store.state?.scale}`, style: {
2445
+ }, visibility: object.isSelected ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle top-left", cx: "0", cy: "0", r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
2358
2446
  fill: 'var(--kritzel-selection-handle-color, #000000)',
2359
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay top-left", cx: "0", cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.store.state?.scale}`, style: {
2447
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay top-left", cx: "0", cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2360
2448
  fill: 'transparent',
2361
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleSize * object.scale) / this.store.state?.scale}`, style: {
2449
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
2362
2450
  fill: 'var(--kritzel-selection-handle-color, #000000)',
2363
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.store.state?.scale}`, style: {
2451
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2364
2452
  fill: 'transparent',
2365
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.store.state?.scale}`, style: {
2453
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
2366
2454
  fill: 'var(--kritzel-selection-handle-color, #000000)',
2367
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.store.state?.scale}`, style: {
2455
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2368
2456
  fill: 'transparent',
2369
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.store.state?.scale}`, style: {
2457
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
2370
2458
  fill: 'var(--kritzel-selection-handle-color, #000000)',
2371
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.store.state?.scale}`, style: {
2459
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "resize-handle-overlay bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2372
2460
  fill: 'transparent',
2373
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.store.state?.scale), style: {
2461
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.core.store.state?.scale), style: {
2374
2462
  stroke: 'var(--kritzel-selection-border-color, #007AFF)',
2375
- strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.store.state?.scale})`,
2376
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.store.state?.scale), r: `${(baseHandleSize * object.scale) / this.store.state?.scale}`, style: {
2463
+ strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
2464
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
2377
2465
  fill: 'var(--kritzel-selection-handle-color, #000000)',
2378
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.store.state?.scale}`, style: {
2466
+ }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
2379
2467
  fill: 'transparent',
2380
2468
  cursor: 'grab',
2381
- }, visibility: object.isSelected && !this.isSelecting ? 'visible' : 'hidden' }), h("g", { style: { display: this.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' } }, "zIndex: ", object.zIndex), h("div", { style: { whiteSpace: 'nowrap' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap' } }, "rotation: ", object.rotation), h("div", { style: { whiteSpace: 'nowrap' } }, "x: ", object.x), h("div", { style: { whiteSpace: 'nowrap' } }, "y: ", object.y)))))));
2382
- }), h("svg", { key: '0098f1b8233d45f49dc8bdcc13c08f20c04b65e1', class: "object", xmlns: "http://www.w3.org/2000/svg", style: {
2383
- height: this.store.state.currentPath?.height.toString(),
2384
- width: this.store.state.currentPath?.width.toString(),
2469
+ }, 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' } }, "zIndex: ", object.zIndex), h("div", { style: { whiteSpace: 'nowrap' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap' } }, "rotation: ", object.rotation), h("div", { style: { whiteSpace: 'nowrap' } }, "x: ", object.x), h("div", { style: { whiteSpace: 'nowrap' } }, "y: ", object.y)))))));
2470
+ }), 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: {
2385
2471
  left: '0',
2386
2472
  top: '0',
2387
- zIndex: this.store.state.currentPath?.zIndex.toString(),
2473
+ zIndex: this.core.store.state.currentPath?.zIndex.toString(),
2388
2474
  position: 'absolute',
2389
- transform: this.store.state.currentPath?.transformationMatrix,
2475
+ transform: this.core.store.state.currentPath?.transformationMatrix,
2390
2476
  transformOrigin: 'top left',
2391
2477
  overflow: 'visible',
2392
- }, viewBox: this.store.state.currentPath?.viewBox }, h("path", { key: '08310713fa8f2f1f695b1b61bb2b6e5a5f77f192', d: this.store.state.currentPath?.d, fill: this.store.state.currentPath?.fill, stroke: this.store.state.currentPath?.stroke }))), this.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '2529447e26ba02689303be39cc593dfafc25b96c', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.store.state.contextMenuItems, objects: this.store.state.selectionGroup?.objects || [], style: {
2478
+ }, viewBox: this.core.store.state.currentPath?.viewBox }, h("path", { key: '6dedb398968d275166e042660c4718635b57da84', 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: '09ae0d7842918bcb4ae9fd16d416badc19942264', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.state.selectionGroup?.objects || [], style: {
2393
2479
  position: 'fixed',
2394
- left: `${this.store.state.contextMenuX}px`,
2395
- top: `${this.store.state.contextMenuY}px`,
2480
+ left: `${this.core.store.state.contextMenuX}px`,
2481
+ top: `${this.core.store.state.contextMenuY}px`,
2396
2482
  zIndex: '10000',
2397
2483
  }, onActionSelected: event => {
2398
2484
  event.detail.action({
2399
- x: (-this.store.state.translateX + this.store.state.contextMenuX) / this.store.state.scale,
2400
- y: (-this.store.state.translateY + this.store.state.contextMenuY) / this.store.state.scale,
2401
- }, this.store.state.selectionGroup?.objects);
2485
+ x: (-this.core.store.state.translateX + this.core.store.state.contextMenuX) / this.core.store.state.scale,
2486
+ y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
2487
+ }, this.core.store.state.selectionGroup?.objects);
2402
2488
  this.hideContextMenu();
2403
- } })), this.store.state?.activeTool instanceof KritzelEraserTool && !this.store.state.isScaling && h("kritzel-cursor-trail", { key: '7c10277160eb1bc51581e4dfbdd4d0cdf626ed8c', store: this.store })));
2489
+ }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: 'e0863ccf8c52ebef822827d8eeac62d3619134ca', core: this.core })));
2404
2490
  }
2405
2491
  static get watchers() { return {
2406
2492
  "workspace": ["onWorkspaceChange"],
@@ -2420,7 +2506,7 @@ const KritzelFont = class {
2420
2506
  size = 24;
2421
2507
  color = '#000000';
2422
2508
  render() {
2423
- return (h(Host, { key: 'd318355704f1bf66468dd793e5e38da827076d3b' }, h("div", { key: '447b4fba97f5d1900060859943438733667aed08', class: "font-preview", style: {
2509
+ return (h(Host, { key: '0d0f0f75b64f579ca236950334fafde7f0ef2a38' }, h("div", { key: 'e71524879ded9727891bdd43f1a41ae5eef49175', class: "font-preview", style: {
2424
2510
  fontFamily: this.fontFamily,
2425
2511
  fontSize: `${this.size}px`,
2426
2512
  color: this.color
@@ -2467,7 +2553,7 @@ const KritzelFontFamily = class {
2467
2553
  label: option.label,
2468
2554
  style: { fontFamily: option.value },
2469
2555
  }));
2470
- return (h(Host, { key: '801b1dbc2b7da7d00fb00ed6a8d8ee7be3e9ef17' }, h("kritzel-dropdown", { key: '5f774c0b31ca16a1c8acda1c73ea3aacc2784649', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: this.selectedFontFamily } }, h("button", { key: '3c101155ff08854f665750f8988fb3691a77c04a', class: "font-style-button", slot: "suffix" }, "B"), h("button", { key: '48d2ead137a8a35f06fb8b5487431e2ce613c755', class: "font-style-button italic-text", slot: "suffix" }, "I"))));
2556
+ 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"))));
2471
2557
  }
2472
2558
  };
2473
2559
  KritzelFontFamily.style = kritzelFontFamilyCss;
@@ -2488,7 +2574,7 @@ const KritzelFontSize = class {
2488
2574
  this.sizeChange.emit(size);
2489
2575
  }
2490
2576
  render() {
2491
- return (h(Host, { key: '08571feed86b37208956608b170ca1f782b7fb18' }, this.sizes.map(size => (h("div", { class: {
2577
+ return (h(Host, { key: '583659340d8f3bfb2ff6f64f2cd692ac07cb32d6' }, this.sizes.map(size => (h("div", { class: {
2492
2578
  'size-container': true,
2493
2579
  'selected': this.selectedSize === size,
2494
2580
  }, onClick: () => this.handleSizeClick(size) }, h("kritzel-font", { fontFamily: this.fontFamily, size: size }))))));
@@ -2496,7 +2582,7 @@ const KritzelFontSize = class {
2496
2582
  };
2497
2583
  KritzelFontSize.style = kritzelFontSizeCss;
2498
2584
 
2499
- const kritzelIconCss = ":host{display:inline-flex;justify-content:center;align-items:center;}span{display:flex;align-items:center;width:100%;height:100%;}span>svg{width:100%;height:100%}";
2585
+ const kritzelIconCss = ":host{display:inline-flex;justify-content:center;align-items:center;color:var(--kritzel-icon-color, inherited)}span{display:flex;align-items:center;width:100%;height:100%;}span>svg{width:100%;height:100%}";
2500
2586
 
2501
2587
  const KritzelIcon = class {
2502
2588
  constructor(hostRef) {
@@ -2520,7 +2606,7 @@ const KritzelIcon = class {
2520
2606
  };
2521
2607
  KritzelIcon.style = kritzelIconCss;
2522
2608
 
2523
- const kritzelMenuCss = ":host{position:relative;display:flex;flex-direction:column;background-color:var(--kritzel-menu-background-color, #ffffff);width:var(--kritzel-menu-width, 180px);padding:var(--kritzel-menu-padding, 8px);border-radius:var(--kritzel-menu-border-radius, 12px);box-shadow:var(--kritzel-menu-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-menu-border, 1px solid #ebebeb);z-index:2;gap:var(--kritzel-menu-gap, 4px);overflow-y:auto;scrollbar-color:#ebebeb transparent;scrollbar-width:thin;max-height:300px}.has-open-child-overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:3}";
2609
+ const kritzelMenuCss = ":host{position:relative;display:flex;flex-direction:column;background-color:var(--kritzel-menu-background-color, #ffffff);width:var(--kritzel-menu-width, 200px);padding:var(--kritzel-menu-padding, 8px);border-radius:var(--kritzel-menu-border-radius, 12px);box-shadow:var(--kritzel-menu-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-menu-border, 1px solid #ebebeb);z-index:2;gap:var(--kritzel-menu-gap, 4px);overflow-y:auto;scrollbar-color:#ebebeb transparent;scrollbar-width:thin;max-height:300px}:host(:focus-visible){outline:var(--kritzel-menu-focus-outline, 2px solid #e3e3e3)}.has-open-child-overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:3}";
2524
2610
 
2525
2611
  const KritzelMenu = class {
2526
2612
  constructor(hostRef) {
@@ -2543,7 +2629,7 @@ const KritzelMenu = class {
2543
2629
  close;
2544
2630
  selectedIndex = null;
2545
2631
  async setFocus() {
2546
- const firstItem = this.host.querySelector('kritzel-menu-item');
2632
+ const firstItem = this.host.shadowRoot.querySelector('kritzel-menu-item');
2547
2633
  if (firstItem) {
2548
2634
  firstItem.focus();
2549
2635
  }
@@ -2579,12 +2665,12 @@ const KritzelMenu = class {
2579
2665
  this.itemCloseChildMenu.emit(event.detail);
2580
2666
  };
2581
2667
  render() {
2582
- return (h(Host, { key: 'c82bde4dc70fdc79df7471bb10396394f6c3870a', onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: '5fe0323aaa0da44abe736c6ef5e0516113c7820d', 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 })))));
2668
+ return (h(Host, { key: 'd971df2bd948b07f7bf2abc589c226d57891d05e', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'dfa6846429aac15a5912b87acd45610663200a3e', 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 })))));
2583
2669
  }
2584
2670
  };
2585
2671
  KritzelMenu.style = kritzelMenuCss;
2586
2672
 
2587
- const kritzelMenuItemCss = ":host{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--kritzel-menu-item-padding, 8px);box-sizing:border-box;gap:16px;height:var(--kritzel-menu-item-height, 40px);min-height:var(--kritzel-menu-item-min-height, 40px);font-family:sans-serif;font-size:var(--kritzel-menu-item-font-size, 14px);border-radius:var(--kritzel-menu-item-border-radius, 12px);outline:none;cursor:default}:host(:hover) .menu-item-overlay,:host(:focus-within) .menu-item-overlay{background-color:var(--kritzel-menu-item-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.selected){background-color:var(--kritzel-menu-item-selected-bg, #007aff);color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected) .action-button{color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected.editing){background-color:var(--kritzel-menu-item-selected-bg, #007aff)}:host(.selected) .edit-input{color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected) .edit-input::selection{background-color:var(--kritzel-menu-item-input-selection-color, rgba(255, 255, 255, 0.16))}:host(.editing){background-color:var(--kritzel-menu-item-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.disabled){opacity:0.5;pointer-events:none}:host(.child-open){background-color:var(--kritzel-menu-item-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.child-open.selected){background-color:var(--kritzel-menu-item-selected-bg, #007aff)}.menu-item-overlay{position:absolute;inset:0;background-color:transparent;z-index:0;pointer-events:none;border-radius:var(--kritzel-menu-item-border-radius, 12px)}.menu-item-content{display:flex;align-items:center;gap:8px;position:relative;z-index:1;height:100%}.left{justify-content:flex-start;flex:1;min-width:0}.left>div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.right{justify-content:flex-end}.edit-input{flex:1;height:var(--kritzel-menu-item-input-height, 24px);padding:0;background-color:transparent;border-radius:0;border:none;border-bottom:1px solid var(--kritzel-menu-item-input-border, #ccc);font-size:var(--kritzel-context-menu-item-font-size, 14px);width:100%;min-width:0;box-sizing:border-box;outline:none}.edit-input::selection{background-color:var(--kritzel-menu-item-input-selection-color, #007bff);color:var(--kritzel-menu-item-input-selection-text-color, #ffffff)}.action-button{padding:4px;border-radius:8px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;background-color:transparent;background:transparent;outline:none;-webkit-tap-highlight-color:transparent}.action-button:hover,.action-button:focus{background-color:var(--kritzel-menu-item-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.action-button.disabled{pointer-events:none;opacity:0.5}";
2673
+ const kritzelMenuItemCss = ":host{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--kritzel-menu-item-padding, 8px);box-sizing:border-box;gap:16px;height:var(--kritzel-menu-item-height, 40px);min-height:var(--kritzel-menu-item-min-height, 40px);font-family:sans-serif;font-size:var(--kritzel-menu-item-font-size, 14px);color:var(--kritzel-menu-item-color, #333333);border-radius:var(--kritzel-menu-item-border-radius, 12px);outline:none;cursor:default}:host(:hover) .menu-item-overlay,:host(:focus-within) .menu-item-overlay{background-color:var(--kritzel-menu-item-overlay-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.selected){background-color:var(--kritzel-menu-item-selected-bg, #007aff);color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected) .action-button{color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected.editing){background-color:var(--kritzel-menu-item-selected-bg, #007aff)}:host(.selected) .edit-input{color:var(--kritzel-menu-item-selected-color, #ffffff)}:host(.selected) .action-button kritzel-icon{--kritzel-icon-color:var(--kritzel-menu-item-selected-color, #ffffff)}kritzel-icon{--kritzel-icon-color:var(--kritzel-menu-item-color, #333333)}:host(.selected) .edit-input::selection{background-color:var(--kritzel-menu-item-input-selection-color, rgba(255, 255, 255, 0.16))}:host(.editing){background-color:var(--kritzel-menu-item-editing-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.disabled){opacity:0.5;pointer-events:none !important}:host(.child-open){background-color:var(--kritzel-menu-item-child-open-background-color, hsl(0, 0%, 0%, 4.3%))}:host(.child-open.selected){background-color:var(--kritzel-menu-item-selected-bg, #007aff)}.menu-item-overlay{position:absolute;inset:0;background-color:transparent;z-index:0;pointer-events:none;border-radius:var(--kritzel-menu-item-border-radius, 12px)}.menu-item-content{display:flex;align-items:center;gap:8px;position:relative;z-index:1;height:100%}.left{justify-content:flex-start;flex:1;min-width:0}.left>div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.right{justify-content:flex-end}.edit-input{flex:1;height:var(--kritzel-menu-item-input-height, 24px);padding:0;background-color:transparent;border-radius:0;border:none;border-bottom:1px solid var(--kritzel-menu-item-input-border, #ccc);font-size:var(--kritzel-context-menu-item-font-size, 14px);width:100%;min-width:0;box-sizing:border-box;outline:none}.edit-input::selection{background-color:var(--kritzel-menu-item-input-selection-color, #007bff);color:var(--kritzel-menu-item-input-selection-text-color, #ffffff)}.action-button{padding:4px;border-radius:8px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;background-color:transparent;background:transparent;outline:none;-webkit-tap-highlight-color:transparent}.action-button:hover,.action-button:focus{background-color:var(--kritzel-menu-item-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.action-button.disabled{pointer-events:none;opacity:0.5}";
2588
2674
 
2589
2675
  const KritzelMenuItem = class {
2590
2676
  constructor(hostRef) {
@@ -2610,18 +2696,32 @@ const KritzelMenuItem = class {
2610
2696
  itemCloseChildMenu;
2611
2697
  isDirty = false;
2612
2698
  inputRef;
2613
- componentDidLoad() {
2699
+ focusInput() {
2614
2700
  if (this.item.isEditing && this.inputRef && !this.isDirty) {
2615
2701
  this.inputRef.focus();
2616
- this.inputRef.select();
2702
+ if (KritzelDevicesHelper.isIOS()) {
2703
+ const length = this.inputRef.value.length;
2704
+ this.inputRef.setSelectionRange(length, length);
2705
+ }
2706
+ else {
2707
+ this.inputRef.select();
2708
+ }
2617
2709
  }
2618
2710
  }
2711
+ componentDidLoad() {
2712
+ this.setDeviceSpecificStyles();
2713
+ this.focusInput();
2714
+ }
2619
2715
  componentDidUpdate() {
2620
- if (this.item.isEditing && this.inputRef && !this.isDirty) {
2621
- this.inputRef.focus();
2622
- this.inputRef.select();
2623
- }
2716
+ this.focusInput();
2624
2717
  }
2718
+ setDeviceSpecificStyles = () => {
2719
+ const isTouchDevice = KritzelDevicesHelper.isTouchDevice();
2720
+ if (isTouchDevice) {
2721
+ this.host.style.setProperty('--kritzel-menu-item-overlay-background-color', 'transparent');
2722
+ this.host.style.setProperty('--kritzel-menu-item-button-hover-background-color', 'transparent');
2723
+ }
2724
+ };
2625
2725
  handleItemSelect = (event) => {
2626
2726
  event.stopPropagation();
2627
2727
  this.itemSelect.emit({ item: this.item, parent: this.parent });
@@ -2662,16 +2762,16 @@ const KritzelMenuItem = class {
2662
2762
  renderEditMode() {
2663
2763
  return [
2664
2764
  h("div", { class: "menu-item-content left" }, h("input", { ref: el => (this.inputRef = el), type: "text", class: "edit-input", value: this.item.label, onInput: this.handleInputChange })),
2665
- h("div", { class: "menu-item-content right" }, h("div", { tabIndex: !this.isDirty && !this.item.isNewItem ? -1 : 0, class: { 'action-button': true, 'disabled': !this.isDirty && !this.item.isNewItem }, onClick: this.handleSave }, h("kritzel-icon", { name: "check", size: 16 })), h("div", { tabIndex: 0, class: "action-button", onClick: this.handleCancel }, h("kritzel-icon", { name: "x", size: 16 }))),
2765
+ h("div", { class: "menu-item-content right" }, h("div", { tabIndex: 0, class: "action-button", onClick: this.handleCancel }, h("kritzel-icon", { name: "x", size: 16 })), h("div", { tabIndex: !this.isDirty && !this.item.isNewItem ? -1 : 0, class: { 'action-button': true, 'disabled': !this.isDirty && !this.item.isNewItem }, onClick: this.handleSave }, h("kritzel-icon", { name: "check", size: 16 }))),
2666
2766
  ];
2667
2767
  }
2668
2768
  render() {
2669
- return (h(Host, { key: '5440ed43726d00ab65e7f423f065c1a3fa74e39e', tabIndex: 0, class: {
2769
+ return (h(Host, { key: 'a35e1e3427568f436a36b43ba87af3710a4e83c5', tabIndex: this.item.isDisabled ? -1 : 0, class: {
2670
2770
  'selected': this.item.isSelected,
2671
2771
  'editing': this.item.isEditing,
2672
2772
  'disabled': this.item.isDisabled,
2673
2773
  'child-open': this.item.isChildMenuOpen,
2674
- }, onClick: this.handleItemSelect }, h("div", { key: '69542710179216a1df47bde5d474a72e4a07aa5b', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
2774
+ }, onClick: this.handleItemSelect }, h("div", { key: '42eef5a16b9b164839c1fe133e38ecb505c07632', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
2675
2775
  }
2676
2776
  static get watchers() { return {
2677
2777
  "item": ["onItemChange"]
@@ -2679,6 +2779,70 @@ const KritzelMenuItem = class {
2679
2779
  };
2680
2780
  KritzelMenuItem.style = kritzelMenuItemCss;
2681
2781
 
2782
+ class KritzelHTMLHelper {
2783
+ static getNumericValueFromStyle(element, property) {
2784
+ const value = window.getComputedStyle(element).getPropertyValue(property);
2785
+ return parseFloat(value) || 0;
2786
+ }
2787
+ static getScrollableParent(element) {
2788
+ if (!element) {
2789
+ return window;
2790
+ }
2791
+ const parent = element.parentNode?.host ?? element.parentElement;
2792
+ if (!parent || parent.tagName === 'BODY') {
2793
+ return window;
2794
+ }
2795
+ const style = window.getComputedStyle(parent);
2796
+ if (style.overflow === 'auto' || style.overflowY === 'auto' || style.overflow === 'scroll' || style.overflowY === 'scroll') {
2797
+ return parent;
2798
+ }
2799
+ return this.getScrollableParent(parent);
2800
+ }
2801
+ static isElementInViewport(element) {
2802
+ if (!element) {
2803
+ return false;
2804
+ }
2805
+ const scrollableParent = this.getScrollableParent(element);
2806
+ const rect = element.getBoundingClientRect();
2807
+ if (scrollableParent === window) {
2808
+ const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
2809
+ const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
2810
+ return rect.top >= 0 && rect.left >= 0 && rect.bottom <= viewportHeight && rect.right <= viewportWidth;
2811
+ }
2812
+ const parentRect = scrollableParent.getBoundingClientRect();
2813
+ return rect.top >= parentRect.top && rect.left >= parentRect.left && rect.bottom <= parentRect.bottom && rect.right <= parentRect.right;
2814
+ }
2815
+ static getFocusableElements(root) {
2816
+ if (!root)
2817
+ return [];
2818
+ const focusableElements = [];
2819
+ const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details, [tabindex]:not([tabindex="-1"])';
2820
+ const isVisible = (el) => {
2821
+ return el.offsetParent !== null;
2822
+ };
2823
+ const find = (element) => {
2824
+ // Check if the element itself is focusable
2825
+ if (element instanceof HTMLElement && element.matches(focusableSelector) && !element.hasAttribute('disabled') && isVisible(element)) {
2826
+ focusableElements.push(element);
2827
+ }
2828
+ // Traverse shadow DOM
2829
+ if (element.shadowRoot) {
2830
+ Array.from(element.shadowRoot.children).forEach(find);
2831
+ }
2832
+ // Traverse slotted content
2833
+ if (element.tagName === 'SLOT') {
2834
+ element.assignedElements({ flatten: true }).forEach(find);
2835
+ }
2836
+ // Traverse light DOM children if there is no shadow root
2837
+ if (!element.shadowRoot) {
2838
+ Array.from(element.children).forEach(find);
2839
+ }
2840
+ };
2841
+ find(root);
2842
+ return focusableElements;
2843
+ }
2844
+ }
2845
+
2682
2846
  const KritzelPortal = class {
2683
2847
  constructor(hostRef) {
2684
2848
  registerInstance(this, hostRef);
@@ -2754,7 +2918,7 @@ const KritzelPortal = class {
2754
2918
  return activeEl;
2755
2919
  }
2756
2920
  trapFocus(event) {
2757
- const focusableElements = this.getFocusableElements(this.host);
2921
+ const focusableElements = KritzelHTMLHelper.getFocusableElements(this.host);
2758
2922
  if (focusableElements.length === 0)
2759
2923
  return;
2760
2924
  const firstFocusable = focusableElements[0];
@@ -2775,51 +2939,12 @@ const KritzelPortal = class {
2775
2939
  }
2776
2940
  }
2777
2941
  }
2778
- getFocusableElements(root) {
2779
- if (!root)
2780
- return [];
2781
- const focusableElements = [];
2782
- const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details, [tabindex]:not([tabindex="-1"])';
2783
- const isVisible = (el) => {
2784
- return el.offsetParent !== null;
2785
- };
2786
- // Check if the root element itself is focusable
2787
- if (root.matches(focusableSelector) && !root.hasAttribute('disabled') && isVisible(root)) {
2788
- focusableElements.push(root);
2789
- }
2790
- // Function to recursively find focusable elements
2791
- const findFocusable = (element) => {
2792
- // Search in shadow root
2793
- if (element.shadowRoot) {
2794
- Array.from(element.shadowRoot.querySelectorAll(focusableSelector)).forEach(el => {
2795
- if (isVisible(el)) {
2796
- focusableElements.push(el);
2797
- }
2798
- });
2799
- Array.from(element.shadowRoot.children).forEach(findFocusable);
2800
- }
2801
- // Search in light DOM
2802
- Array.from(element.querySelectorAll(focusableSelector)).forEach(el => {
2803
- if (!focusableElements.includes(el) && isVisible(el)) {
2804
- focusableElements.push(el);
2805
- }
2806
- });
2807
- // Handle slotted content
2808
- if (element.tagName === 'SLOT') {
2809
- element.assignedElements({ flatten: true }).forEach(el => findFocusable(el));
2810
- }
2811
- Array.from(element.children).forEach(findFocusable);
2812
- };
2813
- findFocusable(root);
2814
- // Return unique elements in document order
2815
- return [...new Set(focusableElements)];
2816
- }
2817
2942
  get firstFocusableElement() {
2818
2943
  const slotEl = this.host.shadowRoot?.querySelector('slot');
2819
2944
  const firstAssigned = slotEl?.assignedElements({ flatten: true })[0];
2820
2945
  if (!firstAssigned)
2821
2946
  return null;
2822
- const focusable = this.getFocusableElements(firstAssigned);
2947
+ const focusable = KritzelHTMLHelper.getFocusableElements(firstAssigned);
2823
2948
  return focusable[0] ?? firstAssigned;
2824
2949
  }
2825
2950
  get lastAddedPortal() {
@@ -2878,25 +3003,26 @@ const KritzelPortal = class {
2878
3003
  this.portal.style.left = `${left}px`;
2879
3004
  }
2880
3005
  render() {
2881
- return (h(Host, { key: '968f0360b9396da16f5b970293ba20f8a1dcc09a', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '0fe1569bde60a834e9226d7c838d113a64151164' })));
3006
+ return (h(Host, { key: 'a994d8ab8c758bc92836693f35f8d9415913cfff', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: 'a9b9a71d82e9b57de24e5ecfa90197a27ed691c4' })));
2882
3007
  }
2883
3008
  static get watchers() { return {
2884
3009
  "anchor": ["anchorChanged"]
2885
3010
  }; }
2886
3011
  };
2887
3012
 
2888
- const kritzelSplitButtonCss = ":host{position:relative;display:flex;align-items:center;font-family:sans-serif;z-index:1;padding:var(--kritzel-split-button-padding, 4px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-split-button-border, 1px solid #ebebeb);gap:var(--kritzel-split-button-gap, 4px)}:host(:focus){outline:none}:host(.mobile){--kritzel-split-button-hover-background-color:transparent}button{border:none;background-color:transparent;padding:0;margin:0;font-family:inherit;font-size:inherit;color:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;text-align:center;display:flex;align-items:center;justify-content:center;pointer-events:all;-webkit-tap-highlight-color:transparent}.split-main-button,.split-menu-button{height:auto;display:flex;align-items:center;padding:var(--kritzel-split-button-padding, 8px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);font-size:var(--kritzel-split-button-font-size, 14px)}.split-main-button:hover,.split-menu-button:hover{background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button:focus,.split-menu-button:focus{outline:none;background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button{gap:var(--kritzel-split-button-gap, 4px)}.split-menu-button{border-left:none;justify-content:center}.split-divider{width:var(--kritzel-split-button-divider-width, 1px);height:24px;background-color:var(--kritzel-split-button-divider-background-color, hsl(0, 0%, 0%, 4.3%))}:disabled{pointer-events:none;opacity:0.5}";
3013
+ const kritzelSplitButtonCss = ":host{position:relative;display:flex;align-items:center;font-family:sans-serif;z-index:1;padding:var(--kritzel-split-button-padding, 4px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-split-button-border, 1px solid #ebebeb);gap:var(--kritzel-split-button-gap, 4px)}:host(.mobile){--kritzel-split-button-hover-background-color:transparent}button{border:none;background-color:transparent;padding:0;margin:0;font-family:inherit;font-size:inherit;color:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;text-align:center;display:flex;align-items:center;justify-content:center;pointer-events:all;-webkit-tap-highlight-color:transparent}.split-main-button,.split-menu-button{height:auto;display:flex;align-items:center;padding:var(--kritzel-split-button-padding, 8px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);font-size:var(--kritzel-split-button-font-size, 14px)}.split-main-button:hover,.split-menu-button:hover{background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button:focus,.split-menu-button:focus{outline:none;background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button{gap:var(--kritzel-split-button-gap, 4px)}.split-menu-button{border-left:none;justify-content:center}.split-divider{width:var(--kritzel-split-button-divider-width, 1px);height:24px;background-color:var(--kritzel-split-button-divider-background-color, hsl(0, 0%, 0%, 4.3%))}:disabled{pointer-events:none;opacity:0.5}";
2889
3014
 
2890
3015
  const KritzelSplitButton = class {
2891
3016
  constructor(hostRef) {
2892
3017
  registerInstance(this, hostRef);
2893
- this.buttonClick = createEvent(this, "buttonClick");
3018
+ this.mainButtonClick = createEvent(this, "mainButtonClick");
2894
3019
  this.itemSelect = createEvent(this, "itemSelect");
2895
3020
  this.itemSave = createEvent(this, "itemSave");
2896
3021
  this.itemCancel = createEvent(this, "itemCancel");
2897
3022
  this.itemToggleChildMenu = createEvent(this, "itemToggleChildMenu");
2898
3023
  this.itemCloseChildMenu = createEvent(this, "itemCloseChildMenu");
2899
- this.close = createEvent(this, "close");
3024
+ this.menuOpen = createEvent(this, "menuOpen");
3025
+ this.menuClose = createEvent(this, "menuClose");
2900
3026
  }
2901
3027
  get host() { return getElement(this); }
2902
3028
  buttonIcon = 'plus';
@@ -2904,13 +3030,14 @@ const KritzelSplitButton = class {
2904
3030
  items = [];
2905
3031
  mainButtonDisabled = false;
2906
3032
  menuButtonDisabled = false;
2907
- buttonClick;
3033
+ mainButtonClick;
2908
3034
  itemSelect;
2909
3035
  itemSave;
2910
3036
  itemCancel;
2911
3037
  itemToggleChildMenu;
2912
3038
  itemCloseChildMenu;
2913
- close;
3039
+ menuOpen;
3040
+ menuClose;
2914
3041
  isMenuOpen = false;
2915
3042
  isTouchDevice = KritzelDevicesHelper.isTouchDevice();
2916
3043
  anchorElement;
@@ -2919,11 +3046,18 @@ const KritzelSplitButton = class {
2919
3046
  async open() {
2920
3047
  if (this.isMenuOpen)
2921
3048
  return;
2922
- this.openMenu(new MouseEvent('click'));
3049
+ this.isMenuOpen = true;
3050
+ this.anchorElement = this.host;
3051
+ this.menuOpen.emit();
3052
+ }
3053
+ async focusMenu() {
3054
+ if (this.menuRef) {
3055
+ await this.menuRef.setFocus();
3056
+ }
2923
3057
  }
2924
3058
  handleButtonClick = (event) => {
2925
3059
  event.stopPropagation();
2926
- this.buttonClick.emit();
3060
+ this.mainButtonClick.emit();
2927
3061
  };
2928
3062
  toggleMenu = (event) => {
2929
3063
  event.stopPropagation();
@@ -2938,11 +3072,13 @@ const KritzelSplitButton = class {
2938
3072
  event.stopPropagation();
2939
3073
  this.isMenuOpen = true;
2940
3074
  this.anchorElement = this.host;
3075
+ this.menuOpen.emit();
2941
3076
  };
2942
3077
  closeMenu = () => {
2943
3078
  this.isMenuOpen = false;
2944
3079
  this.anchorElement = null;
2945
- this.close.emit();
3080
+ this.splitMenuButtonRef?.blur();
3081
+ this.menuClose.emit();
2946
3082
  };
2947
3083
  handleItemSelect = event => {
2948
3084
  this.itemSelect.emit(event.detail);
@@ -2960,12 +3096,12 @@ const KritzelSplitButton = class {
2960
3096
  this.itemCloseChildMenu.emit(event.detail);
2961
3097
  };
2962
3098
  render() {
2963
- return (h(Host, { key: 'be79d702d2c400d1feedeb89eca6fc78559f30f3', class: { mobile: this.isTouchDevice } }, h("button", { key: 'e4a74c56c122ea617f44f1d7e31672d1f913de46', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: '44bd79270e7cc4a17b45133b5c513642013e5a66', name: this.buttonIcon })), h("div", { key: '2392e8c6f75510c529585a69c861b2fcafdef5ce', class: "split-divider" }), h("button", { key: 'bcdf61c2a195271771479de385db3b4982f6cad2', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: '90383a8690111c97054fb8ac93b91cb6644de137', name: this.dropdownIcon })), h("kritzel-portal", { key: 'c6a4c32ab731fede13e1382bff9dbd68794b1103', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: '8b792c9a2d4af60ba464bb80551c5358e21bfa96', 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 }))));
3099
+ return (h(Host, { key: '2521559224e78ed1984446320a1601e77ccf2843', class: { mobile: this.isTouchDevice } }, h("button", { key: 'a924ad4590506cb5209ef9fa1babca5312ec0513', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: '214565d158d4d3c06ad883559aa7bac2827a593f', name: this.buttonIcon })), h("div", { key: '2f7d189c46c08227c3006d226a0ee3065f241bf4', class: "split-divider" }), h("button", { key: '4d6e2e224e3719fe3685ee289af94680c120abf6', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: 'bc8176681dfedde9d13b9af561d8bdff8613098f', name: this.dropdownIcon })), h("kritzel-portal", { key: 'afb44cd208f52350cbc82e050d6dee0ba734391d', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: 'b28f04138daa8777e6c9b2aa7fa3b5f2f62fd914', 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 }))));
2964
3100
  }
2965
3101
  };
2966
3102
  KritzelSplitButton.style = kritzelSplitButtonCss;
2967
3103
 
2968
- const kritzelStrokeSizeCss = ":host{display:flex;align-items:flex-start;gap:8px;padding:8px;box-sizing:border-box}.size-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}.size-container:hover{background-color:var(--kritzel-stroke-size-hover-background-color, #ebebeb)}.size-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-stroke-size-selected-background-color, #ebebeb)}";
3104
+ const kritzelStrokeSizeCss = ":host{display:flex;align-items:flex-start;gap:8px;padding:8px;box-sizing:border-box}.size-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}.size-container:focus-visible{outline:var(--kritzel-stroke-size-focus-outline, 2px auto #e3e3e3)}.size-container:hover{background-color:var(--kritzel-stroke-size-hover-background-color, #ebebeb)}.size-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-stroke-size-selected-background-color, #ebebeb)}";
2969
3105
 
2970
3106
  const KritzelStrokeSize = class {
2971
3107
  constructor(hostRef) {
@@ -2980,7 +3116,7 @@ const KritzelStrokeSize = class {
2980
3116
  this.sizeChange.emit(size);
2981
3117
  }
2982
3118
  render() {
2983
- return (h(Host, { key: 'f9f0fe49963655a2beeffe5c369ccbe018c8aa5e' }, this.sizes.map(size => (h("div", { class: {
3119
+ return (h(Host, { key: '001a0ef8408d19532b57a521929c0cba54e99c52' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
2984
3120
  'size-container': true,
2985
3121
  'selected': this.selectedSize === size,
2986
3122
  }, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size }))))));
@@ -2994,19 +3130,38 @@ const MOBILE_BREAKPOINT = 768;
2994
3130
  const KritzelTooltip = class {
2995
3131
  constructor(hostRef) {
2996
3132
  registerInstance(this, hostRef);
3133
+ this.tooltipClosed = createEvent(this, "tooltipClosed");
2997
3134
  }
3135
+ get host() { return getElement(this); }
2998
3136
  isVisible = false;
2999
3137
  anchorElement;
3000
3138
  arrowSize = 8;
3001
3139
  offsetY = 24;
3002
- get el() { return getElement(this); }
3140
+ tooltipClosed;
3003
3141
  positionX = 0;
3004
3142
  arrowOffset = '0px';
3005
3143
  isMobileView = window.innerWidth < MOBILE_BREAKPOINT;
3144
+ handleOutsideClick(event) {
3145
+ if (!this.isVisible)
3146
+ return;
3147
+ const target = event.target;
3148
+ if (!this.host.contains(target)) {
3149
+ this.tooltipClosed.emit();
3150
+ }
3151
+ }
3006
3152
  handleWindowResize() {
3007
3153
  this.isMobileView = window.innerWidth < MOBILE_BREAKPOINT;
3008
3154
  this.calculateAdjustedPosition();
3009
3155
  }
3156
+ async focusContent() {
3157
+ const focusableElements = KritzelHTMLHelper.getFocusableElements(this.host);
3158
+ if (focusableElements.length > 0) {
3159
+ focusableElements[0].focus();
3160
+ }
3161
+ }
3162
+ componentDidLoad() {
3163
+ this.focusSlottedContent();
3164
+ }
3010
3165
  componentWillLoad() {
3011
3166
  this.isMobileView = window.innerWidth < MOBILE_BREAKPOINT;
3012
3167
  this.calculateAdjustedPosition();
@@ -3014,10 +3169,18 @@ const KritzelTooltip = class {
3014
3169
  componentWillUpdate() {
3015
3170
  this.calculateAdjustedPosition();
3016
3171
  }
3172
+ focusSlottedContent() {
3173
+ const slot = this.host.shadowRoot?.querySelector('slot');
3174
+ const assignedElements = slot?.assignedElements() || [];
3175
+ if (assignedElements.length > 0) {
3176
+ const firstElement = assignedElements[0];
3177
+ firstElement.focus();
3178
+ }
3179
+ }
3017
3180
  calculateAdjustedPosition() {
3018
3181
  if (this.isVisible && this.anchorElement) {
3019
3182
  const anchorRect = this.anchorElement.getBoundingClientRect();
3020
- const tooltipContent = this.el.shadowRoot?.querySelector('.tooltip-content');
3183
+ const tooltipContent = this.host.shadowRoot?.querySelector('.tooltip-content');
3021
3184
  if (!this.isMobileView) {
3022
3185
  this.positionX = anchorRect.left + anchorRect.width / 2;
3023
3186
  this.arrowOffset = `calc(${50}% - ${this.arrowSize}px)`;
@@ -3030,23 +3193,23 @@ const KritzelTooltip = class {
3030
3193
  }
3031
3194
  }
3032
3195
  render() {
3033
- return (h(Host, { key: '6eb67bcfd08234affe3724dff4d94ddf7907a1a7', style: {
3196
+ return (h(Host, { key: '8c3aeff60625f43f129afa70367cdb7a68a4b271', style: {
3034
3197
  position: 'fixed',
3035
3198
  zIndex: '9999',
3036
3199
  transition: 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out',
3037
3200
  visibility: this.isVisible ? 'visible' : 'hidden',
3038
3201
  left: !this.isMobileView ? `${this.positionX}px` : '50%',
3039
3202
  marginBottom: `${this.offsetY + this.arrowSize}px`,
3040
- } }, h("div", { key: '9314b30b71200776e3728027b2ac7332cf4ab669', class: "tooltip-content", onClick: event => event.stopPropagation() }, h("slot", { key: '80cb8d0a8a91d9c816580cedc02fc9382fb07f8c' }), h("div", { key: '87fb2399463a0eb7beb1ca0f2c2867d8ff033f3a', class: "tooltip-arrow-wrapper", style: {
3203
+ } }, h("div", { key: 'b22b606c2a836c2c9bbe21c6b470754753ccb309', class: "tooltip-content", onClick: event => event.stopPropagation() }, h("slot", { key: '783403f4b5560012c9f6bd184a8c5eb26428e148' }), h("div", { key: 'bb98400edc5c6e05fd4ed2a476a5821f93964b8e', class: "tooltip-arrow-wrapper", style: {
3041
3204
  position: 'fixed',
3042
3205
  left: this.arrowOffset,
3043
3206
  bottom: `-${this.arrowSize * 2}px`,
3044
- } }, h("div", { key: 'fc3953ad9b6aa5a4b2228653573fc3a7e37c0487', class: "tooltip-arrow", style: {
3207
+ } }, h("div", { key: '850a058d635113a7870f25fa288a6447394c53ed', class: "tooltip-arrow", style: {
3045
3208
  borderLeft: `${this.arrowSize}px solid transparent`,
3046
3209
  borderRight: `${this.arrowSize}px solid transparent`,
3047
3210
  borderTop: `${this.arrowSize}px solid var(--kritzel-controls-tooltip-background-color, #ffffff)`,
3048
3211
  filter: 'drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2))',
3049
- } }), h("div", { key: '5b8e4e3eb90c4c47c47fa47dc96e4149794e1732', class: "tooltip-arrow-rect", style: {
3212
+ } }), h("div", { key: 'bbb3dc2673e2dfe4443ad80540dfc9e5a25c6c06', class: "tooltip-arrow-rect", style: {
3050
3213
  position: 'relative',
3051
3214
  width: `${this.arrowSize * 2}px`,
3052
3215
  height: `${this.arrowSize}px`,
@@ -3057,7 +3220,7 @@ const KritzelTooltip = class {
3057
3220
  };
3058
3221
  KritzelTooltip.style = kritzelTooltipCss;
3059
3222
 
3060
- const kritzelUtilityPanelCss = ":host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:rgb(226, 226, 226);width:fit-content;user-select:none}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;outline:none;background:none;cursor:pointer;color:#333333;-webkit-tap-highlight-color:transparent}.utility-separator{width:1px;height:16px;background-color:hsl(0, 0%, 0%, 4.3%)}";
3223
+ const kritzelUtilityPanelCss = ":host{display:flex;flex-direction:row;align-items:center;padding:4px;gap:8px;border-top-left-radius:12px;border-top-right-radius:12px;background-color:rgb(226, 226, 226);width:fit-content;user-select:none}.utility-button{display:flex;justify-content:center;align-items:center;width:28px;height:28px;padding:8px 4px;border:none;outline:none;background:none;cursor:pointer;color:#333333;-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-utility-panel-button-border-radius, 8px)}.utility-button:focus{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.utility-separator{width:1px;height:16px;background-color:hsl(0, 0%, 0%, 4.3%)}";
3061
3224
 
3062
3225
  const KritzelUtilityPanel = class {
3063
3226
  constructor(hostRef) {
@@ -3082,7 +3245,7 @@ const KritzelUtilityPanel = class {
3082
3245
  this.redo.emit();
3083
3246
  }
3084
3247
  render() {
3085
- return (h(Host, { key: '134058928a840d11fdc39849b35f08b21840fc0c' }, h("button", { key: '8d80cb496983b0709c06bacb12ca6819789aa47d', class: "utility-button", onClick: event => this.handleUndo(event) }, h("kritzel-icon", { key: 'c6733ef61ab6a272f80a580243fdd15063b8bf0c', name: "undo" })), h("button", { key: 'dc6147152bccd43ea54b9af20d019d305e550987', class: "utility-button", onClick: event => this.handleRedo(event) }, h("kritzel-icon", { key: '3ab8bced0f398a8d5f053cb0f388199fd2148bfc', name: "redo" })), h("div", { key: 'ebbfd25fb69faf2b669de20dc74a3dcabc01f489', class: "utility-separator" }), h("button", { key: 'd86caf8a7f2c2bc899b09871f555973137693eb9', class: "utility-button" }, h("kritzel-icon", { key: 'e1b4e9eef3d3ab2a2ddd1688818d4bcd2d7226c1', name: "delete", onClick: () => this.delete.emit() }))));
3248
+ 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() }))));
3086
3249
  }
3087
3250
  };
3088
3251
  KritzelUtilityPanel.style = kritzelUtilityPanelCss;
@@ -3131,9 +3294,9 @@ const KritzelWorkspaceManager = class {
3131
3294
  this.workspaceChange.emit(item.value);
3132
3295
  }
3133
3296
  async add() {
3297
+ await this.splitButtonRef.open();
3134
3298
  this.newWorkspace = new KritzelWorkspace(ObjectHelper.generateUUID(), 'New Workspace');
3135
3299
  this.editingItemId = this.newWorkspace.id;
3136
- await this.splitButtonRef.open();
3137
3300
  }
3138
3301
  edit(item) {
3139
3302
  this.openChildMenuItem = null;
@@ -3144,11 +3307,14 @@ const KritzelWorkspaceManager = class {
3144
3307
  }
3145
3308
  async save(item) {
3146
3309
  if (this.newWorkspace) {
3147
- await this.kritzelEngineRef.createWorkspace({ ...item.value, name: item.label });
3310
+ this.newWorkspace.name = item.label;
3311
+ await this.kritzelEngineRef.createWorkspace(this.newWorkspace);
3148
3312
  this.workspaceChange.emit(this.newWorkspace);
3149
3313
  }
3150
3314
  else {
3151
- await this.kritzelEngineRef.updateWorkspace({ ...item.value, name: item.label });
3315
+ const workspace = item.value;
3316
+ workspace.name = item.label;
3317
+ await this.kritzelEngineRef.updateWorkspace(workspace);
3152
3318
  }
3153
3319
  this.editingItemId = null;
3154
3320
  this.newWorkspace = null;
@@ -3161,6 +3327,11 @@ const KritzelWorkspaceManager = class {
3161
3327
  this.openChildMenuItem = null;
3162
3328
  this.childMenuAnchor = null;
3163
3329
  await this.kritzelEngineRef.deleteWorkspace(item.value);
3330
+ if (item.value.id === this.activeWorkspace?.id) {
3331
+ this.activeWorkspace = this.sortedWorkspaces.find(ws => ws.id !== item.value.id) || null;
3332
+ this.workspaceChange.emit(this.activeWorkspace);
3333
+ }
3334
+ await this.splitButtonRef.focusMenu();
3164
3335
  }
3165
3336
  toggleChildMenu(item, anchor) {
3166
3337
  this.openChildMenuItem = item;
@@ -3170,12 +3341,15 @@ const KritzelWorkspaceManager = class {
3170
3341
  this.openChildMenuItem = null;
3171
3342
  this.childMenuAnchor = null;
3172
3343
  }
3173
- closeMenu() {
3344
+ handleMenuOpen() {
3345
+ this.kritzelEngineRef.disable();
3346
+ }
3347
+ handleMenuClose() {
3174
3348
  this.cancel();
3175
3349
  this.closeChildMenu();
3350
+ this.kritzelEngineRef.enable();
3176
3351
  }
3177
3352
  render() {
3178
- console.log('render workspace manager');
3179
3353
  const menuItems = this.sortedWorkspaces
3180
3354
  .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
3181
3355
  .filter(ws => ws !== null)
@@ -3200,17 +3374,16 @@ const KritzelWorkspaceManager = class {
3200
3374
  id: `${ws.id}-delete`,
3201
3375
  label: 'Delete',
3202
3376
  value: 'delete',
3377
+ isDisabled: this.sortedWorkspaces.length <= 1,
3203
3378
  action: (_item, parent) => this.delete(parent),
3204
3379
  },
3205
3380
  ],
3206
3381
  };
3207
3382
  });
3208
- return (h(Host, null, h("kritzel-split-button", { ref: el => (this.splitButtonRef = el), items: menuItems, mainButtonDisabled: this.editingItemId != null, onButtonClick: () => this.add(), onItemSelect: event => this.select(event.detail.item, event.detail.parent), onItemToggleChildMenu: event => this.toggleChildMenu(event.detail.item, event.detail.childMenuAnchor), onItemSave: event => this.save(event.detail), onItemCancel: () => this.cancel(), onItemCloseChildMenu: () => this.closeChildMenu(), onClose: () => {
3209
- this.closeMenu();
3210
- } })));
3383
+ return (h(Host, null, h("kritzel-split-button", { ref: el => (this.splitButtonRef = el), items: menuItems, mainButtonDisabled: this.editingItemId != null, onMainButtonClick: () => this.add(), onItemSelect: event => this.select(event.detail.item, event.detail.parent), onItemToggleChildMenu: event => this.toggleChildMenu(event.detail.item, event.detail.childMenuAnchor), onItemSave: event => this.save(event.detail), onItemCancel: () => this.cancel(), onItemCloseChildMenu: () => this.closeChildMenu(), onMenuOpen: () => this.handleMenuOpen(), onMenuClose: () => this.handleMenuClose() })));
3211
3384
  }
3212
3385
  };
3213
3386
  KritzelWorkspaceManager.style = kritzelWorkspaceManagerCss;
3214
3387
 
3215
- export { KritzelBrushStyle as kritzel_brush_style, KritzelColor as kritzel_color, KritzelColorPalette as kritzel_color_palette, KritzelContextMenu as kritzel_context_menu, KritzelControlBrushConfig as kritzel_control_brush_config, KritzelControlTextConfig as kritzel_control_text_config, KritzelControls as kritzel_controls, KritzelCursorTrail as kritzel_cursor_trail, KritzelDropdown as kritzel_dropdown, KritzelEditor as kritzel_editor, KritzelEngine as kritzel_engine, KritzelFont as kritzel_font, KritzelFontFamily as kritzel_font_family, KritzelFontSize as kritzel_font_size, KritzelIcon as kritzel_icon, KritzelMenu as kritzel_menu, KritzelMenuItem as kritzel_menu_item, KritzelPortal as kritzel_portal, KritzelSplitButton as kritzel_split_button, KritzelStrokeSize as kritzel_stroke_size, KritzelTooltip as kritzel_tooltip, KritzelUtilityPanel as kritzel_utility_panel, KritzelWorkspaceManager as kritzel_workspace_manager };
3216
- //# sourceMappingURL=kritzel-brush-style.kritzel-color.kritzel-color-palette.kritzel-context-menu.kritzel-control-brush-config.kritzel-control-text-config.kritzel-controls.kritzel-cursor-trail.kritzel-dropdown.kritzel-editor.kritzel-engine.kritzel-font.kritzel-font-family.kritzel-font-size.kritzel-icon.kritzel-menu.kritzel-menu-item.kritzel-portal.kritzel-split-button.kritzel-stroke-size.kritzel-tooltip.kritzel-utility-panel.kritzel-workspace-manager.entry.js.map
3388
+ export { KritzelColor as kritzel_color, KritzelColorPalette as kritzel_color_palette, KritzelContextMenu as kritzel_context_menu, KritzelControlBrushConfig as kritzel_control_brush_config, KritzelControlTextConfig as kritzel_control_text_config, KritzelControls as kritzel_controls, KritzelCursorTrail as kritzel_cursor_trail, KritzelDropdown as kritzel_dropdown, KritzelEditor as kritzel_editor, KritzelEngine as kritzel_engine, KritzelFont as kritzel_font, KritzelFontFamily as kritzel_font_family, KritzelFontSize as kritzel_font_size, KritzelIcon as kritzel_icon, KritzelMenu as kritzel_menu, KritzelMenuItem as kritzel_menu_item, KritzelPortal as kritzel_portal, KritzelSplitButton as kritzel_split_button, KritzelStrokeSize as kritzel_stroke_size, KritzelTooltip as kritzel_tooltip, KritzelUtilityPanel as kritzel_utility_panel, KritzelWorkspaceManager as kritzel_workspace_manager };
3389
+ //# sourceMappingURL=kritzel-color.kritzel-color-palette.kritzel-context-menu.kritzel-control-brush-config.kritzel-control-text-config.kritzel-controls.kritzel-cursor-trail.kritzel-dropdown.kritzel-editor.kritzel-engine.kritzel-font.kritzel-font-family.kritzel-font-size.kritzel-icon.kritzel-menu.kritzel-menu-item.kritzel-portal.kritzel-split-button.kritzel-stroke-size.kritzel-tooltip.kritzel-utility-panel.kritzel-workspace-manager.entry.js.map