@kritzel/engine 0.4.31

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 (373) hide show
  1. package/LICENSE.md +50 -0
  2. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  3. package/dist/cjs/engine.constants-CakmdKMW.js +28206 -0
  4. package/dist/cjs/index-BbbWU2aN.js +1742 -0
  5. package/dist/cjs/index.cjs.js +4232 -0
  6. package/dist/cjs/kritzel-awareness-cursors_5.cjs.entry.js +28004 -0
  7. package/dist/cjs/loader.cjs.js +13 -0
  8. package/dist/cjs/stencil.cjs.js +25 -0
  9. package/dist/collection/classes/core/core.class.js +1389 -0
  10. package/dist/collection/classes/core/reviver.class.js +124 -0
  11. package/dist/collection/classes/core/store.class.js +337 -0
  12. package/dist/collection/classes/core/viewport.class.js +794 -0
  13. package/dist/collection/classes/core/workspace.class.js +112 -0
  14. package/dist/collection/classes/handlers/base.handler.js +20 -0
  15. package/dist/collection/classes/handlers/context-menu.handler.js +170 -0
  16. package/dist/collection/classes/handlers/hover.handler.js +35 -0
  17. package/dist/collection/classes/handlers/key.handler.js +162 -0
  18. package/dist/collection/classes/handlers/line-handle.handler.js +475 -0
  19. package/dist/collection/classes/handlers/move.handler.js +295 -0
  20. package/dist/collection/classes/handlers/resize.handler.js +327 -0
  21. package/dist/collection/classes/handlers/rotation.handler.js +174 -0
  22. package/dist/collection/classes/handlers/selection.handler.js +526 -0
  23. package/dist/collection/classes/managers/anchor.manager.js +1476 -0
  24. package/dist/collection/classes/managers/browser-permission.manager.js +64 -0
  25. package/dist/collection/classes/managers/clipboard.manager.js +346 -0
  26. package/dist/collection/classes/managers/clipboard.types.js +1 -0
  27. package/dist/collection/classes/managers/cursor.manager.js +139 -0
  28. package/dist/collection/classes/managers/license.manager.js +341 -0
  29. package/dist/collection/classes/managers/localization.manager.js +227 -0
  30. package/dist/collection/classes/managers/theme.manager.js +206 -0
  31. package/dist/collection/classes/objects/base-object.class.js +462 -0
  32. package/dist/collection/classes/objects/dynamic-object.class.js +437 -0
  33. package/dist/collection/classes/objects/group.class.js +590 -0
  34. package/dist/collection/classes/objects/image.class.js +500 -0
  35. package/dist/collection/classes/objects/line.class.js +789 -0
  36. package/dist/collection/classes/objects/path.class.js +578 -0
  37. package/dist/collection/classes/objects/selection-box.class.js +32 -0
  38. package/dist/collection/classes/objects/selection-group.class.js +752 -0
  39. package/dist/collection/classes/objects/shape.class.js +628 -0
  40. package/dist/collection/classes/objects/text.class.js +461 -0
  41. package/dist/collection/classes/providers/assets/asset-resolver.class.js +536 -0
  42. package/dist/collection/classes/providers/assets/http-asset-provider.class.js +111 -0
  43. package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +241 -0
  44. package/dist/collection/classes/providers/assets/presigned-asset-provider.class.js +86 -0
  45. package/dist/collection/classes/providers/paste-intent/event-paste-intent.provider.js +48 -0
  46. package/dist/collection/classes/providers/paste-intent/ios-paste-intent.provider.js +16 -0
  47. package/dist/collection/classes/providers/paste-intent/navigator-paste-intent.provider.js +86 -0
  48. package/dist/collection/classes/providers/sync/broadcast-sync-provider.class.js +100 -0
  49. package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +333 -0
  50. package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +69 -0
  51. package/dist/collection/classes/providers/sync/indexeddb-sync-provider.class.js +39 -0
  52. package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +110 -0
  53. package/dist/collection/classes/registries/dynamic-object-renderer.registry.js +52 -0
  54. package/dist/collection/classes/registries/font-registry.class.js +161 -0
  55. package/dist/collection/classes/registries/icon-registry.class.js +118 -0
  56. package/dist/collection/classes/registries/paste-intent-provider.registry.js +26 -0
  57. package/dist/collection/classes/registries/tool.registry.js +69 -0
  58. package/dist/collection/classes/structures/app-state-map.structure.js +461 -0
  59. package/dist/collection/classes/structures/object-map.structure.js +1103 -0
  60. package/dist/collection/classes/structures/quadtree.structure.js +251 -0
  61. package/dist/collection/classes/tools/base-tool.class.js +88 -0
  62. package/dist/collection/classes/tools/brush-tool.class.js +236 -0
  63. package/dist/collection/classes/tools/eraser-tool.class.js +133 -0
  64. package/dist/collection/classes/tools/image-tool.class.js +152 -0
  65. package/dist/collection/classes/tools/line-tool.class.js +249 -0
  66. package/dist/collection/classes/tools/selection-tool.class.js +611 -0
  67. package/dist/collection/classes/tools/shape-tool.class.js +251 -0
  68. package/dist/collection/classes/tools/text-tool.class.js +179 -0
  69. package/dist/collection/collection-manifest.json +17 -0
  70. package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.css +115 -0
  71. package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.js +380 -0
  72. package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.css +10 -0
  73. package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.js +153 -0
  74. package/dist/collection/components/kritzel-engine/kritzel-engine.css +81 -0
  75. package/dist/collection/components/kritzel-engine/kritzel-engine.js +6345 -0
  76. package/dist/collection/components/kritzel-icon/kritzel-icon.css +18 -0
  77. package/dist/collection/components/kritzel-icon/kritzel-icon.js +93 -0
  78. package/dist/collection/components/kritzel-watermark/kritzel-watermark.css +29 -0
  79. package/dist/collection/components/kritzel-watermark/kritzel-watermark.js +83 -0
  80. package/dist/collection/configs/default-asset-storage.config.js +9 -0
  81. package/dist/collection/configs/default-brush-tool.config.js +9 -0
  82. package/dist/collection/configs/default-engine-config.js +73 -0
  83. package/dist/collection/configs/default-line-tool.config.js +12 -0
  84. package/dist/collection/configs/default-shape-tool.config.js +15 -0
  85. package/dist/collection/configs/default-sync.config.js +6 -0
  86. package/dist/collection/configs/default-text-tool.config.js +12 -0
  87. package/dist/collection/constants/color-palette.constants.js +40 -0
  88. package/dist/collection/constants/core.constants.js +1 -0
  89. package/dist/collection/constants/engine.constants.js +4 -0
  90. package/dist/collection/constants/license.constants.js +25 -0
  91. package/dist/collection/constants/schema.constants.js +4 -0
  92. package/dist/collection/constants/storage.constants.js +1 -0
  93. package/dist/collection/constants/stroke-size.constants.js +2 -0
  94. package/dist/collection/constants/text-tool-fonts.constants.js +18 -0
  95. package/dist/collection/constants/version.js +6 -0
  96. package/dist/collection/enums/alignment.enum.js +9 -0
  97. package/dist/collection/enums/event-button.enum.js +6 -0
  98. package/dist/collection/enums/handle-type.enum.js +7 -0
  99. package/dist/collection/enums/shape-type.enum.js +6 -0
  100. package/dist/collection/events/active-workspace-change.event.js +1 -0
  101. package/dist/collection/events/editor-is-ready.event.js +1 -0
  102. package/dist/collection/events/login.event.js +1 -0
  103. package/dist/collection/helpers/alignment.helper.js +73 -0
  104. package/dist/collection/helpers/class.helper.js +5 -0
  105. package/dist/collection/helpers/color.helper.js +106 -0
  106. package/dist/collection/helpers/cursor.helper.js +57 -0
  107. package/dist/collection/helpers/devices.helper.js +28 -0
  108. package/dist/collection/helpers/event.helper.js +58 -0
  109. package/dist/collection/helpers/geometry.helper.js +149 -0
  110. package/dist/collection/helpers/html.helper.js +116 -0
  111. package/dist/collection/helpers/image-file.helper.js +6 -0
  112. package/dist/collection/helpers/keyboard.helper.js +55 -0
  113. package/dist/collection/helpers/localization.helper.js +25 -0
  114. package/dist/collection/helpers/math.helper.js +8 -0
  115. package/dist/collection/helpers/migration.helper.js +45 -0
  116. package/dist/collection/helpers/object.helper.js +29 -0
  117. package/dist/collection/helpers/svg-export.helper.js +655 -0
  118. package/dist/collection/helpers/theme.helper.js +77 -0
  119. package/dist/collection/helpers/tool-config.helper.js +63 -0
  120. package/dist/collection/helpers/wheel.helper.js +113 -0
  121. package/dist/collection/index.js +107 -0
  122. package/dist/collection/interfaces/anchor.interface.js +1 -0
  123. package/dist/collection/interfaces/arrow-head.interface.js +1 -0
  124. package/dist/collection/interfaces/asset-provider.interface.js +1 -0
  125. package/dist/collection/interfaces/asset-storage-config.interface.js +1 -0
  126. package/dist/collection/interfaces/asset.interface.js +1 -0
  127. package/dist/collection/interfaces/bounding-box.interface.js +1 -0
  128. package/dist/collection/interfaces/clonable.interface.js +1 -0
  129. package/dist/collection/interfaces/context-menu-item.interface.js +1 -0
  130. package/dist/collection/interfaces/context-menu-state.interface.js +1 -0
  131. package/dist/collection/interfaces/debug-info.interface.js +1 -0
  132. package/dist/collection/interfaces/dialog.interface.js +1 -0
  133. package/dist/collection/interfaces/document-metadata.interface.js +1 -0
  134. package/dist/collection/interfaces/dynamic-object-renderer.interface.js +1 -0
  135. package/dist/collection/interfaces/engine-state.interface.js +1 -0
  136. package/dist/collection/interfaces/font.interface.js +1 -0
  137. package/dist/collection/interfaces/localization.interface.js +1 -0
  138. package/dist/collection/interfaces/login-config.interface.js +1 -0
  139. package/dist/collection/interfaces/master-detail.interface.js +1 -0
  140. package/dist/collection/interfaces/menu-item.interface.js +1 -0
  141. package/dist/collection/interfaces/migration.interface.js +1 -0
  142. package/dist/collection/interfaces/notification.interface.js +1 -0
  143. package/dist/collection/interfaces/object-change-event.interface.js +1 -0
  144. package/dist/collection/interfaces/object-export.interface.js +1 -0
  145. package/dist/collection/interfaces/object.interface.js +1 -0
  146. package/dist/collection/interfaces/paste-intent-provider.interface.js +1 -0
  147. package/dist/collection/interfaces/point.interface.js +1 -0
  148. package/dist/collection/interfaces/polygon.interface.js +1 -0
  149. package/dist/collection/interfaces/remote-cursor.interface.js +1 -0
  150. package/dist/collection/interfaces/selection-state.interface.js +1 -0
  151. package/dist/collection/interfaces/serializable.interface.js +1 -0
  152. package/dist/collection/interfaces/settings.interface.js +1 -0
  153. package/dist/collection/interfaces/share.interface.js +1 -0
  154. package/dist/collection/interfaces/shortcut.interface.js +1 -0
  155. package/dist/collection/interfaces/sync-config.interface.js +21 -0
  156. package/dist/collection/interfaces/sync-provider.interface.js +1 -0
  157. package/dist/collection/interfaces/theme.interface.js +1 -0
  158. package/dist/collection/interfaces/tool-config.interface.js +1 -0
  159. package/dist/collection/interfaces/tool-type.interface.js +1 -0
  160. package/dist/collection/interfaces/tool.interface.js +1 -0
  161. package/dist/collection/interfaces/toolbar-item.interface.js +1 -0
  162. package/dist/collection/interfaces/undo-state.interface.js +1 -0
  163. package/dist/collection/interfaces/user.interface.js +1 -0
  164. package/dist/collection/interfaces/viewport-state.interface.js +1 -0
  165. package/dist/collection/locales/de-locale.js +119 -0
  166. package/dist/collection/locales/en-locale.js +120 -0
  167. package/dist/collection/locales/fr-locale.js +119 -0
  168. package/dist/collection/migrations/app-state.migrations.js +47 -0
  169. package/dist/collection/migrations/workspace.migrations.js +67 -0
  170. package/dist/collection/themes/dark-theme.js +340 -0
  171. package/dist/collection/themes/light-theme.js +346 -0
  172. package/dist/collection/types/deep-readonly.type.js +1 -0
  173. package/dist/collection/types/state.types.js +1 -0
  174. package/dist/components/index.d.ts +47 -0
  175. package/dist/components/index.js +4143 -0
  176. package/dist/components/kritzel-awareness-cursors.d.ts +11 -0
  177. package/dist/components/kritzel-awareness-cursors.js +6 -0
  178. package/dist/components/kritzel-cursor-trail.d.ts +11 -0
  179. package/dist/components/kritzel-cursor-trail.js +6 -0
  180. package/dist/components/kritzel-engine.d.ts +11 -0
  181. package/dist/components/kritzel-engine.js +52641 -0
  182. package/dist/components/kritzel-icon.d.ts +11 -0
  183. package/dist/components/kritzel-icon.js +6 -0
  184. package/dist/components/kritzel-watermark.d.ts +11 -0
  185. package/dist/components/kritzel-watermark.js +6 -0
  186. package/dist/components/p-B2Htv9ou.js +49 -0
  187. package/dist/components/p-BvRGQvVI.js +3456 -0
  188. package/dist/components/p-CfSx6HU_.js +1469 -0
  189. package/dist/components/p-YP8wAcF4.js +122 -0
  190. package/dist/components/p-fx6msYHJ.js +167 -0
  191. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  192. package/dist/esm/engine.constants-Bl5-pbq-.js +28143 -0
  193. package/dist/esm/index-BU9Mv7y0.js +1715 -0
  194. package/dist/esm/index.js +4134 -0
  195. package/dist/esm/kritzel-awareness-cursors_5.entry.js +27978 -0
  196. package/dist/esm/loader.js +11 -0
  197. package/dist/esm/stencil.js +21 -0
  198. package/dist/index.cjs.js +1 -0
  199. package/dist/index.js +1 -0
  200. package/dist/stencil/index.esm.js +4134 -0
  201. package/dist/stencil/p-BU9Mv7y0.js +1702 -0
  202. package/dist/stencil/p-Bl5-pbq-.js +28143 -0
  203. package/dist/stencil/p-DQuL1Twl.js +3 -0
  204. package/dist/stencil/p-f0a8b7af.entry.js +27978 -0
  205. package/dist/stencil/stencil.esm.js +21 -0
  206. package/dist/types/classes/core/core.class.d.ts +532 -0
  207. package/dist/types/classes/core/reviver.class.d.ts +32 -0
  208. package/dist/types/classes/core/store.class.d.ts +198 -0
  209. package/dist/types/classes/core/viewport.class.d.ts +256 -0
  210. package/dist/types/classes/core/workspace.class.d.ts +95 -0
  211. package/dist/types/classes/handlers/base.handler.d.ts +18 -0
  212. package/dist/types/classes/handlers/context-menu.handler.d.ts +67 -0
  213. package/dist/types/classes/handlers/hover.handler.d.ts +23 -0
  214. package/dist/types/classes/handlers/key.handler.d.ts +44 -0
  215. package/dist/types/classes/handlers/line-handle.handler.d.ts +115 -0
  216. package/dist/types/classes/handlers/move.handler.d.ts +94 -0
  217. package/dist/types/classes/handlers/resize.handler.d.ts +95 -0
  218. package/dist/types/classes/handlers/rotation.handler.d.ts +50 -0
  219. package/dist/types/classes/handlers/selection.handler.d.ts +153 -0
  220. package/dist/types/classes/managers/anchor.manager.d.ts +513 -0
  221. package/dist/types/classes/managers/browser-permission.manager.d.ts +41 -0
  222. package/dist/types/classes/managers/clipboard.manager.d.ts +71 -0
  223. package/dist/types/classes/managers/clipboard.types.d.ts +23 -0
  224. package/dist/types/classes/managers/cursor.manager.d.ts +66 -0
  225. package/dist/types/classes/managers/license.manager.d.ts +147 -0
  226. package/dist/types/classes/managers/localization.manager.d.ts +145 -0
  227. package/dist/types/classes/managers/theme.manager.d.ts +112 -0
  228. package/dist/types/classes/objects/base-object.class.d.ts +266 -0
  229. package/dist/types/classes/objects/dynamic-object.class.d.ts +148 -0
  230. package/dist/types/classes/objects/group.class.d.ts +231 -0
  231. package/dist/types/classes/objects/image.class.d.ts +246 -0
  232. package/dist/types/classes/objects/line.class.d.ts +285 -0
  233. package/dist/types/classes/objects/path.class.d.ts +220 -0
  234. package/dist/types/classes/objects/selection-box.class.d.ts +19 -0
  235. package/dist/types/classes/objects/selection-group.class.d.ts +267 -0
  236. package/dist/types/classes/objects/shape.class.d.ts +322 -0
  237. package/dist/types/classes/objects/text.class.d.ts +197 -0
  238. package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +141 -0
  239. package/dist/types/classes/providers/assets/http-asset-provider.class.d.ts +79 -0
  240. package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +69 -0
  241. package/dist/types/classes/providers/assets/presigned-asset-provider.class.d.ts +69 -0
  242. package/dist/types/classes/providers/paste-intent/event-paste-intent.provider.d.ts +8 -0
  243. package/dist/types/classes/providers/paste-intent/ios-paste-intent.provider.d.ts +6 -0
  244. package/dist/types/classes/providers/paste-intent/navigator-paste-intent.provider.d.ts +9 -0
  245. package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +23 -0
  246. package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +163 -0
  247. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +39 -0
  248. package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +25 -0
  249. package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +63 -0
  250. package/dist/types/classes/registries/dynamic-object-renderer.registry.d.ts +32 -0
  251. package/dist/types/classes/registries/font-registry.class.d.ts +19 -0
  252. package/dist/types/classes/registries/icon-registry.class.d.ts +39 -0
  253. package/dist/types/classes/registries/paste-intent-provider.registry.d.ts +10 -0
  254. package/dist/types/classes/registries/tool.registry.d.ts +53 -0
  255. package/dist/types/classes/structures/app-state-map.structure.d.ts +171 -0
  256. package/dist/types/classes/structures/object-map.structure.d.ts +403 -0
  257. package/dist/types/classes/structures/quadtree.structure.d.ts +128 -0
  258. package/dist/types/classes/tools/base-tool.class.d.ts +72 -0
  259. package/dist/types/classes/tools/brush-tool.class.d.ts +68 -0
  260. package/dist/types/classes/tools/eraser-tool.class.d.ts +38 -0
  261. package/dist/types/classes/tools/image-tool.class.d.ts +74 -0
  262. package/dist/types/classes/tools/line-tool.class.d.ts +63 -0
  263. package/dist/types/classes/tools/selection-tool.class.d.ts +188 -0
  264. package/dist/types/classes/tools/shape-tool.class.d.ts +90 -0
  265. package/dist/types/classes/tools/text-tool.class.d.ts +66 -0
  266. package/dist/types/components/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +29 -0
  267. package/dist/types/components/kritzel-cursor-trail/kritzel-cursor-trail.d.ts +19 -0
  268. package/dist/types/components/kritzel-engine/kritzel-engine.d.ts +695 -0
  269. package/dist/types/components/kritzel-icon/kritzel-icon.d.ts +6 -0
  270. package/dist/types/components/kritzel-watermark/kritzel-watermark.d.ts +20 -0
  271. package/dist/types/components.d.ts +981 -0
  272. package/dist/types/configs/default-asset-storage.config.d.ts +8 -0
  273. package/dist/types/configs/default-brush-tool.config.d.ts +2 -0
  274. package/dist/types/configs/default-engine-config.d.ts +2 -0
  275. package/dist/types/configs/default-line-tool.config.d.ts +2 -0
  276. package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
  277. package/dist/types/configs/default-sync.config.d.ts +5 -0
  278. package/dist/types/configs/default-text-tool.config.d.ts +2 -0
  279. package/dist/types/constants/color-palette.constants.d.ts +31 -0
  280. package/dist/types/constants/core.constants.d.ts +0 -0
  281. package/dist/types/constants/engine.constants.d.ts +4 -0
  282. package/dist/types/constants/license.constants.d.ts +25 -0
  283. package/dist/types/constants/schema.constants.d.ts +4 -0
  284. package/dist/types/constants/storage.constants.d.ts +1 -0
  285. package/dist/types/constants/stroke-size.constants.d.ts +2 -0
  286. package/dist/types/constants/text-tool-fonts.constants.d.ts +3 -0
  287. package/dist/types/constants/version.d.ts +6 -0
  288. package/dist/types/enums/alignment.enum.d.ts +8 -0
  289. package/dist/types/enums/event-button.enum.d.ts +5 -0
  290. package/dist/types/enums/handle-type.enum.d.ts +6 -0
  291. package/dist/types/enums/shape-type.enum.d.ts +5 -0
  292. package/dist/types/events/active-workspace-change.event.d.ts +7 -0
  293. package/dist/types/events/editor-is-ready.event.d.ts +18 -0
  294. package/dist/types/events/login.event.d.ts +3 -0
  295. package/dist/types/helpers/alignment.helper.d.ts +21 -0
  296. package/dist/types/helpers/class.helper.d.ts +3 -0
  297. package/dist/types/helpers/color.helper.d.ts +34 -0
  298. package/dist/types/helpers/cursor.helper.d.ts +22 -0
  299. package/dist/types/helpers/devices.helper.d.ts +8 -0
  300. package/dist/types/helpers/event.helper.d.ts +6 -0
  301. package/dist/types/helpers/geometry.helper.d.ts +38 -0
  302. package/dist/types/helpers/html.helper.d.ts +8 -0
  303. package/dist/types/helpers/image-file.helper.d.ts +3 -0
  304. package/dist/types/helpers/keyboard.helper.d.ts +6 -0
  305. package/dist/types/helpers/localization.helper.d.ts +18 -0
  306. package/dist/types/helpers/math.helper.d.ts +4 -0
  307. package/dist/types/helpers/migration.helper.d.ts +30 -0
  308. package/dist/types/helpers/object.helper.d.ts +9 -0
  309. package/dist/types/helpers/svg-export.helper.d.ts +231 -0
  310. package/dist/types/helpers/theme.helper.d.ts +42 -0
  311. package/dist/types/helpers/tool-config.helper.d.ts +4 -0
  312. package/dist/types/helpers/wheel.helper.d.ts +9 -0
  313. package/dist/types/index.d.ts +109 -0
  314. package/dist/types/interfaces/anchor.interface.d.ts +147 -0
  315. package/dist/types/interfaces/arrow-head.interface.d.ts +27 -0
  316. package/dist/types/interfaces/asset-provider.interface.d.ts +88 -0
  317. package/dist/types/interfaces/asset-storage-config.interface.d.ts +40 -0
  318. package/dist/types/interfaces/asset.interface.d.ts +43 -0
  319. package/dist/types/interfaces/bounding-box.interface.d.ts +8 -0
  320. package/dist/types/interfaces/clonable.interface.d.ts +3 -0
  321. package/dist/types/interfaces/context-menu-item.interface.d.ts +25 -0
  322. package/dist/types/interfaces/context-menu-state.interface.d.ts +16 -0
  323. package/dist/types/interfaces/debug-info.interface.d.ts +7 -0
  324. package/dist/types/interfaces/dialog.interface.d.ts +4 -0
  325. package/dist/types/interfaces/document-metadata.interface.d.ts +6 -0
  326. package/dist/types/interfaces/dynamic-object-renderer.interface.d.ts +40 -0
  327. package/dist/types/interfaces/engine-state.interface.d.ts +82 -0
  328. package/dist/types/interfaces/font.interface.d.ts +15 -0
  329. package/dist/types/interfaces/localization.interface.d.ts +143 -0
  330. package/dist/types/interfaces/login-config.interface.d.ts +24 -0
  331. package/dist/types/interfaces/master-detail.interface.d.ts +14 -0
  332. package/dist/types/interfaces/menu-item.interface.d.ts +27 -0
  333. package/dist/types/interfaces/migration.interface.d.ts +16 -0
  334. package/dist/types/interfaces/notification.interface.d.ts +10 -0
  335. package/dist/types/interfaces/object-change-event.interface.d.ts +31 -0
  336. package/dist/types/interfaces/object-export.interface.d.ts +20 -0
  337. package/dist/types/interfaces/object.interface.d.ts +53 -0
  338. package/dist/types/interfaces/paste-intent-provider.interface.d.ts +10 -0
  339. package/dist/types/interfaces/point.interface.d.ts +4 -0
  340. package/dist/types/interfaces/polygon.interface.d.ts +7 -0
  341. package/dist/types/interfaces/remote-cursor.interface.d.ts +18 -0
  342. package/dist/types/interfaces/selection-state.interface.d.ts +7 -0
  343. package/dist/types/interfaces/serializable.interface.d.ts +5 -0
  344. package/dist/types/interfaces/settings.interface.d.ts +25 -0
  345. package/dist/types/interfaces/share.interface.d.ts +9 -0
  346. package/dist/types/interfaces/shortcut.interface.d.ts +10 -0
  347. package/dist/types/interfaces/sync-config.interface.d.ts +41 -0
  348. package/dist/types/interfaces/sync-provider.interface.d.ts +66 -0
  349. package/dist/types/interfaces/theme.interface.d.ts +553 -0
  350. package/dist/types/interfaces/tool-config.interface.d.ts +24 -0
  351. package/dist/types/interfaces/tool-type.interface.d.ts +1 -0
  352. package/dist/types/interfaces/tool.interface.d.ts +8 -0
  353. package/dist/types/interfaces/toolbar-item.interface.d.ts +66 -0
  354. package/dist/types/interfaces/undo-state.interface.d.ts +6 -0
  355. package/dist/types/interfaces/user.interface.d.ts +22 -0
  356. package/dist/types/interfaces/viewport-state.interface.d.ts +7 -0
  357. package/dist/types/locales/de-locale.d.ts +5 -0
  358. package/dist/types/locales/en-locale.d.ts +6 -0
  359. package/dist/types/locales/fr-locale.d.ts +5 -0
  360. package/dist/types/migrations/app-state.migrations.d.ts +11 -0
  361. package/dist/types/migrations/workspace.migrations.d.ts +11 -0
  362. package/dist/types/stencil-public-runtime.d.ts +1873 -0
  363. package/dist/types/themes/dark-theme.d.ts +5 -0
  364. package/dist/types/themes/light-theme.d.ts +5 -0
  365. package/dist/types/types/deep-readonly.type.d.ts +7 -0
  366. package/dist/types/types/state.types.d.ts +3 -0
  367. package/loader/cdn.js +1 -0
  368. package/loader/index.cjs.js +1 -0
  369. package/loader/index.d.ts +24 -0
  370. package/loader/index.es2017.js +1 -0
  371. package/loader/index.js +2 -0
  372. package/package.json +101 -0
  373. package/readme.md +11 -0
@@ -0,0 +1,590 @@
1
+ import { KritzelBaseObject } from "./base-object.class";
2
+ import { KritzelClassHelper } from "../../helpers/class.helper";
3
+ import { KritzelMathHelper } from "../../helpers/math.helper";
4
+ /**
5
+ * KritzelGroup represents a permanent grouping of objects that act as a single unit.
6
+ *
7
+ * Unlike KritzelSelectionGroup (which is ephemeral and used for temporary multi-selection),
8
+ * KritzelGroup is persisted and saved with the workspace. Grouped objects move, resize,
9
+ * rotate, copy, and delete together as one unit.
10
+ *
11
+ * Key features:
12
+ * - Supports nested groups (groups can contain other groups)
13
+ * - Clicking any child selects the entire group
14
+ * - Can be ungrouped to restore children to top-level objects
15
+ */
16
+ export class KritzelGroup extends KritzelBaseObject {
17
+ __class__ = 'KritzelGroup';
18
+ constructor(config) {
19
+ super();
20
+ this.rotation = KritzelMathHelper.degreesToRadians(config?.rotation ?? 0);
21
+ }
22
+ /**
23
+ * IDs of child objects within this group.
24
+ * Children can be any KritzelBaseObject, including other KritzelGroups for nesting.
25
+ */
26
+ childIds = [];
27
+ /**
28
+ * Holds child objects that have been added via addChild() before the group
29
+ * is added to the engine. Once the group is added (and _core is set),
30
+ * these are flushed into the store and this array is cleared.
31
+ */
32
+ _pendingChildren = [];
33
+ /**
34
+ * Snapshots of child states for transformation operations (resize, rotate).
35
+ * Similar pattern to KritzelSelectionGroup.
36
+ */
37
+ unchangedChildSnapshots = new Map();
38
+ snapshotRotation = 0;
39
+ snapshotTranslateX = 0;
40
+ snapshotTranslateY = 0;
41
+ snapshotTotalWidth = 0;
42
+ snapshotTotalHeight = 0;
43
+ snapshotScale = 1;
44
+ /**
45
+ * Retrieves the actual child objects from the store by their IDs.
46
+ * Filters out any IDs that no longer exist in the store.
47
+ * @returns An array of KritzelBaseObject instances representing the group's children.
48
+ */
49
+ get children() {
50
+ if (!this._core) {
51
+ return this._pendingChildren;
52
+ }
53
+ return this.childIds
54
+ .map(id => {
55
+ const found = this._core.store.objects.filter(obj => obj.id === id);
56
+ return found.length > 0 ? found[0] : null;
57
+ })
58
+ .filter((obj) => obj !== null);
59
+ }
60
+ /**
61
+ * Returns the number of children in this group.
62
+ * @returns The count of child IDs stored in this group.
63
+ */
64
+ get length() {
65
+ return this.childIds.length;
66
+ }
67
+ /**
68
+ * Factory method to create a new empty KritzelGroup with core integration.
69
+ * Initializes the group with default values and links it to the core store.
70
+ * @param core - The KritzelCore instance providing access to store and state management.
71
+ * @returns A new KritzelGroup instance configured with the core context.
72
+ */
73
+ static create(core, config) {
74
+ const group = new KritzelGroup(config);
75
+ group._core = core;
76
+ group.id = group.generateId();
77
+ group.workspaceId = core.store.state.activeWorkspace.id;
78
+ group.userId = core.user?.id;
79
+ group.scale = core.store.state.scale;
80
+ group.zIndex = core.store.currentZIndex;
81
+ return group;
82
+ }
83
+ /**
84
+ * Creates a KritzelGroup from an array of existing objects.
85
+ * The objects are added as children and the group's bounding box is calculated
86
+ * to encompass all children. Child snapshots are captured for transformation operations.
87
+ * @param core - The KritzelCore instance providing access to store and state management.
88
+ * @param objects - An array of KritzelBaseObject instances to group together.
89
+ * @returns A new KritzelGroup containing the specified objects as children.
90
+ */
91
+ static createFromObjects(core, objects) {
92
+ const group = KritzelGroup.create(core);
93
+ // Add all objects as children
94
+ objects.forEach(obj => {
95
+ group.childIds.push(obj.id);
96
+ });
97
+ // Calculate bounding box from children
98
+ group.refreshBoundingBox();
99
+ group.captureChildSnapshots();
100
+ return group;
101
+ }
102
+ /**
103
+ * Finds the parent KritzelGroup that contains the given object as a direct child.
104
+ * Searches through all groups in the store to find one containing the specified object ID.
105
+ * @param core - The KritzelCore instance providing access to the object store.
106
+ * @param objectId - The unique identifier of the object to find the parent group for.
107
+ * @returns The parent KritzelGroup if found, or null if the object is not a child of any group.
108
+ */
109
+ static findParentGroup(core, objectId) {
110
+ const allGroups = core.store.objects
111
+ .filter(obj => obj.__class__ === 'KritzelGroup');
112
+ for (const group of allGroups) {
113
+ if (group.childIds.includes(objectId)) {
114
+ return group;
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Recursively collects the IDs of all descendants of the given group (children,
121
+ * grandchildren, etc.). Useful for detecting when a selection contains both an
122
+ * ancestor group and one of its descendants — a configuration that would otherwise
123
+ * cause the descendant to be transformed twice (once via the ancestor, once directly).
124
+ * @param group - The group whose descendants should be collected.
125
+ * @param out - A set that will be populated with all descendant object IDs.
126
+ */
127
+ static collectDescendantIds(group, out = new Set()) {
128
+ for (const child of group.children) {
129
+ out.add(child.id);
130
+ if (child instanceof KritzelGroup) {
131
+ KritzelGroup.collectDescendantIds(child, out);
132
+ }
133
+ }
134
+ return out;
135
+ }
136
+ /**
137
+ * Adds a child object to this group.
138
+ * If the object is already a child, no action is taken.
139
+ * Automatically refreshes the bounding box and captures child snapshots.
140
+ * @param object - The KritzelBaseObject instance to add as a child.
141
+ */
142
+ addChild(object) {
143
+ if (!this.childIds.includes(object.id)) {
144
+ this.childIds.push(object.id);
145
+ if (!this._core) {
146
+ this._pendingChildren.push(object);
147
+ return;
148
+ }
149
+ this.refreshBoundingBox();
150
+ this.captureChildSnapshots();
151
+ }
152
+ }
153
+ /**
154
+ * Removes a child object from this group by its ID.
155
+ * If the object is not a child, no action is taken.
156
+ * Automatically refreshes the bounding box and captures child snapshots.
157
+ * @param objectId - The unique identifier of the child object to remove.
158
+ */
159
+ removeChild(objectId) {
160
+ const index = this.childIds.indexOf(objectId);
161
+ if (index !== -1) {
162
+ this.childIds.splice(index, 1);
163
+ this.refreshBoundingBox();
164
+ this.captureChildSnapshots();
165
+ }
166
+ }
167
+ /**
168
+ * Ungroups this group, returning all children to top-level objects.
169
+ * The group itself should be removed from the store after calling this method.
170
+ * @returns An array of all child objects that were part of this group.
171
+ */
172
+ ungroup() {
173
+ return this.children;
174
+ }
175
+ /**
176
+ * Finalizes the group after children have been positioned (e.g., after paste).
177
+ * Refreshes the bounding box to encompass all children and captures
178
+ * child snapshots for subsequent transformation operations.
179
+ *
180
+ * Recursively finalizes nested child groups first, so that when a transform
181
+ * (rotate/resize) cascades through nested groups, every group's snapshots are
182
+ * aligned with the current visual state. Without this, a nested group's
183
+ * `snapshotRotation` could be stale, causing the inner group to be offset
184
+ * relative to its parent during rotation.
185
+ */
186
+ finalize() {
187
+ for (const child of this.children) {
188
+ if (child instanceof KritzelGroup) {
189
+ child.finalize();
190
+ }
191
+ }
192
+ this.refreshBoundingBox();
193
+ this.captureChildSnapshots();
194
+ }
195
+ /**
196
+ * Moves the group and all its children to the center of the viewport.
197
+ * Overrides the base implementation to ensure children move with the group.
198
+ */
199
+ centerInViewport() {
200
+ const { viewportWidth, viewportHeight, translateX: viewportTranslateX, translateY: viewportTranslateY, scale: viewportScale } = this._core.store.state;
201
+ const { x, y, width, height } = this.rotatedBoundingBox;
202
+ const objectCenterX = x + width / 2;
203
+ const objectCenterY = y + height / 2;
204
+ const targetCenterX = (viewportWidth / 2 - viewportTranslateX) / viewportScale;
205
+ const targetCenterY = (viewportHeight / 2 - viewportTranslateY) / viewportScale;
206
+ const deltaX = targetCenterX - objectCenterX;
207
+ const deltaY = targetCenterY - objectCenterY;
208
+ this.translateX += deltaX;
209
+ this.translateY += deltaY;
210
+ this.children.forEach(child => {
211
+ child.translateX += deltaX;
212
+ child.translateY += deltaY;
213
+ });
214
+ this.captureChildSnapshots();
215
+ }
216
+ /**
217
+ * Recalculates the group's bounding box based on its children.
218
+ * Handles three cases: empty group (zero dimensions), single child (inherit its bounds),
219
+ * and multiple children (calculate encompassing bounds with rotation support).
220
+ * Updates translateX, translateY, width, and height properties.
221
+ */
222
+ refreshBoundingBox() {
223
+ if (this.children.length === 0) {
224
+ this.width = 0;
225
+ this.height = 0;
226
+ this.translateX = 0;
227
+ this.translateY = 0;
228
+ return;
229
+ }
230
+ if (this.children.length === 1) {
231
+ // Single child: inherit its bounding box
232
+ const child = this.children[0];
233
+ this.translateX = child.boundingBox.x;
234
+ this.translateY = child.boundingBox.y;
235
+ this.width = child.boundingBox.width * this.scale;
236
+ this.height = child.boundingBox.height * this.scale;
237
+ return;
238
+ }
239
+ // Multiple children: calculate encompassing bounding box
240
+ const rotation = this.rotation;
241
+ const cos = Math.cos(-rotation);
242
+ const sin = Math.sin(-rotation);
243
+ let minX = Infinity;
244
+ let maxX = -Infinity;
245
+ let minY = Infinity;
246
+ let maxY = -Infinity;
247
+ this.children.forEach(child => {
248
+ const polygon = child.rotatedPolygon;
249
+ const corners = [polygon.topLeft, polygon.topRight, polygon.bottomRight, polygon.bottomLeft];
250
+ corners.forEach(corner => {
251
+ // Rotate corner into local space (aligned with group rotation)
252
+ const rx = corner.x * cos - corner.y * sin;
253
+ const ry = corner.x * sin + corner.y * cos;
254
+ if (rx < minX)
255
+ minX = rx;
256
+ if (rx > maxX)
257
+ maxX = rx;
258
+ if (ry < minY)
259
+ minY = ry;
260
+ if (ry > maxY)
261
+ maxY = ry;
262
+ });
263
+ });
264
+ // Dimensions in world units (unrotated)
265
+ const worldWidth = maxX - minX;
266
+ const worldHeight = maxY - minY;
267
+ this.width = (worldWidth - this.padding) * this.scale;
268
+ this.height = (worldHeight - this.padding) * this.scale;
269
+ // Center of the box in rotated space
270
+ const cRx = (minX + maxX) / 2;
271
+ const cRy = (minY + maxY) / 2;
272
+ // Rotate center back to world space
273
+ const cosR = Math.cos(rotation);
274
+ const sinR = Math.sin(rotation);
275
+ const cx = cRx * cosR - cRy * sinR;
276
+ const cy = cRx * sinR + cRy * cosR;
277
+ this.translateX = cx - (this.width / this.scale + 2 * this.padding) / 2;
278
+ this.translateY = cy - (this.height / this.scale + 2 * this.padding) / 2;
279
+ }
280
+ /**
281
+ * Captures snapshots of all child states for transformation operations.
282
+ * Stores position, rotation, dimensions, and scale for each child.
283
+ * Also captures the group's current state for relative calculations.
284
+ */
285
+ captureChildSnapshots() {
286
+ this.unchangedChildSnapshots.clear();
287
+ this.snapshotRotation = this.rotation;
288
+ this.snapshotTranslateX = this.translateX;
289
+ this.snapshotTranslateY = this.translateY;
290
+ this.snapshotTotalWidth = this.totalWidth;
291
+ this.snapshotTotalHeight = this.totalHeight;
292
+ this.snapshotScale = this.scale || 1;
293
+ this.children.forEach(child => {
294
+ this.unchangedChildSnapshots.set(child.id, {
295
+ id: child.id,
296
+ translateX: child.translateX,
297
+ translateY: child.translateY,
298
+ rotation: child.rotation,
299
+ width: child.width,
300
+ height: child.height,
301
+ totalWidth: child.totalWidth,
302
+ totalHeight: child.totalHeight,
303
+ scale: child.scale,
304
+ });
305
+ });
306
+ }
307
+ // ─────────────────────────────────────────────────────────────────────────────
308
+ // TRANSFORMATION METHODS
309
+ // ─────────────────────────────────────────────────────────────────────────────
310
+ /**
311
+ * Moves the group and all its children by the delta between start and end positions.
312
+ * Updates are wrapped in a transaction for atomic persistence.
313
+ * Also updates any lines anchored to child objects.
314
+ * @param startX - The starting x coordinate in screen space.
315
+ * @param startY - The starting y coordinate in screen space.
316
+ * @param endX - The ending x coordinate in screen space.
317
+ * @param endY - The ending y coordinate in screen space.
318
+ */
319
+ move(startX, startY, endX, endY) {
320
+ const deltaX = (startX - endX) / this._core.store.state.scale;
321
+ const deltaY = (startY - endY) / this._core.store.state.scale;
322
+ this.translateX += deltaX;
323
+ this.translateY += deltaY;
324
+ this._core.store.objects.transaction(() => {
325
+ this._core.store.objects.update(this);
326
+ this.children.forEach(child => {
327
+ child.move(startX, startY, endX, endY);
328
+ // Update any lines anchored to this child
329
+ this._core.anchorManager.updateAnchorsForObject(child.id);
330
+ });
331
+ });
332
+ // Update snapshots
333
+ this.unchangedChildSnapshots.forEach(snapshot => {
334
+ snapshot.translateX += deltaX;
335
+ snapshot.translateY += deltaY;
336
+ });
337
+ }
338
+ /**
339
+ * Resizes the group and proportionally transforms all children.
340
+ * Children are scaled and repositioned relative to the group's center,
341
+ * accounting for rotation. Updates are wrapped in a transaction.
342
+ * @param x - The new x translation coordinate for the group.
343
+ * @param y - The new y translation coordinate for the group.
344
+ * @param width - The new width of the group's content area.
345
+ * @param height - The new height of the group's content area.
346
+ */
347
+ resize(x, y, width, height) {
348
+ // Use snapshot dimensions (stable across the gesture) instead of `this.*`,
349
+ // which mutates each frame and gets distorted by descendants like KritzelText
350
+ // that clamp to a uniform scale, causing the cascade factor to drift.
351
+ const baseWidth = this.snapshotTotalWidth > 0
352
+ ? this.snapshotTotalWidth - this.padding * 2
353
+ : this.width;
354
+ const baseHeight = this.snapshotTotalHeight > 0
355
+ ? this.snapshotTotalHeight - this.padding * 2
356
+ : this.height;
357
+ const baseScale = this.snapshotScale || this.scale || 1;
358
+ const widthScaleFactor = baseWidth !== 0 ? width / baseWidth : 1;
359
+ const heightScaleFactor = baseHeight !== 0 ? height / baseHeight : 1;
360
+ // Calculate old center from snapshot (stable across the gesture)
361
+ const snapshotTotalWidth = this.snapshotTotalWidth || (this.width + this.padding * 2);
362
+ const snapshotTotalHeight = this.snapshotTotalHeight || (this.height + this.padding * 2);
363
+ const oldCenterX = this.snapshotTranslateX + snapshotTotalWidth / 2 / baseScale;
364
+ const oldCenterY = this.snapshotTranslateY + snapshotTotalHeight / 2 / baseScale;
365
+ // Calculate new center
366
+ const newTotalWidth = width + this.padding * 2;
367
+ const newTotalHeight = height + this.padding * 2;
368
+ const newCenterX = x + newTotalWidth / 2 / this.scale;
369
+ const newCenterY = y + newTotalHeight / 2 / this.scale;
370
+ const rotation = this.rotation;
371
+ const cos = Math.cos(-rotation);
372
+ const sin = Math.sin(-rotation);
373
+ const cosR = Math.cos(rotation);
374
+ const sinR = Math.sin(rotation);
375
+ this._core.store.objects.transaction(() => {
376
+ this.children.forEach(child => {
377
+ // Use snapshot values for the child to avoid compounding distortions caused
378
+ // by descendants like text that cannot honour requested aspect ratios.
379
+ const snapshot = this.unchangedChildSnapshots.get(child.id);
380
+ const childTranslateX = snapshot ? snapshot.translateX : child.translateX;
381
+ const childTranslateY = snapshot ? snapshot.translateY : child.translateY;
382
+ const childTotalWidth = snapshot ? snapshot.totalWidth : child.totalWidth;
383
+ const childTotalHeight = snapshot ? snapshot.totalHeight : child.totalHeight;
384
+ const childWidth = snapshot ? snapshot.width : child.width;
385
+ const childHeight = snapshot ? snapshot.height : child.height;
386
+ const childRotation = snapshot ? snapshot.rotation : child.rotation;
387
+ const childScale = (snapshot ? snapshot.scale : child.scale) || 1;
388
+ // Calculate child center from snapshot
389
+ const childCenterX = childTranslateX + childTotalWidth / 2 / childScale;
390
+ const childCenterY = childTranslateY + childTotalHeight / 2 / childScale;
391
+ // Vector from old group center to child center
392
+ const dx = childCenterX - oldCenterX;
393
+ const dy = childCenterY - oldCenterY;
394
+ // Rotate to local space
395
+ const localX = dx * cos - dy * sin;
396
+ const localY = dx * sin + dy * cos;
397
+ // Scale in local space
398
+ const scaledLocalX = localX * widthScaleFactor;
399
+ const scaledLocalY = localY * heightScaleFactor;
400
+ // Rotate back to world space
401
+ const rotatedX = scaledLocalX * cosR - scaledLocalY * sinR;
402
+ const rotatedY = scaledLocalX * sinR + scaledLocalY * cosR;
403
+ // New child center
404
+ const newChildCenterX = newCenterX + rotatedX;
405
+ const newChildCenterY = newCenterY + rotatedY;
406
+ // Calculate relative rotation for scaling
407
+ const relativeRotation = childRotation - rotation;
408
+ const cosRel = Math.cos(relativeRotation);
409
+ const sinRel = Math.sin(relativeRotation);
410
+ const newChildWidthScale = Math.sqrt(Math.pow(widthScaleFactor * cosRel, 2) + Math.pow(heightScaleFactor * sinRel, 2));
411
+ const newChildHeightScale = Math.sqrt(Math.pow(widthScaleFactor * sinRel, 2) + Math.pow(heightScaleFactor * cosRel, 2));
412
+ const updatedWidth = childWidth * newChildWidthScale;
413
+ const updatedHeight = childHeight * newChildHeightScale;
414
+ const updatedTotalWidth = updatedWidth + child.padding * 2;
415
+ const updatedTotalHeight = updatedHeight + child.padding * 2;
416
+ const updatedX = newChildCenterX - updatedTotalWidth / 2 / child.scale;
417
+ const updatedY = newChildCenterY - updatedTotalHeight / 2 / child.scale;
418
+ child.resize(updatedX, updatedY, updatedWidth, updatedHeight);
419
+ // Update anchored lines
420
+ this._core.anchorManager.updateAnchorsForObject(child.id);
421
+ });
422
+ this.refreshBoundingBox();
423
+ // Don't recapture snapshots while an interactive resize is in progress —
424
+ // recapturing each frame would defeat the purpose of using stable snapshots
425
+ // and re-introduce the compounding distortion described above. Snapshots are
426
+ // refreshed at the start of the next gesture via beginTransform/finalize.
427
+ if (!this._core.store.state.isResizing) {
428
+ this.captureChildSnapshots();
429
+ }
430
+ this._core.store.objects.update(this);
431
+ });
432
+ }
433
+ /**
434
+ * Rotates the group and all its children around the group's center.
435
+ * Children maintain their relative positions and are individually rotated.
436
+ * Uses captured snapshots to calculate rotation deltas.
437
+ * @param value - The new absolute rotation angle in radians.
438
+ */
439
+ rotate(value) {
440
+ this.rotation = value;
441
+ const centerX = this.translateX + this.totalWidth / 2 / this.scale;
442
+ const centerY = this.translateY + this.totalHeight / 2 / this.scale;
443
+ const angle = value - this.snapshotRotation;
444
+ const cos = Math.cos(angle);
445
+ const sin = Math.sin(angle);
446
+ this._core.store.objects.transaction(() => {
447
+ this._core.store.objects.update(this);
448
+ this.children.forEach(child => {
449
+ const unchangedSnapshot = this.unchangedChildSnapshots.get(child.id);
450
+ if (!unchangedSnapshot)
451
+ return;
452
+ const offsetX = this.getOffsetXToCenterFromSnapshot(unchangedSnapshot);
453
+ const offsetY = this.getOffsetYToCenterFromSnapshot(unchangedSnapshot);
454
+ const rotatedX = cos * offsetX - sin * offsetY;
455
+ const rotatedY = sin * offsetX + cos * offsetY;
456
+ child.translateX = centerX + rotatedX - child.totalWidth / 2 / child.scale;
457
+ child.translateY = centerY + rotatedY - child.totalHeight / 2 / child.scale;
458
+ child.rotate(this.children.length === 1 ? value : unchangedSnapshot.rotation + angle);
459
+ });
460
+ });
461
+ }
462
+ /**
463
+ * Calculates the horizontal offset from the group's center to a child's center
464
+ * using the captured snapshot values.
465
+ * @param snapshot - The captured state of the child object.
466
+ * @returns The x-axis offset from the group center to the child center.
467
+ */
468
+ getOffsetXToCenterFromSnapshot(snapshot) {
469
+ const childCenterX = snapshot.translateX + snapshot.totalWidth / snapshot.scale / 2;
470
+ const groupScale = this.snapshotScale || this.scale || 1;
471
+ const groupCenterX = this.snapshotTranslateX + this.snapshotTotalWidth / groupScale / 2;
472
+ return childCenterX - groupCenterX;
473
+ }
474
+ /**
475
+ * Calculates the vertical offset from the group's center to a child's center
476
+ * using the captured snapshot values.
477
+ * @param snapshot - The captured state of the child object.
478
+ * @returns The y-axis offset from the group center to the child center.
479
+ */
480
+ getOffsetYToCenterFromSnapshot(snapshot) {
481
+ const childCenterY = snapshot.translateY + snapshot.totalHeight / snapshot.scale / 2;
482
+ const groupScale = this.snapshotScale || this.scale || 1;
483
+ const groupCenterY = this.snapshotTranslateY + this.snapshotTotalHeight / groupScale / 2;
484
+ return childCenterY - groupCenterY;
485
+ }
486
+ // ─────────────────────────────────────────────────────────────────────────────
487
+ // HIT TESTING
488
+ // ─────────────────────────────────────────────────────────────────────────────
489
+ /**
490
+ * Tests if a point lies within any of the group's children.
491
+ * The group is considered hit if any child passes the hit test.
492
+ * @param x - The x coordinate to test in world space.
493
+ * @param y - The y coordinate to test in world space.
494
+ * @returns True if the point is inside any child, false otherwise.
495
+ */
496
+ hitTest(x, y) {
497
+ // Check if point is inside any child
498
+ return this.children.some(child => child.hitTest(x, y));
499
+ }
500
+ /**
501
+ * Tests if a polygon intersects with any of the group's children.
502
+ * Used for lasso selection and area-based hit detection.
503
+ * @param polygon - The polygon to test intersection against.
504
+ * @returns True if the polygon intersects any child, false otherwise.
505
+ */
506
+ hitTestPolygon(polygon) {
507
+ // Check if polygon intersects with any child
508
+ return this.children.some(child => child.hitTestPolygon(polygon));
509
+ }
510
+ // ─────────────────────────────────────────────────────────────────────────────
511
+ // COPY & SERIALIZATION
512
+ // ─────────────────────────────────────────────────────────────────────────────
513
+ /**
514
+ * Creates a deep copy of this group and all its children.
515
+ * Children are copied but not added to the store; they are stored
516
+ * in a temporary _pendingChildren property for paste() to handle.
517
+ * @returns A new KritzelGroup with copied children and properties.
518
+ */
519
+ copy() {
520
+ const copiedGroup = KritzelGroup.create(this._core);
521
+ // Deep copy all children but DON'T add to store yet
522
+ // Store the copied children temporarily for paste() to handle
523
+ const copiedChildren = [];
524
+ this.children
525
+ .sort((a, b) => a.zIndex - b.zIndex)
526
+ .forEach(child => {
527
+ const copiedChild = child.copy();
528
+ copiedChildren.push(copiedChild);
529
+ copiedGroup.childIds.push(copiedChild.id);
530
+ });
531
+ // Store copied children on the group for paste() to handle
532
+ copiedGroup._pendingChildren = copiedChildren;
533
+ // Copy group properties
534
+ copiedGroup.rotation = this.rotation;
535
+ copiedGroup.translateX = this.translateX;
536
+ copiedGroup.translateY = this.translateY;
537
+ copiedGroup.width = this.width;
538
+ copiedGroup.height = this.height;
539
+ return copiedGroup;
540
+ }
541
+ /**
542
+ * Serializes the group to a plain object for persistence.
543
+ * Excludes runtime references (_core, _elementRef, element) and
544
+ * converts the unchangedChildSnapshots Map to a plain object.
545
+ * @returns A serializable plain object representation of this group.
546
+ */
547
+ serialize() {
548
+ const { _core, _elementRef, element, totalWidth, totalHeight, unchangedChildSnapshots, _pendingChildren, ...remainingProps } = this;
549
+ const clonedProps = structuredClone(remainingProps);
550
+ // Convert Map to plain object for serialization
551
+ clonedProps.unchangedChildSnapshots = Object.fromEntries(this.unchangedChildSnapshots);
552
+ return clonedProps;
553
+ }
554
+ /**
555
+ * Deserializes a plain object back into this KritzelGroup instance.
556
+ * Restores the unchangedChildSnapshots Map from the serialized object format.
557
+ * @param object - The serialized plain object containing group data.
558
+ * @returns This group instance after deserialization, cast to type T.
559
+ */
560
+ deserialize(object) {
561
+ super.deserialize(object);
562
+ // Restore the Map from serialized object
563
+ if (object.unchangedChildSnapshots) {
564
+ this.unchangedChildSnapshots = new Map(Object.entries(object.unchangedChildSnapshots));
565
+ }
566
+ return this;
567
+ }
568
+ /**
569
+ * Persists the current state of this group to the store.
570
+ * Triggers synchronization with y.js for collaborative editing.
571
+ */
572
+ update() {
573
+ this._core.store.objects.update(this);
574
+ }
575
+ /**
576
+ * Updates the workspace ID for this group and all its children recursively.
577
+ * Handles nested groups by recursively calling this method on child groups.
578
+ * @param workspaceId - The new workspace ID to assign to this group and its children.
579
+ */
580
+ updateWorkspaceId(workspaceId) {
581
+ this.workspaceId = workspaceId;
582
+ this.children.forEach(child => {
583
+ child.workspaceId = workspaceId;
584
+ // Recursively update nested groups
585
+ if (KritzelClassHelper.isInstanceOf(child, 'KritzelGroup')) {
586
+ child.updateWorkspaceId(workspaceId);
587
+ }
588
+ });
589
+ }
590
+ }