@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,341 @@
1
+ import { KRITZEL_LICENSE_PUBLIC_KEY, KRITZEL_LICENSE_TOKEN_PREFIX } from "../../constants/license.constants";
2
+ /** Minimum delay (ms) between periodic license re-validations. */
3
+ const MIN_REVALIDATION_DELAY_MS = 30_000;
4
+ /** Maximum delay (ms) between periodic license re-validations. */
5
+ const MAX_REVALIDATION_DELAY_MS = 60_000;
6
+ /**
7
+ * Manages license validation state for the Kritzel editor.
8
+ *
9
+ * The manager is owned per {@link KritzelCore} instance (like the theme and
10
+ * localization managers) so that multiple editors on the same page validate
11
+ * independently.
12
+ *
13
+ * A license key is an offline Ed25519 signed token of the form
14
+ * `KRTZL1.<base64url(payload)>.<base64url(signature)>`. The library verifies it
15
+ * against the embedded {@link KRITZEL_LICENSE_PUBLIC_KEY}; only the owner can
16
+ * mint tokens, with the matching private key (see scripts/license/).
17
+ *
18
+ * Responsibilities:
19
+ * - Cheaply reject absent/malformed/expired keys synchronously so the watermark
20
+ * never flashes off for an obviously invalid key.
21
+ * - Verify the signature asynchronously via WebCrypto, then drive a rerender if
22
+ * the licensed state changed so the watermark is re-asserted on the reactive
23
+ * render path.
24
+ * - Periodically re-check on a randomized interval so the check is harder to
25
+ * stub out programmatically than a fixed `setInterval`. Re-checks reuse the
26
+ * cached verified token and only re-evaluate expiry, so crypto is not re-run
27
+ * on an unchanged key every tick.
28
+ *
29
+ * Failure semantics (fail open):
30
+ * - No key provided -> unlicensed (free tier, watermark shown). The normal
31
+ * default, not an error.
32
+ * - Key present but cleanly invalid (malformed, bad signature, expired) ->
33
+ * unlicensed.
34
+ * - Key present but validation throws an *unexpected* internal error, or the
35
+ * runtime lacks Ed25519 support in WebCrypto -> fail open and treat as
36
+ * licensed so a library defect or old browser never breaks a paying
37
+ * customer's app.
38
+ */
39
+ export class KritzelLicenseManager {
40
+ _core;
41
+ /** The most recently provided license key, re-checked on each periodic tick. */
42
+ _licenseKey;
43
+ /** Cached result of the latest validation. */
44
+ _isLicensed = false;
45
+ /**
46
+ * The token whose signature most recently verified successfully. Lets the
47
+ * periodic re-check skip crypto and only re-evaluate expiry while the key is
48
+ * unchanged.
49
+ */
50
+ _verifiedToken;
51
+ /**
52
+ * Monotonic id incremented on every {@link validate} call. An in-flight async
53
+ * verification only commits its result if its id still matches, so a stale
54
+ * verification resolving after a newer call can never clobber fresh state.
55
+ */
56
+ _validationId = 0;
57
+ /** Cached imported public key, lazily created on first signature check. */
58
+ _publicKeyPromise;
59
+ /** Handle for the self-rescheduling re-validation timer. */
60
+ _timer = null;
61
+ /**
62
+ * Creates a new KritzelLicenseManager instance.
63
+ * @param core - The KritzelCore instance this manager belongs to
64
+ */
65
+ constructor(core) {
66
+ this._core = core;
67
+ }
68
+ /**
69
+ * Whether the editor is currently considered licensed (watermark hidden).
70
+ */
71
+ get isLicensed() {
72
+ return this._isLicensed;
73
+ }
74
+ /**
75
+ * Validates the given license key.
76
+ *
77
+ * Runs a synchronous structural pre-check first: an absent, malformed, or
78
+ * already-expired key resolves the state immediately (no async work). A
79
+ * structurally valid key then has its signature verified asynchronously; the
80
+ * licensed state is committed (and a rerender triggered) only if it changed.
81
+ *
82
+ * The return value reflects the state known *synchronously* at call time. The
83
+ * authoritative result for a structurally valid key arrives shortly after via
84
+ * the async verification and the reactive rerender.
85
+ *
86
+ * @param key - The license key to validate, or undefined to clear the license
87
+ * @returns The licensed state known synchronously at call time
88
+ */
89
+ validate(key) {
90
+ this._licenseKey = key;
91
+ const validationId = ++this._validationId;
92
+ let pre;
93
+ try {
94
+ pre = this.preCheck(key);
95
+ }
96
+ catch {
97
+ // Fail open: an unexpected internal error in the cheap pre-check must
98
+ // never break a paying customer's app.
99
+ this.commit(true, validationId);
100
+ return this._isLicensed;
101
+ }
102
+ if (pre.status === 'rejected') {
103
+ this._verifiedToken = undefined;
104
+ this.commit(false, validationId);
105
+ return this._isLicensed;
106
+ }
107
+ // Structurally valid and unexpired. If we already verified this exact token,
108
+ // the signature is still good, so license it without re-running crypto.
109
+ if (this._verifiedToken === key) {
110
+ this.commit(true, validationId);
111
+ return this._isLicensed;
112
+ }
113
+ // Otherwise verify the signature asynchronously. Leave the current state
114
+ // untouched until it settles so a forged token cannot even briefly hide the
115
+ // watermark (default state is unlicensed), and a valid renewal does not flap.
116
+ this.verifySignature(pre.payloadSegment, pre.signatureSegment)
117
+ .then(valid => {
118
+ if (validationId !== this._validationId) {
119
+ return; // A newer validate() superseded this one.
120
+ }
121
+ if (valid) {
122
+ this._verifiedToken = key;
123
+ this.commit(true, validationId);
124
+ }
125
+ else {
126
+ this._verifiedToken = undefined;
127
+ this.commit(false, validationId);
128
+ }
129
+ })
130
+ .catch(() => {
131
+ if (validationId !== this._validationId) {
132
+ return;
133
+ }
134
+ // Fail open on unexpected crypto errors / missing Ed25519 support.
135
+ this.commit(true, validationId);
136
+ });
137
+ return this._isLicensed;
138
+ }
139
+ /**
140
+ * Starts periodic re-validation on a randomized interval between
141
+ * {@link MIN_REVALIDATION_DELAY_MS} and {@link MAX_REVALIDATION_DELAY_MS}.
142
+ *
143
+ * Uses a self-rescheduling `setTimeout` (a fresh random delay each cycle)
144
+ * rather than a fixed `setInterval`, making the check fractionally harder to
145
+ * predict and no-op programmatically. Any existing timer is cleared first so
146
+ * the method is idempotent.
147
+ */
148
+ startPeriodicValidation() {
149
+ this.stopPeriodicValidation();
150
+ this.scheduleNextValidation();
151
+ }
152
+ /**
153
+ * Stops periodic re-validation and releases the timer.
154
+ */
155
+ stopPeriodicValidation() {
156
+ if (this._timer !== null) {
157
+ clearTimeout(this._timer);
158
+ this._timer = null;
159
+ }
160
+ }
161
+ /**
162
+ * Cleanup hook called when the editor is torn down.
163
+ */
164
+ destroy() {
165
+ this.stopPeriodicValidation();
166
+ }
167
+ /**
168
+ * Commits a new licensed state, triggering a rerender only when it changed.
169
+ * The {@link validationId} guard is checked by async callers; synchronous
170
+ * callers pass the current id.
171
+ */
172
+ commit(nextLicensed, validationId) {
173
+ if (validationId !== this._validationId) {
174
+ return;
175
+ }
176
+ if (nextLicensed !== this._isLicensed) {
177
+ this._isLicensed = nextLicensed;
178
+ this._core.rerender();
179
+ }
180
+ }
181
+ /**
182
+ * Schedules the next re-validation tick at a randomized delay.
183
+ */
184
+ scheduleNextValidation() {
185
+ const delay = this.getRandomRevalidationDelay();
186
+ this._timer = setTimeout(() => {
187
+ this.validate(this._licenseKey);
188
+ this.scheduleNextValidation();
189
+ }, delay);
190
+ }
191
+ /**
192
+ * Returns a random delay within the configured re-validation window.
193
+ */
194
+ getRandomRevalidationDelay() {
195
+ const span = MAX_REVALIDATION_DELAY_MS - MIN_REVALIDATION_DELAY_MS;
196
+ return MIN_REVALIDATION_DELAY_MS + Math.floor(Math.random() * (span + 1));
197
+ }
198
+ /**
199
+ * Synchronous structural pre-check of a license key: verifies the format
200
+ * prefix, three-part structure, JSON payload, and (if present) that the token
201
+ * has not expired. Does not verify the signature.
202
+ *
203
+ * @returns `rejected` for absent/malformed/expired keys, or `pass` with the
204
+ * parsed segments and claims for a structurally valid, unexpired token.
205
+ */
206
+ preCheck(key) {
207
+ if (key === undefined || key === null) {
208
+ return { status: 'rejected' };
209
+ }
210
+ const token = key.trim();
211
+ if (token.length === 0 || !token.startsWith(KRITZEL_LICENSE_TOKEN_PREFIX)) {
212
+ return { status: 'rejected' };
213
+ }
214
+ const body = token.slice(KRITZEL_LICENSE_TOKEN_PREFIX.length);
215
+ const parts = body.split('.');
216
+ if (parts.length !== 2 || parts[0].length === 0 || parts[1].length === 0) {
217
+ return { status: 'rejected' };
218
+ }
219
+ const [payloadSegment, signatureSegment] = parts;
220
+ let claims;
221
+ try {
222
+ claims = JSON.parse(this.base64UrlToString(payloadSegment));
223
+ }
224
+ catch {
225
+ return { status: 'rejected' };
226
+ }
227
+ if (claims === null || typeof claims !== 'object') {
228
+ return { status: 'rejected' };
229
+ }
230
+ if (typeof claims.exp === 'number' && claims.exp * 1000 <= Date.now()) {
231
+ return { status: 'rejected' }; // Cleanly expired.
232
+ }
233
+ const allowedDomains = this.normalizeAllowedDomains(claims.allowedDomains);
234
+ if (allowedDomains === null || allowedDomains.length === 0) {
235
+ return { status: 'rejected' };
236
+ }
237
+ const currentHostname = this.getCurrentHostname();
238
+ if (!currentHostname || !allowedDomains.includes(currentHostname)) {
239
+ return { status: 'rejected' };
240
+ }
241
+ return { status: 'pass', payloadSegment, signatureSegment, claims };
242
+ }
243
+ /** Returns the normalized current hostname, or null when unavailable/invalid. */
244
+ getCurrentHostname() {
245
+ const hostname = globalThis.location?.hostname;
246
+ if (typeof hostname !== 'string') {
247
+ return null;
248
+ }
249
+ return this.normalizeDomain(hostname);
250
+ }
251
+ /** Normalizes and validates the allowed domains claim. */
252
+ normalizeAllowedDomains(domains) {
253
+ if (!Array.isArray(domains)) {
254
+ return null;
255
+ }
256
+ const normalized = new Set();
257
+ for (const entry of domains) {
258
+ if (typeof entry !== 'string') {
259
+ return null;
260
+ }
261
+ const domain = this.normalizeDomain(entry);
262
+ if (!domain) {
263
+ return null;
264
+ }
265
+ normalized.add(domain);
266
+ }
267
+ return Array.from(normalized);
268
+ }
269
+ /** Normalizes a domain and rejects malformed hostnames. */
270
+ normalizeDomain(value) {
271
+ const trimmed = value.trim().toLowerCase();
272
+ if (trimmed.length === 0) {
273
+ return null;
274
+ }
275
+ const withoutTrailingDot = trimmed.endsWith('.') ? trimmed.slice(0, -1) : trimmed;
276
+ if (withoutTrailingDot.length === 0) {
277
+ return null;
278
+ }
279
+ try {
280
+ const parsed = new URL(`https://${withoutTrailingDot}`);
281
+ const normalizedHostname = parsed.hostname.toLowerCase();
282
+ if (normalizedHostname !== withoutTrailingDot) {
283
+ return null;
284
+ }
285
+ return normalizedHostname;
286
+ }
287
+ catch {
288
+ return null;
289
+ }
290
+ }
291
+ /**
292
+ * Verifies the Ed25519 signature of the token against the embedded public
293
+ * key. Resolves true/false for a definitive valid/invalid signature.
294
+ *
295
+ * Rejects (rather than resolving false) on unexpected crypto failures or when
296
+ * the runtime lacks Ed25519 support, so the caller fails open.
297
+ */
298
+ async verifySignature(payloadSegment, signatureSegment) {
299
+ const publicKey = await this.getPublicKey();
300
+ const data = this.utf8Bytes(payloadSegment);
301
+ const signature = this.base64UrlToBytes(signatureSegment);
302
+ return crypto.subtle.verify('Ed25519', publicKey, signature, data);
303
+ }
304
+ /**
305
+ * Imports and caches the embedded Ed25519 public key for signature checks.
306
+ */
307
+ getPublicKey() {
308
+ if (!this._publicKeyPromise) {
309
+ const raw = this.base64UrlToBytes(KRITZEL_LICENSE_PUBLIC_KEY);
310
+ this._publicKeyPromise = Promise.resolve().then(() => crypto.subtle.importKey('raw', raw, { name: 'Ed25519' }, false, ['verify']));
311
+ // If import fails (e.g. no Ed25519 support), drop the cache so a later
312
+ // tick can retry, and let the rejection propagate to fail open.
313
+ this._publicKeyPromise.catch(() => {
314
+ this._publicKeyPromise = undefined;
315
+ });
316
+ }
317
+ return this._publicKeyPromise;
318
+ }
319
+ /** Decodes a base64url string to its UTF-8 text. */
320
+ base64UrlToString(value) {
321
+ return new TextDecoder().decode(this.base64UrlToBytes(value));
322
+ }
323
+ /** Decodes a base64url string to raw bytes. */
324
+ base64UrlToBytes(value) {
325
+ const base64 = value.replace(/-/g, '+').replace(/_/g, '/');
326
+ const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
327
+ const binary = atob(padded);
328
+ const bytes = new Uint8Array(new ArrayBuffer(binary.length));
329
+ for (let i = 0; i < binary.length; i++) {
330
+ bytes[i] = binary.charCodeAt(i);
331
+ }
332
+ return bytes;
333
+ }
334
+ /** Encodes a string to its UTF-8 bytes. */
335
+ utf8Bytes(value) {
336
+ const encoded = new TextEncoder().encode(value);
337
+ const bytes = new Uint8Array(new ArrayBuffer(encoded.length));
338
+ bytes.set(encoded);
339
+ return bytes;
340
+ }
341
+ }
@@ -0,0 +1,227 @@
1
+ import { LocalizationHelper } from "../../helpers/localization.helper";
2
+ import { EN_LOCALE } from "../../locales/en-locale";
3
+ import { DE_LOCALE } from "../../locales/de-locale";
4
+ import { FR_LOCALE } from "../../locales/fr-locale";
5
+ /** Key used to store the settings object in localStorage. */
6
+ const SETTINGS_STORAGE_KEY = 'kritzel-settings';
7
+ /** Default locale used when no stored preference exists. */
8
+ const DEFAULT_LOCALE = 'en';
9
+ /**
10
+ * Manages localization state and term resolution across the Kritzel editor.
11
+ *
12
+ * The manager is owned per {@link KritzelCore} instance (like the theme manager)
13
+ * so that multiple editors on the same page can use different languages in
14
+ * isolation.
15
+ *
16
+ * Term resolution follows a deterministic fallback chain for each key:
17
+ * 1. active locale's custom terms
18
+ * 2. active locale's built-in terms
19
+ * 3. fallback locale's custom terms
20
+ * 4. fallback locale's built-in terms
21
+ * 5. the key itself (last resort)
22
+ *
23
+ * Persistence of the selected locale is handled by the KritzelSettings
24
+ * component; this manager only reads the stored value.
25
+ */
26
+ export class KritzelLocalizationManager {
27
+ _core;
28
+ _storageKey;
29
+ /** Built-in locale definitions, keyed by locale code. */
30
+ _builtinLocales = new Map();
31
+ /** Consumer-registered locale definitions, keyed by locale code. */
32
+ _customLocales = new Map();
33
+ _currentLocale = DEFAULT_LOCALE;
34
+ _fallbackLocale = DEFAULT_LOCALE;
35
+ /** Whether the consumer explicitly configured a locale catalog (even an empty one) via `configureLocales`. */
36
+ _explicitLocales = false;
37
+ /**
38
+ * Creates a new KritzelLocalizationManager instance.
39
+ * Seeds the built-in locales and initializes the current locale from the
40
+ * settings object in localStorage (or the default locale).
41
+ *
42
+ * @param core - The KritzelCore instance this manager belongs to
43
+ */
44
+ constructor(core) {
45
+ this._core = core;
46
+ this._storageKey = core.editorId ? `${SETTINGS_STORAGE_KEY}-${core.editorId}` : SETTINGS_STORAGE_KEY;
47
+ this._builtinLocales.set(EN_LOCALE.code, EN_LOCALE);
48
+ this._builtinLocales.set(DE_LOCALE.code, DE_LOCALE);
49
+ this._builtinLocales.set(FR_LOCALE.code, FR_LOCALE);
50
+ this._currentLocale = this.getStoredLocale();
51
+ }
52
+ /**
53
+ * Gets the currently active locale code.
54
+ */
55
+ get currentLocale() {
56
+ return this._currentLocale;
57
+ }
58
+ /**
59
+ * Gets the fallback locale code used when a term is missing from the active locale.
60
+ */
61
+ get fallbackLocale() {
62
+ return this._fallbackLocale;
63
+ }
64
+ /**
65
+ * Sets the fallback locale code used when a term is missing from the active locale.
66
+ *
67
+ * @param code - The fallback locale code
68
+ */
69
+ setFallbackLocale(code) {
70
+ this._fallbackLocale = code;
71
+ }
72
+ /**
73
+ * Registers consumer-provided locale definitions. Definitions are merged by
74
+ * code; registering the same code again replaces the previous definition.
75
+ * A registered locale may provide a partial set of terms — missing terms are
76
+ * resolved through the fallback chain.
77
+ *
78
+ * @param locales - The locale definitions to register
79
+ */
80
+ registerLocales(locales) {
81
+ for (const locale of locales) {
82
+ this._customLocales.set(locale.code, locale);
83
+ }
84
+ }
85
+ /**
86
+ * Declaratively configures the full locale catalog, replacing any previously
87
+ * configured or registered custom locales. Unlike {@link registerLocales},
88
+ * this determines which locales are considered "available" (e.g. for a
89
+ * settings selector): passing `undefined` restores the built-in set
90
+ * (en/de/fr); passing an array (even empty) makes that array's codes the
91
+ * exclusive available set, falling back to `en` only if the array is empty.
92
+ * Built-in term fallback for missing keys is unaffected either way.
93
+ *
94
+ * @param locales - The full locale catalog, or `undefined` to use built-ins
95
+ */
96
+ configureLocales(locales) {
97
+ this._customLocales.clear();
98
+ this._explicitLocales = locales !== undefined;
99
+ if (locales) {
100
+ this.registerLocales(locales);
101
+ }
102
+ }
103
+ /**
104
+ * Resolves the locale code that should actually be activated, falling back
105
+ * to the first available locale when the requested one isn't available.
106
+ *
107
+ * @param requested - The locale code the consumer asked to activate
108
+ */
109
+ resolveActiveLocale(requested) {
110
+ const available = this.getAvailableLocales();
111
+ return available.includes(requested) ? requested : available[0];
112
+ }
113
+ /**
114
+ * Sets the active locale and triggers a re-render so UI strings update.
115
+ *
116
+ * @param code - The locale code to activate
117
+ */
118
+ setLocale(code) {
119
+ this._currentLocale = code;
120
+ this._core.rerender();
121
+ }
122
+ /**
123
+ * Gets the list of available locale codes. When a locale catalog was
124
+ * explicitly configured via {@link configureLocales}, only those codes are
125
+ * returned (or `[DEFAULT_LOCALE]` if the catalog is empty); otherwise the
126
+ * built-in and registered codes are combined.
127
+ */
128
+ getAvailableLocales() {
129
+ if (this._explicitLocales) {
130
+ const codes = Array.from(this._customLocales.keys());
131
+ return codes.length > 0 ? codes : [DEFAULT_LOCALE];
132
+ }
133
+ return Array.from(new Set([...this._builtinLocales.keys(), ...this._customLocales.keys()]));
134
+ }
135
+ /**
136
+ * Gets the available locales as `{ code, label }` pairs for use in a selector.
137
+ * A registered locale's label takes precedence over the built-in label; the
138
+ * code is used as the label when none is provided.
139
+ */
140
+ getAvailableLocaleOptions() {
141
+ return this.getAvailableLocales().map(code => ({ code, label: this.getLocaleLabel(code) }));
142
+ }
143
+ /**
144
+ * Gets the display label for a locale code, falling back to the code itself.
145
+ *
146
+ * @param code - The locale code
147
+ */
148
+ getLocaleLabel(code) {
149
+ return this._customLocales.get(code)?.label ?? this._builtinLocales.get(code)?.label ?? code;
150
+ }
151
+ /**
152
+ * Resolves a term key to its translated string for the active locale and
153
+ * interpolates any `{placeholder}` tokens.
154
+ *
155
+ * @param key - The term key to resolve
156
+ * @param vars - Optional values for `{placeholder}` interpolation
157
+ * @returns The translated, interpolated string (or the key if unresolved)
158
+ *
159
+ * @example
160
+ * manager.translate('menu.copy'); // 'Copy'
161
+ * manager.translate('share.expires', { date: '5/1' }); // 'Expires 5/1'
162
+ */
163
+ translate(key, vars) {
164
+ const resolved = this._customLocales.get(this._currentLocale)?.terms[key] ??
165
+ this._builtinLocales.get(this._currentLocale)?.terms[key] ??
166
+ this._customLocales.get(this._fallbackLocale)?.terms[key] ??
167
+ this._builtinLocales.get(this._fallbackLocale)?.terms[key] ??
168
+ key;
169
+ return LocalizationHelper.interpolate(resolved, vars);
170
+ }
171
+ /**
172
+ * Resolves every known term key for the active locale into a flat map.
173
+ *
174
+ * The key set is the union of all keys defined across the built-in and
175
+ * registered locales, so consumer-added keys are included. Each value is
176
+ * resolved through the same fallback chain as {@link translate} (without
177
+ * interpolation, since these are shared, variable-free UI labels).
178
+ *
179
+ * @returns A map of every term key to its resolved string for the active locale
180
+ */
181
+ getAllTerms() {
182
+ const keys = new Set();
183
+ for (const locale of [...this._builtinLocales.values(), ...this._customLocales.values()]) {
184
+ for (const key of Object.keys(locale.terms)) {
185
+ keys.add(key);
186
+ }
187
+ }
188
+ const result = {};
189
+ for (const key of keys) {
190
+ result[key] = this.translate(key);
191
+ }
192
+ return result;
193
+ }
194
+ /**
195
+ * Reads the stored locale from the settings object in localStorage using this
196
+ * instance's namespaced key.
197
+ *
198
+ * @returns The stored locale code if valid, or the default locale
199
+ */
200
+ getStoredLocale() {
201
+ if (typeof localStorage === 'undefined') {
202
+ return DEFAULT_LOCALE;
203
+ }
204
+ const stored = localStorage.getItem(this._storageKey);
205
+ if (!stored) {
206
+ return DEFAULT_LOCALE;
207
+ }
208
+ try {
209
+ const parsed = JSON.parse(stored);
210
+ if (typeof parsed?.locale === 'string') {
211
+ return parsed.locale;
212
+ }
213
+ }
214
+ catch {
215
+ // Invalid JSON, use default
216
+ }
217
+ return DEFAULT_LOCALE;
218
+ }
219
+ /**
220
+ * Cleans up the localization manager state.
221
+ * Provided for lifecycle parity with other managers.
222
+ */
223
+ cleanup() {
224
+ this._customLocales.clear();
225
+ this._explicitLocales = false;
226
+ }
227
+ }