@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.
- package/LICENSE.md +50 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/engine.constants-CakmdKMW.js +28206 -0
- package/dist/cjs/index-BbbWU2aN.js +1742 -0
- package/dist/cjs/index.cjs.js +4232 -0
- package/dist/cjs/kritzel-awareness-cursors_5.cjs.entry.js +28004 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/stencil.cjs.js +25 -0
- package/dist/collection/classes/core/core.class.js +1389 -0
- package/dist/collection/classes/core/reviver.class.js +124 -0
- package/dist/collection/classes/core/store.class.js +337 -0
- package/dist/collection/classes/core/viewport.class.js +794 -0
- package/dist/collection/classes/core/workspace.class.js +112 -0
- package/dist/collection/classes/handlers/base.handler.js +20 -0
- package/dist/collection/classes/handlers/context-menu.handler.js +170 -0
- package/dist/collection/classes/handlers/hover.handler.js +35 -0
- package/dist/collection/classes/handlers/key.handler.js +162 -0
- package/dist/collection/classes/handlers/line-handle.handler.js +475 -0
- package/dist/collection/classes/handlers/move.handler.js +295 -0
- package/dist/collection/classes/handlers/resize.handler.js +327 -0
- package/dist/collection/classes/handlers/rotation.handler.js +174 -0
- package/dist/collection/classes/handlers/selection.handler.js +526 -0
- package/dist/collection/classes/managers/anchor.manager.js +1476 -0
- package/dist/collection/classes/managers/browser-permission.manager.js +64 -0
- package/dist/collection/classes/managers/clipboard.manager.js +346 -0
- package/dist/collection/classes/managers/clipboard.types.js +1 -0
- package/dist/collection/classes/managers/cursor.manager.js +139 -0
- package/dist/collection/classes/managers/license.manager.js +341 -0
- package/dist/collection/classes/managers/localization.manager.js +227 -0
- package/dist/collection/classes/managers/theme.manager.js +206 -0
- package/dist/collection/classes/objects/base-object.class.js +462 -0
- package/dist/collection/classes/objects/dynamic-object.class.js +437 -0
- package/dist/collection/classes/objects/group.class.js +590 -0
- package/dist/collection/classes/objects/image.class.js +500 -0
- package/dist/collection/classes/objects/line.class.js +789 -0
- package/dist/collection/classes/objects/path.class.js +578 -0
- package/dist/collection/classes/objects/selection-box.class.js +32 -0
- package/dist/collection/classes/objects/selection-group.class.js +752 -0
- package/dist/collection/classes/objects/shape.class.js +628 -0
- package/dist/collection/classes/objects/text.class.js +461 -0
- package/dist/collection/classes/providers/assets/asset-resolver.class.js +536 -0
- package/dist/collection/classes/providers/assets/http-asset-provider.class.js +111 -0
- package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +241 -0
- package/dist/collection/classes/providers/assets/presigned-asset-provider.class.js +86 -0
- package/dist/collection/classes/providers/paste-intent/event-paste-intent.provider.js +48 -0
- package/dist/collection/classes/providers/paste-intent/ios-paste-intent.provider.js +16 -0
- package/dist/collection/classes/providers/paste-intent/navigator-paste-intent.provider.js +86 -0
- package/dist/collection/classes/providers/sync/broadcast-sync-provider.class.js +100 -0
- package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +333 -0
- package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +69 -0
- package/dist/collection/classes/providers/sync/indexeddb-sync-provider.class.js +39 -0
- package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +110 -0
- package/dist/collection/classes/registries/dynamic-object-renderer.registry.js +52 -0
- package/dist/collection/classes/registries/font-registry.class.js +161 -0
- package/dist/collection/classes/registries/icon-registry.class.js +118 -0
- package/dist/collection/classes/registries/paste-intent-provider.registry.js +26 -0
- package/dist/collection/classes/registries/tool.registry.js +69 -0
- package/dist/collection/classes/structures/app-state-map.structure.js +461 -0
- package/dist/collection/classes/structures/object-map.structure.js +1103 -0
- package/dist/collection/classes/structures/quadtree.structure.js +251 -0
- package/dist/collection/classes/tools/base-tool.class.js +88 -0
- package/dist/collection/classes/tools/brush-tool.class.js +236 -0
- package/dist/collection/classes/tools/eraser-tool.class.js +133 -0
- package/dist/collection/classes/tools/image-tool.class.js +152 -0
- package/dist/collection/classes/tools/line-tool.class.js +249 -0
- package/dist/collection/classes/tools/selection-tool.class.js +611 -0
- package/dist/collection/classes/tools/shape-tool.class.js +251 -0
- package/dist/collection/classes/tools/text-tool.class.js +179 -0
- package/dist/collection/collection-manifest.json +17 -0
- package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.css +115 -0
- package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.js +380 -0
- package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.css +10 -0
- package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.js +153 -0
- package/dist/collection/components/kritzel-engine/kritzel-engine.css +81 -0
- package/dist/collection/components/kritzel-engine/kritzel-engine.js +6345 -0
- package/dist/collection/components/kritzel-icon/kritzel-icon.css +18 -0
- package/dist/collection/components/kritzel-icon/kritzel-icon.js +93 -0
- package/dist/collection/components/kritzel-watermark/kritzel-watermark.css +29 -0
- package/dist/collection/components/kritzel-watermark/kritzel-watermark.js +83 -0
- package/dist/collection/configs/default-asset-storage.config.js +9 -0
- package/dist/collection/configs/default-brush-tool.config.js +9 -0
- package/dist/collection/configs/default-engine-config.js +73 -0
- package/dist/collection/configs/default-line-tool.config.js +12 -0
- package/dist/collection/configs/default-shape-tool.config.js +15 -0
- package/dist/collection/configs/default-sync.config.js +6 -0
- package/dist/collection/configs/default-text-tool.config.js +12 -0
- package/dist/collection/constants/color-palette.constants.js +40 -0
- package/dist/collection/constants/core.constants.js +1 -0
- package/dist/collection/constants/engine.constants.js +4 -0
- package/dist/collection/constants/license.constants.js +25 -0
- package/dist/collection/constants/schema.constants.js +4 -0
- package/dist/collection/constants/storage.constants.js +1 -0
- package/dist/collection/constants/stroke-size.constants.js +2 -0
- package/dist/collection/constants/text-tool-fonts.constants.js +18 -0
- package/dist/collection/constants/version.js +6 -0
- package/dist/collection/enums/alignment.enum.js +9 -0
- package/dist/collection/enums/event-button.enum.js +6 -0
- package/dist/collection/enums/handle-type.enum.js +7 -0
- package/dist/collection/enums/shape-type.enum.js +6 -0
- package/dist/collection/events/active-workspace-change.event.js +1 -0
- package/dist/collection/events/editor-is-ready.event.js +1 -0
- package/dist/collection/events/login.event.js +1 -0
- package/dist/collection/helpers/alignment.helper.js +73 -0
- package/dist/collection/helpers/class.helper.js +5 -0
- package/dist/collection/helpers/color.helper.js +106 -0
- package/dist/collection/helpers/cursor.helper.js +57 -0
- package/dist/collection/helpers/devices.helper.js +28 -0
- package/dist/collection/helpers/event.helper.js +58 -0
- package/dist/collection/helpers/geometry.helper.js +149 -0
- package/dist/collection/helpers/html.helper.js +116 -0
- package/dist/collection/helpers/image-file.helper.js +6 -0
- package/dist/collection/helpers/keyboard.helper.js +55 -0
- package/dist/collection/helpers/localization.helper.js +25 -0
- package/dist/collection/helpers/math.helper.js +8 -0
- package/dist/collection/helpers/migration.helper.js +45 -0
- package/dist/collection/helpers/object.helper.js +29 -0
- package/dist/collection/helpers/svg-export.helper.js +655 -0
- package/dist/collection/helpers/theme.helper.js +77 -0
- package/dist/collection/helpers/tool-config.helper.js +63 -0
- package/dist/collection/helpers/wheel.helper.js +113 -0
- package/dist/collection/index.js +107 -0
- package/dist/collection/interfaces/anchor.interface.js +1 -0
- package/dist/collection/interfaces/arrow-head.interface.js +1 -0
- package/dist/collection/interfaces/asset-provider.interface.js +1 -0
- package/dist/collection/interfaces/asset-storage-config.interface.js +1 -0
- package/dist/collection/interfaces/asset.interface.js +1 -0
- package/dist/collection/interfaces/bounding-box.interface.js +1 -0
- package/dist/collection/interfaces/clonable.interface.js +1 -0
- package/dist/collection/interfaces/context-menu-item.interface.js +1 -0
- package/dist/collection/interfaces/context-menu-state.interface.js +1 -0
- package/dist/collection/interfaces/debug-info.interface.js +1 -0
- package/dist/collection/interfaces/dialog.interface.js +1 -0
- package/dist/collection/interfaces/document-metadata.interface.js +1 -0
- package/dist/collection/interfaces/dynamic-object-renderer.interface.js +1 -0
- package/dist/collection/interfaces/engine-state.interface.js +1 -0
- package/dist/collection/interfaces/font.interface.js +1 -0
- package/dist/collection/interfaces/localization.interface.js +1 -0
- package/dist/collection/interfaces/login-config.interface.js +1 -0
- package/dist/collection/interfaces/master-detail.interface.js +1 -0
- package/dist/collection/interfaces/menu-item.interface.js +1 -0
- package/dist/collection/interfaces/migration.interface.js +1 -0
- package/dist/collection/interfaces/notification.interface.js +1 -0
- package/dist/collection/interfaces/object-change-event.interface.js +1 -0
- package/dist/collection/interfaces/object-export.interface.js +1 -0
- package/dist/collection/interfaces/object.interface.js +1 -0
- package/dist/collection/interfaces/paste-intent-provider.interface.js +1 -0
- package/dist/collection/interfaces/point.interface.js +1 -0
- package/dist/collection/interfaces/polygon.interface.js +1 -0
- package/dist/collection/interfaces/remote-cursor.interface.js +1 -0
- package/dist/collection/interfaces/selection-state.interface.js +1 -0
- package/dist/collection/interfaces/serializable.interface.js +1 -0
- package/dist/collection/interfaces/settings.interface.js +1 -0
- package/dist/collection/interfaces/share.interface.js +1 -0
- package/dist/collection/interfaces/shortcut.interface.js +1 -0
- package/dist/collection/interfaces/sync-config.interface.js +21 -0
- package/dist/collection/interfaces/sync-provider.interface.js +1 -0
- package/dist/collection/interfaces/theme.interface.js +1 -0
- package/dist/collection/interfaces/tool-config.interface.js +1 -0
- package/dist/collection/interfaces/tool-type.interface.js +1 -0
- package/dist/collection/interfaces/tool.interface.js +1 -0
- package/dist/collection/interfaces/toolbar-item.interface.js +1 -0
- package/dist/collection/interfaces/undo-state.interface.js +1 -0
- package/dist/collection/interfaces/user.interface.js +1 -0
- package/dist/collection/interfaces/viewport-state.interface.js +1 -0
- package/dist/collection/locales/de-locale.js +119 -0
- package/dist/collection/locales/en-locale.js +120 -0
- package/dist/collection/locales/fr-locale.js +119 -0
- package/dist/collection/migrations/app-state.migrations.js +47 -0
- package/dist/collection/migrations/workspace.migrations.js +67 -0
- package/dist/collection/themes/dark-theme.js +340 -0
- package/dist/collection/themes/light-theme.js +346 -0
- package/dist/collection/types/deep-readonly.type.js +1 -0
- package/dist/collection/types/state.types.js +1 -0
- package/dist/components/index.d.ts +47 -0
- package/dist/components/index.js +4143 -0
- package/dist/components/kritzel-awareness-cursors.d.ts +11 -0
- package/dist/components/kritzel-awareness-cursors.js +6 -0
- package/dist/components/kritzel-cursor-trail.d.ts +11 -0
- package/dist/components/kritzel-cursor-trail.js +6 -0
- package/dist/components/kritzel-engine.d.ts +11 -0
- package/dist/components/kritzel-engine.js +52641 -0
- package/dist/components/kritzel-icon.d.ts +11 -0
- package/dist/components/kritzel-icon.js +6 -0
- package/dist/components/kritzel-watermark.d.ts +11 -0
- package/dist/components/kritzel-watermark.js +6 -0
- package/dist/components/p-B2Htv9ou.js +49 -0
- package/dist/components/p-BvRGQvVI.js +3456 -0
- package/dist/components/p-CfSx6HU_.js +1469 -0
- package/dist/components/p-YP8wAcF4.js +122 -0
- package/dist/components/p-fx6msYHJ.js +167 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/engine.constants-Bl5-pbq-.js +28143 -0
- package/dist/esm/index-BU9Mv7y0.js +1715 -0
- package/dist/esm/index.js +4134 -0
- package/dist/esm/kritzel-awareness-cursors_5.entry.js +27978 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/stencil.js +21 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/stencil/index.esm.js +4134 -0
- package/dist/stencil/p-BU9Mv7y0.js +1702 -0
- package/dist/stencil/p-Bl5-pbq-.js +28143 -0
- package/dist/stencil/p-DQuL1Twl.js +3 -0
- package/dist/stencil/p-f0a8b7af.entry.js +27978 -0
- package/dist/stencil/stencil.esm.js +21 -0
- package/dist/types/classes/core/core.class.d.ts +532 -0
- package/dist/types/classes/core/reviver.class.d.ts +32 -0
- package/dist/types/classes/core/store.class.d.ts +198 -0
- package/dist/types/classes/core/viewport.class.d.ts +256 -0
- package/dist/types/classes/core/workspace.class.d.ts +95 -0
- package/dist/types/classes/handlers/base.handler.d.ts +18 -0
- package/dist/types/classes/handlers/context-menu.handler.d.ts +67 -0
- package/dist/types/classes/handlers/hover.handler.d.ts +23 -0
- package/dist/types/classes/handlers/key.handler.d.ts +44 -0
- package/dist/types/classes/handlers/line-handle.handler.d.ts +115 -0
- package/dist/types/classes/handlers/move.handler.d.ts +94 -0
- package/dist/types/classes/handlers/resize.handler.d.ts +95 -0
- package/dist/types/classes/handlers/rotation.handler.d.ts +50 -0
- package/dist/types/classes/handlers/selection.handler.d.ts +153 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +513 -0
- package/dist/types/classes/managers/browser-permission.manager.d.ts +41 -0
- package/dist/types/classes/managers/clipboard.manager.d.ts +71 -0
- package/dist/types/classes/managers/clipboard.types.d.ts +23 -0
- package/dist/types/classes/managers/cursor.manager.d.ts +66 -0
- package/dist/types/classes/managers/license.manager.d.ts +147 -0
- package/dist/types/classes/managers/localization.manager.d.ts +145 -0
- package/dist/types/classes/managers/theme.manager.d.ts +112 -0
- package/dist/types/classes/objects/base-object.class.d.ts +266 -0
- package/dist/types/classes/objects/dynamic-object.class.d.ts +148 -0
- package/dist/types/classes/objects/group.class.d.ts +231 -0
- package/dist/types/classes/objects/image.class.d.ts +246 -0
- package/dist/types/classes/objects/line.class.d.ts +285 -0
- package/dist/types/classes/objects/path.class.d.ts +220 -0
- package/dist/types/classes/objects/selection-box.class.d.ts +19 -0
- package/dist/types/classes/objects/selection-group.class.d.ts +267 -0
- package/dist/types/classes/objects/shape.class.d.ts +322 -0
- package/dist/types/classes/objects/text.class.d.ts +197 -0
- package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +141 -0
- package/dist/types/classes/providers/assets/http-asset-provider.class.d.ts +79 -0
- package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +69 -0
- package/dist/types/classes/providers/assets/presigned-asset-provider.class.d.ts +69 -0
- package/dist/types/classes/providers/paste-intent/event-paste-intent.provider.d.ts +8 -0
- package/dist/types/classes/providers/paste-intent/ios-paste-intent.provider.d.ts +6 -0
- package/dist/types/classes/providers/paste-intent/navigator-paste-intent.provider.d.ts +9 -0
- package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +23 -0
- package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +163 -0
- package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +39 -0
- package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +25 -0
- package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +63 -0
- package/dist/types/classes/registries/dynamic-object-renderer.registry.d.ts +32 -0
- package/dist/types/classes/registries/font-registry.class.d.ts +19 -0
- package/dist/types/classes/registries/icon-registry.class.d.ts +39 -0
- package/dist/types/classes/registries/paste-intent-provider.registry.d.ts +10 -0
- package/dist/types/classes/registries/tool.registry.d.ts +53 -0
- package/dist/types/classes/structures/app-state-map.structure.d.ts +171 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +403 -0
- package/dist/types/classes/structures/quadtree.structure.d.ts +128 -0
- package/dist/types/classes/tools/base-tool.class.d.ts +72 -0
- package/dist/types/classes/tools/brush-tool.class.d.ts +68 -0
- package/dist/types/classes/tools/eraser-tool.class.d.ts +38 -0
- package/dist/types/classes/tools/image-tool.class.d.ts +74 -0
- package/dist/types/classes/tools/line-tool.class.d.ts +63 -0
- package/dist/types/classes/tools/selection-tool.class.d.ts +188 -0
- package/dist/types/classes/tools/shape-tool.class.d.ts +90 -0
- package/dist/types/classes/tools/text-tool.class.d.ts +66 -0
- package/dist/types/components/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +29 -0
- package/dist/types/components/kritzel-cursor-trail/kritzel-cursor-trail.d.ts +19 -0
- package/dist/types/components/kritzel-engine/kritzel-engine.d.ts +695 -0
- package/dist/types/components/kritzel-icon/kritzel-icon.d.ts +6 -0
- package/dist/types/components/kritzel-watermark/kritzel-watermark.d.ts +20 -0
- package/dist/types/components.d.ts +981 -0
- package/dist/types/configs/default-asset-storage.config.d.ts +8 -0
- package/dist/types/configs/default-brush-tool.config.d.ts +2 -0
- package/dist/types/configs/default-engine-config.d.ts +2 -0
- package/dist/types/configs/default-line-tool.config.d.ts +2 -0
- package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
- package/dist/types/configs/default-sync.config.d.ts +5 -0
- package/dist/types/configs/default-text-tool.config.d.ts +2 -0
- package/dist/types/constants/color-palette.constants.d.ts +31 -0
- package/dist/types/constants/core.constants.d.ts +0 -0
- package/dist/types/constants/engine.constants.d.ts +4 -0
- package/dist/types/constants/license.constants.d.ts +25 -0
- package/dist/types/constants/schema.constants.d.ts +4 -0
- package/dist/types/constants/storage.constants.d.ts +1 -0
- package/dist/types/constants/stroke-size.constants.d.ts +2 -0
- package/dist/types/constants/text-tool-fonts.constants.d.ts +3 -0
- package/dist/types/constants/version.d.ts +6 -0
- package/dist/types/enums/alignment.enum.d.ts +8 -0
- package/dist/types/enums/event-button.enum.d.ts +5 -0
- package/dist/types/enums/handle-type.enum.d.ts +6 -0
- package/dist/types/enums/shape-type.enum.d.ts +5 -0
- package/dist/types/events/active-workspace-change.event.d.ts +7 -0
- package/dist/types/events/editor-is-ready.event.d.ts +18 -0
- package/dist/types/events/login.event.d.ts +3 -0
- package/dist/types/helpers/alignment.helper.d.ts +21 -0
- package/dist/types/helpers/class.helper.d.ts +3 -0
- package/dist/types/helpers/color.helper.d.ts +34 -0
- package/dist/types/helpers/cursor.helper.d.ts +22 -0
- package/dist/types/helpers/devices.helper.d.ts +8 -0
- package/dist/types/helpers/event.helper.d.ts +6 -0
- package/dist/types/helpers/geometry.helper.d.ts +38 -0
- package/dist/types/helpers/html.helper.d.ts +8 -0
- package/dist/types/helpers/image-file.helper.d.ts +3 -0
- package/dist/types/helpers/keyboard.helper.d.ts +6 -0
- package/dist/types/helpers/localization.helper.d.ts +18 -0
- package/dist/types/helpers/math.helper.d.ts +4 -0
- package/dist/types/helpers/migration.helper.d.ts +30 -0
- package/dist/types/helpers/object.helper.d.ts +9 -0
- package/dist/types/helpers/svg-export.helper.d.ts +231 -0
- package/dist/types/helpers/theme.helper.d.ts +42 -0
- package/dist/types/helpers/tool-config.helper.d.ts +4 -0
- package/dist/types/helpers/wheel.helper.d.ts +9 -0
- package/dist/types/index.d.ts +109 -0
- package/dist/types/interfaces/anchor.interface.d.ts +147 -0
- package/dist/types/interfaces/arrow-head.interface.d.ts +27 -0
- package/dist/types/interfaces/asset-provider.interface.d.ts +88 -0
- package/dist/types/interfaces/asset-storage-config.interface.d.ts +40 -0
- package/dist/types/interfaces/asset.interface.d.ts +43 -0
- package/dist/types/interfaces/bounding-box.interface.d.ts +8 -0
- package/dist/types/interfaces/clonable.interface.d.ts +3 -0
- package/dist/types/interfaces/context-menu-item.interface.d.ts +25 -0
- package/dist/types/interfaces/context-menu-state.interface.d.ts +16 -0
- package/dist/types/interfaces/debug-info.interface.d.ts +7 -0
- package/dist/types/interfaces/dialog.interface.d.ts +4 -0
- package/dist/types/interfaces/document-metadata.interface.d.ts +6 -0
- package/dist/types/interfaces/dynamic-object-renderer.interface.d.ts +40 -0
- package/dist/types/interfaces/engine-state.interface.d.ts +82 -0
- package/dist/types/interfaces/font.interface.d.ts +15 -0
- package/dist/types/interfaces/localization.interface.d.ts +143 -0
- package/dist/types/interfaces/login-config.interface.d.ts +24 -0
- package/dist/types/interfaces/master-detail.interface.d.ts +14 -0
- package/dist/types/interfaces/menu-item.interface.d.ts +27 -0
- package/dist/types/interfaces/migration.interface.d.ts +16 -0
- package/dist/types/interfaces/notification.interface.d.ts +10 -0
- package/dist/types/interfaces/object-change-event.interface.d.ts +31 -0
- package/dist/types/interfaces/object-export.interface.d.ts +20 -0
- package/dist/types/interfaces/object.interface.d.ts +53 -0
- package/dist/types/interfaces/paste-intent-provider.interface.d.ts +10 -0
- package/dist/types/interfaces/point.interface.d.ts +4 -0
- package/dist/types/interfaces/polygon.interface.d.ts +7 -0
- package/dist/types/interfaces/remote-cursor.interface.d.ts +18 -0
- package/dist/types/interfaces/selection-state.interface.d.ts +7 -0
- package/dist/types/interfaces/serializable.interface.d.ts +5 -0
- package/dist/types/interfaces/settings.interface.d.ts +25 -0
- package/dist/types/interfaces/share.interface.d.ts +9 -0
- package/dist/types/interfaces/shortcut.interface.d.ts +10 -0
- package/dist/types/interfaces/sync-config.interface.d.ts +41 -0
- package/dist/types/interfaces/sync-provider.interface.d.ts +66 -0
- package/dist/types/interfaces/theme.interface.d.ts +553 -0
- package/dist/types/interfaces/tool-config.interface.d.ts +24 -0
- package/dist/types/interfaces/tool-type.interface.d.ts +1 -0
- package/dist/types/interfaces/tool.interface.d.ts +8 -0
- package/dist/types/interfaces/toolbar-item.interface.d.ts +66 -0
- package/dist/types/interfaces/undo-state.interface.d.ts +6 -0
- package/dist/types/interfaces/user.interface.d.ts +22 -0
- package/dist/types/interfaces/viewport-state.interface.d.ts +7 -0
- package/dist/types/locales/de-locale.d.ts +5 -0
- package/dist/types/locales/en-locale.d.ts +6 -0
- package/dist/types/locales/fr-locale.d.ts +5 -0
- package/dist/types/migrations/app-state.migrations.d.ts +11 -0
- package/dist/types/migrations/workspace.migrations.d.ts +11 -0
- package/dist/types/stencil-public-runtime.d.ts +1873 -0
- package/dist/types/themes/dark-theme.d.ts +5 -0
- package/dist/types/themes/light-theme.d.ts +5 -0
- package/dist/types/types/deep-readonly.type.d.ts +7 -0
- package/dist/types/types/state.types.d.ts +3 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +101 -0
- package/readme.md +11 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { AssetNotFoundError } from "../providers/assets/asset-resolver.class";
|
|
2
|
+
import { KritzelBaseObject } from "./base-object.class";
|
|
3
|
+
import { KritzelMathHelper } from "../../helpers/math.helper";
|
|
4
|
+
/**
|
|
5
|
+
* Represents an image object on the canvas.
|
|
6
|
+
*
|
|
7
|
+
* Image bytes are NOT stored on this object or inside the Yjs document.
|
|
8
|
+
* Instead, the image is identified by a stable `assetId`; the actual
|
|
9
|
+
* bytes live in the asset storage layer (see `KritzelAssetResolver`).
|
|
10
|
+
* This keeps the CRDT small and lets images be served from pluggable
|
|
11
|
+
* storage (IndexedDB, HTTP, pre-signed S3, ...).
|
|
12
|
+
*
|
|
13
|
+
* Legacy images persisted before the asset layer existed may still carry
|
|
14
|
+
* a `src` data URL; the renderer and migration path treat `src` as a
|
|
15
|
+
* read-only fallback that is upgraded to an `assetId` on first load.
|
|
16
|
+
*/
|
|
17
|
+
export class KritzelImage extends KritzelBaseObject {
|
|
18
|
+
__class__ = 'KritzelImage';
|
|
19
|
+
/**
|
|
20
|
+
* Stable asset identifier (uuid) persisted in the Yjs document.
|
|
21
|
+
* Used by the asset resolver to locate the image bytes across
|
|
22
|
+
* devices and storage backends.
|
|
23
|
+
*/
|
|
24
|
+
assetId = '';
|
|
25
|
+
/**
|
|
26
|
+
* MIME type of the referenced asset (e.g. `image/png`). Persisted in
|
|
27
|
+
* the Yjs document alongside `assetId` so the renderer can hint
|
|
28
|
+
* browsers and the exporter can produce correct data URLs.
|
|
29
|
+
*/
|
|
30
|
+
mimeType = '';
|
|
31
|
+
/**
|
|
32
|
+
* Legacy inline source (typically a `data:` URL). Preserved only for
|
|
33
|
+
* backward compatibility with documents that were created before the
|
|
34
|
+
* asset storage layer existed. New images should use `assetId`.
|
|
35
|
+
*
|
|
36
|
+
* @deprecated Use `assetId` with an asset storage provider instead.
|
|
37
|
+
*/
|
|
38
|
+
src = '';
|
|
39
|
+
maxWidth = 300;
|
|
40
|
+
maxHeight = 300;
|
|
41
|
+
maxCompressionSize = 1200;
|
|
42
|
+
// --- Transient (not persisted to Yjs) ---
|
|
43
|
+
/**
|
|
44
|
+
* URL resolved from the asset storage layer (e.g. a `blob:` or https URL).
|
|
45
|
+
* Not serialized into the Yjs document.
|
|
46
|
+
*/
|
|
47
|
+
resolvedSrc;
|
|
48
|
+
/**
|
|
49
|
+
* Current load state for the referenced asset.
|
|
50
|
+
* Not serialized into the Yjs document.
|
|
51
|
+
*/
|
|
52
|
+
loadState = 'idle';
|
|
53
|
+
/**
|
|
54
|
+
* Maximum number of resolution attempts per page load before the
|
|
55
|
+
* image is considered permanently failed. Defaults to 3.
|
|
56
|
+
*
|
|
57
|
+
* Only attempts that fail with a definitive "asset not found"
|
|
58
|
+
* (i.e. {@link AssetNotFoundError}) consume this budget. Transient
|
|
59
|
+
* failures (network blips, remote temporarily unreachable) do not
|
|
60
|
+
* count against the budget; they are bounded by
|
|
61
|
+
* {@link maxTransientRetryDurationMs} instead.
|
|
62
|
+
*
|
|
63
|
+
* The counter is transient (not persisted to Yjs) and resets every
|
|
64
|
+
* time a fresh `KritzelImage` instance is constructed, so a full page
|
|
65
|
+
* reload always grants a fresh budget.
|
|
66
|
+
*/
|
|
67
|
+
maxLoadAttempts = 3;
|
|
68
|
+
/**
|
|
69
|
+
* Number of resolution attempts that have failed with a definitive
|
|
70
|
+
* "asset not found" so far for the current page load. Only updates
|
|
71
|
+
* for {@link AssetNotFoundError} rejections; transient failures do
|
|
72
|
+
* not increment this counter. Not serialized into the Yjs document.
|
|
73
|
+
*/
|
|
74
|
+
loadAttempts = 0;
|
|
75
|
+
/**
|
|
76
|
+
* Maximum wall-clock duration (in milliseconds) the image will keep
|
|
77
|
+
* retrying transient resolution failures before giving up and
|
|
78
|
+
* surfacing the error placeholder. Defaults to 30 seconds.
|
|
79
|
+
*
|
|
80
|
+
* This bound exists so that a permanently-broken backend eventually
|
|
81
|
+
* surfaces UX feedback even when failures look "transient" (and
|
|
82
|
+
* therefore do not consume {@link maxLoadAttempts}).
|
|
83
|
+
*/
|
|
84
|
+
maxTransientRetryDurationMs = 30_000;
|
|
85
|
+
/**
|
|
86
|
+
* Wall-clock timestamp (ms since epoch) of the first transient
|
|
87
|
+
* failure in the current retry chain. `null` when no transient
|
|
88
|
+
* retries are in flight. Reset on success and on definitive miss.
|
|
89
|
+
* Not serialized into the Yjs document.
|
|
90
|
+
*/
|
|
91
|
+
transientRetryStartedAt = null;
|
|
92
|
+
/**
|
|
93
|
+
* Creates a new KritzelImage instance.
|
|
94
|
+
* @param config - Optional configuration object to initialize image properties
|
|
95
|
+
* including assetId, src, position (x, y), translation, and scale.
|
|
96
|
+
*/
|
|
97
|
+
constructor(config) {
|
|
98
|
+
super();
|
|
99
|
+
this.assetId = config?.assetId || '';
|
|
100
|
+
this.mimeType = config?.mimeType || '';
|
|
101
|
+
this.src = config?.src || '';
|
|
102
|
+
this.x = config?.x || 0;
|
|
103
|
+
this.y = config?.y || 0;
|
|
104
|
+
this.translateX = config?.translateX || 0;
|
|
105
|
+
this.translateY = config?.translateY || 0;
|
|
106
|
+
this.rotation = KritzelMathHelper.degreesToRadians(config?.rotation ?? 0);
|
|
107
|
+
this.scale = config?.scale || 1;
|
|
108
|
+
this.width = config?.width || 0;
|
|
109
|
+
this.height = config?.height || 0;
|
|
110
|
+
this.maxWidth = config?.maxWidth ?? 300;
|
|
111
|
+
this.maxHeight = config?.maxHeight ?? 300;
|
|
112
|
+
this.maxLoadAttempts = config?.maxLoadAttempts ?? 3;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Factory method to create a new KritzelImage instance with core integration.
|
|
116
|
+
* Initializes the image with default values and links it to the core store.
|
|
117
|
+
* @param core - The KritzelCore instance providing access to store and state management.
|
|
118
|
+
* @returns A new KritzelImage instance configured with the core context.
|
|
119
|
+
*/
|
|
120
|
+
static create(core, config) {
|
|
121
|
+
const object = new KritzelImage(config);
|
|
122
|
+
object._core = core;
|
|
123
|
+
object.id = object.generateId();
|
|
124
|
+
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
125
|
+
object.userId = core.user?.id;
|
|
126
|
+
object.x = config?.x ?? 0;
|
|
127
|
+
object.y = config?.y ?? 0;
|
|
128
|
+
object.translateX = config?.translateX ?? 0;
|
|
129
|
+
object.translateY = config?.translateY ?? 0;
|
|
130
|
+
object.scale = config?.scale ?? object._core.store.state.scale;
|
|
131
|
+
object.rotation = KritzelMathHelper.degreesToRadians(config?.rotation ?? 0);
|
|
132
|
+
object.zIndex = core.store.currentZIndex;
|
|
133
|
+
return object;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Resizes the image while maintaining aspect ratio based on the new height.
|
|
137
|
+
* Updates the image's position and dimensions, then syncs changes to y.js
|
|
138
|
+
* for collaborative editing support.
|
|
139
|
+
* @param x - The new x translation coordinate.
|
|
140
|
+
* @param y - The new y translation coordinate.
|
|
141
|
+
* @param width - The new width (used for validation, not directly applied).
|
|
142
|
+
* @param height - The new height used to calculate the scale factor.
|
|
143
|
+
*/
|
|
144
|
+
resize(x, y, width, height) {
|
|
145
|
+
if (width <= 1 || height <= 1) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const scaleFactor = height / this.height;
|
|
149
|
+
this.width = this.width * scaleFactor;
|
|
150
|
+
this.height = this.height * scaleFactor;
|
|
151
|
+
this.translateX = x;
|
|
152
|
+
this.translateY = y;
|
|
153
|
+
// Update to sync changes to y.js and propagate to other tabs
|
|
154
|
+
this._core.store.objects.update(this);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Serializes the image, excluding transient rendering state so the
|
|
158
|
+
* Yjs document never persists blob URLs or load lifecycle flags.
|
|
159
|
+
*/
|
|
160
|
+
serialize() {
|
|
161
|
+
const plain = super.serialize();
|
|
162
|
+
// Strip transient, non-persistent rendering state.
|
|
163
|
+
delete plain.resolvedSrc;
|
|
164
|
+
delete plain.loadState;
|
|
165
|
+
delete plain.loadAttempts;
|
|
166
|
+
delete plain.transientRetryStartedAt;
|
|
167
|
+
return plain;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Carries transient asset-loading state (resolved URL, load lifecycle,
|
|
171
|
+
* retry counters) over from the previous local instance when a remote
|
|
172
|
+
* Yjs update produces a freshly-revived replacement. Without this,
|
|
173
|
+
* frequent remote updates (e.g. another user dragging the image)
|
|
174
|
+
* would reset `loadState` to `'idle'` on every tick and cause the
|
|
175
|
+
* skeleton to flicker between renders.
|
|
176
|
+
*/
|
|
177
|
+
adoptTransientStateFrom(previous) {
|
|
178
|
+
if (!(previous instanceof KritzelImage))
|
|
179
|
+
return;
|
|
180
|
+
// Only carry over the resolved URL when the asset reference itself
|
|
181
|
+
// hasn't changed; otherwise the new asset must be re-resolved.
|
|
182
|
+
if (previous.assetId === this.assetId) {
|
|
183
|
+
this.resolvedSrc = previous.resolvedSrc;
|
|
184
|
+
this.loadState = previous.loadState;
|
|
185
|
+
this.loadAttempts = previous.loadAttempts;
|
|
186
|
+
this.transientRetryStartedAt = previous.transientRetryStartedAt;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Triggers (idempotent) resolution of the referenced asset. Updates
|
|
191
|
+
* `resolvedSrc` and `loadState` as the resolution progresses and
|
|
192
|
+
* schedules a re-render when the URL is available.
|
|
193
|
+
*
|
|
194
|
+
* Failure handling distinguishes two cases:
|
|
195
|
+
* - Definitive miss ({@link AssetNotFoundError}): consumes one slot
|
|
196
|
+
* of the {@link maxLoadAttempts} budget. Once exhausted, the
|
|
197
|
+
* image is marked permanently `'error'` for the remainder of the
|
|
198
|
+
* page load to avoid hammering an unavailable backend; a full
|
|
199
|
+
* reload (which constructs a fresh instance) grants a new budget.
|
|
200
|
+
* - Transient failure (network blip, resolver init in flight, ...):
|
|
201
|
+
* does NOT consume the attempt budget. Retries continue with the
|
|
202
|
+
* same exponential backoff up to
|
|
203
|
+
* {@link maxTransientRetryDurationMs} of wall-clock time, after
|
|
204
|
+
* which the image is marked `'error'`.
|
|
205
|
+
*/
|
|
206
|
+
ensureResolved() {
|
|
207
|
+
if (this.loadState === 'loading' || this.loadState === 'ready')
|
|
208
|
+
return;
|
|
209
|
+
if (this.loadState === 'error')
|
|
210
|
+
return;
|
|
211
|
+
if (!this.assetId)
|
|
212
|
+
return;
|
|
213
|
+
if (!this._core?.assetResolver)
|
|
214
|
+
return;
|
|
215
|
+
if (this.loadAttempts >= this.maxLoadAttempts) {
|
|
216
|
+
this.loadState = 'error';
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
this.loadState = 'loading';
|
|
220
|
+
const attemptIndex = this.loadAttempts; // backoff base only; bumped on real misses
|
|
221
|
+
this._core.assetResolver
|
|
222
|
+
.resolve(this.assetId)
|
|
223
|
+
.then(url => {
|
|
224
|
+
this.resolvedSrc = url;
|
|
225
|
+
this.loadState = 'ready';
|
|
226
|
+
// Reset transient retry tracking on success.
|
|
227
|
+
this.transientRetryStartedAt = null;
|
|
228
|
+
this._core?.rerender();
|
|
229
|
+
})
|
|
230
|
+
.catch(err => {
|
|
231
|
+
const isDefinitiveMiss = err instanceof AssetNotFoundError;
|
|
232
|
+
if (isDefinitiveMiss) {
|
|
233
|
+
this.loadAttempts += 1;
|
|
234
|
+
// Definitive miss resets the transient deadline so a later
|
|
235
|
+
// transient retry chain (post-recovery) starts fresh.
|
|
236
|
+
this.transientRetryStartedAt = null;
|
|
237
|
+
const attemptsExhausted = this.loadAttempts >= this.maxLoadAttempts;
|
|
238
|
+
console.warn(`[KritzelImage] Asset ${this.assetId} not found ` +
|
|
239
|
+
`(attempt ${this.loadAttempts}/${this.maxLoadAttempts}):`, err);
|
|
240
|
+
if (attemptsExhausted) {
|
|
241
|
+
this.loadState = 'error';
|
|
242
|
+
this._core?.rerender();
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.scheduleRetry(this.loadAttempts);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Transient failure: do not burn the per-page-load budget, but
|
|
249
|
+
// bound retries by a wall-clock deadline so a permanently broken
|
|
250
|
+
// backend still surfaces feedback eventually.
|
|
251
|
+
const now = Date.now();
|
|
252
|
+
if (this.transientRetryStartedAt === null) {
|
|
253
|
+
this.transientRetryStartedAt = now;
|
|
254
|
+
}
|
|
255
|
+
const elapsed = now - this.transientRetryStartedAt;
|
|
256
|
+
const deadlineExceeded = elapsed >= this.maxTransientRetryDurationMs;
|
|
257
|
+
console.warn(`[KritzelImage] Transient resolve failure for asset ${this.assetId} ` +
|
|
258
|
+
`(elapsed ${Math.round(elapsed / 1000)}s/${Math.round(this.maxTransientRetryDurationMs / 1000)}s):`, err);
|
|
259
|
+
if (deadlineExceeded) {
|
|
260
|
+
this.loadState = 'error';
|
|
261
|
+
this._core?.rerender();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// Use the existing attempt count as the backoff base. Transient
|
|
265
|
+
// retries do not increment loadAttempts, so the backoff remains
|
|
266
|
+
// bounded at the first step (250ms) until a real miss happens.
|
|
267
|
+
this.scheduleRetry(attemptIndex + 1);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Schedules a retry of {@link ensureResolved} with a small exponential
|
|
272
|
+
* backoff. The backoff base is the current attempt index so successive
|
|
273
|
+
* definitive misses ramp up gradually.
|
|
274
|
+
*/
|
|
275
|
+
scheduleRetry(attemptBase) {
|
|
276
|
+
// Reset to 'idle' so the next call (or scheduled tick) is allowed to
|
|
277
|
+
// proceed past the early-return guard in ensureResolved().
|
|
278
|
+
this.loadState = 'idle';
|
|
279
|
+
const backoffMs = Math.min(2000, 250 * Math.pow(2, Math.max(0, attemptBase - 1)));
|
|
280
|
+
setTimeout(() => {
|
|
281
|
+
if (this.loadState === 'idle') {
|
|
282
|
+
this.ensureResolved();
|
|
283
|
+
}
|
|
284
|
+
}, backoffMs);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* One-shot migration for legacy images that were persisted with an
|
|
288
|
+
* inline `src` data URL. Uploads the bytes to the asset resolver and
|
|
289
|
+
* swaps the image to use the resulting `assetId`, clearing `src` so
|
|
290
|
+
* the Yjs document no longer carries the raw payload.
|
|
291
|
+
*/
|
|
292
|
+
migrateLegacyDataUrlIfNeeded() {
|
|
293
|
+
if (this.assetId)
|
|
294
|
+
return;
|
|
295
|
+
if (!this.src || !this.src.startsWith('data:'))
|
|
296
|
+
return;
|
|
297
|
+
if (!this._core?.assetResolver)
|
|
298
|
+
return;
|
|
299
|
+
const legacySrc = this.src;
|
|
300
|
+
// Render the legacy data URL directly until migration completes.
|
|
301
|
+
this.resolvedSrc = legacySrc;
|
|
302
|
+
this.loadState = 'ready';
|
|
303
|
+
this._core.assetResolver
|
|
304
|
+
.putDataUrl(legacySrc, { kind: 'image' })
|
|
305
|
+
.then(asset => {
|
|
306
|
+
this.assetId = asset.id;
|
|
307
|
+
this.mimeType = asset.mimeType;
|
|
308
|
+
this.src = '';
|
|
309
|
+
// Persist the migrated reference back into Yjs.
|
|
310
|
+
this._core?.store.objects?.update(this);
|
|
311
|
+
})
|
|
312
|
+
.catch(err => {
|
|
313
|
+
console.warn('[KritzelImage] Failed to migrate legacy data URL to asset storage:', err);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Kicks off asset resolution (or legacy data-URL migration) without
|
|
318
|
+
* requiring the `<img>` element to be mounted. Safe to call multiple
|
|
319
|
+
* times; both underlying paths are idempotent.
|
|
320
|
+
*
|
|
321
|
+
* Useful for the renderer's loading-skeleton path, where the actual
|
|
322
|
+
* `<img>` is not in the DOM yet but the asset bytes still need to
|
|
323
|
+
* start loading.
|
|
324
|
+
*/
|
|
325
|
+
ensureLoaded() {
|
|
326
|
+
if (this.assetId && !this.resolvedSrc) {
|
|
327
|
+
this.ensureResolved();
|
|
328
|
+
}
|
|
329
|
+
else if (!this.assetId && this.src?.startsWith('data:')) {
|
|
330
|
+
this.migrateLegacyDataUrlIfNeeded();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Prepares image objects for insertion into the canvas while preserving
|
|
335
|
+
* the standard object-first flow (`new KritzelImage(...); addObject(image)`).
|
|
336
|
+
*
|
|
337
|
+
* Behavior:
|
|
338
|
+
* - If `assetId` is already set, no-op.
|
|
339
|
+
* - If `src` is set (URL or data URL), uploads bytes through the asset
|
|
340
|
+
* resolver, fills `assetId`/`mimeType`, computes dimensions when needed,
|
|
341
|
+
* and seeds `resolvedSrc` for immediate rendering.
|
|
342
|
+
*/
|
|
343
|
+
async prepareForInsert() {
|
|
344
|
+
if (this.assetId || !this.src) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (!this._core?.assetResolver) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const source = this.src;
|
|
351
|
+
const response = await fetch(source);
|
|
352
|
+
if (!response.ok) {
|
|
353
|
+
throw new Error(`Failed to load image source: ${source} (HTTP ${response.status})`);
|
|
354
|
+
}
|
|
355
|
+
const blob = await response.blob();
|
|
356
|
+
const mimeType = blob.type || 'image/png';
|
|
357
|
+
const { naturalWidth, naturalHeight } = await this.measureImageBlob(blob);
|
|
358
|
+
const asset = await this._core.assetResolver.put(blob, {
|
|
359
|
+
mimeType,
|
|
360
|
+
kind: 'image',
|
|
361
|
+
width: naturalWidth,
|
|
362
|
+
height: naturalHeight,
|
|
363
|
+
});
|
|
364
|
+
this.assetId = asset.id;
|
|
365
|
+
this.mimeType = asset.mimeType;
|
|
366
|
+
if (this.width <= 0 || this.height <= 0) {
|
|
367
|
+
const { scaledWidth, scaledHeight } = this.calculateScaledDimensions({
|
|
368
|
+
width: naturalWidth,
|
|
369
|
+
height: naturalHeight,
|
|
370
|
+
});
|
|
371
|
+
this.width = scaledWidth;
|
|
372
|
+
this.height = scaledHeight;
|
|
373
|
+
}
|
|
374
|
+
this.resolvedSrc = await this._core.assetResolver.resolve(asset.id);
|
|
375
|
+
this.loadState = 'ready';
|
|
376
|
+
this.src = '';
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Measures intrinsic image dimensions from a Blob.
|
|
380
|
+
*/
|
|
381
|
+
async measureImageBlob(blob) {
|
|
382
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
383
|
+
try {
|
|
384
|
+
return await new Promise((resolve, reject) => {
|
|
385
|
+
const img = new Image();
|
|
386
|
+
img.onload = () => resolve({ naturalWidth: img.naturalWidth, naturalHeight: img.naturalHeight });
|
|
387
|
+
img.onerror = err => reject(err);
|
|
388
|
+
img.src = objectUrl;
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
finally {
|
|
392
|
+
URL.revokeObjectURL(objectUrl);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Overrides base mount to kick off asset resolution the first time
|
|
397
|
+
* the image is attached to the DOM. Legacy images persisted with an
|
|
398
|
+
* inline `src` data URL are opportunistically migrated to the asset
|
|
399
|
+
* storage layer on first mount.
|
|
400
|
+
*/
|
|
401
|
+
mount(element) {
|
|
402
|
+
super.mount(element);
|
|
403
|
+
this.ensureLoaded();
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Creates a KritzelImage from a URL, handling image loading and dimension calculation.
|
|
407
|
+
* Loads the image, calculates scaled dimensions respecting maxWidth/maxHeight constraints,
|
|
408
|
+
* and returns a fully configured KritzelImage instance.
|
|
409
|
+
*
|
|
410
|
+
* Intended for legacy / data-URL code paths only. New callers should
|
|
411
|
+
* upload through the asset resolver and construct the image from the
|
|
412
|
+
* resulting asset descriptor.
|
|
413
|
+
* @param src - The image URL or data URI to load.
|
|
414
|
+
* @param config - Optional partial configuration to pass to the KritzelImage constructor.
|
|
415
|
+
* @returns A promise resolving to a fully configured KritzelImage with correct dimensions.
|
|
416
|
+
*/
|
|
417
|
+
static fromUrl(src, config) {
|
|
418
|
+
return new Promise((resolve, reject) => {
|
|
419
|
+
const img = new Image();
|
|
420
|
+
img.onload = () => {
|
|
421
|
+
const image = new KritzelImage({ ...config, src });
|
|
422
|
+
const { scaledWidth, scaledHeight } = image.calculateScaledDimensions(img);
|
|
423
|
+
image.width = scaledWidth;
|
|
424
|
+
image.height = scaledHeight;
|
|
425
|
+
resolve(image);
|
|
426
|
+
};
|
|
427
|
+
img.onerror = (err) => reject(err);
|
|
428
|
+
img.src = src;
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Creates a fully initialized KritzelImage from a Blob.
|
|
433
|
+
* Uploads the blob via the asset resolver and sets up dimensions/asset references.
|
|
434
|
+
*
|
|
435
|
+
* @param core - The KritzelCore instance providing the asset resolver and state.
|
|
436
|
+
* @param blob - The image Blob (e.g. from clipboard or file picker).
|
|
437
|
+
* @param config - Optional configuration to merge into the new image.
|
|
438
|
+
* @returns A promise resolving to a fully loaded KritzelImage object.
|
|
439
|
+
*/
|
|
440
|
+
static async fromBlob(core, blob, config) {
|
|
441
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
442
|
+
try {
|
|
443
|
+
const dimensions = await new Promise((resolve, reject) => {
|
|
444
|
+
const img = new Image();
|
|
445
|
+
img.onload = () => resolve({ naturalWidth: img.naturalWidth, naturalHeight: img.naturalHeight });
|
|
446
|
+
img.onerror = err => reject(err);
|
|
447
|
+
img.src = objectUrl;
|
|
448
|
+
});
|
|
449
|
+
const mimeType = blob.type || 'image/png';
|
|
450
|
+
const asset = await core.assetResolver.put(blob, {
|
|
451
|
+
mimeType,
|
|
452
|
+
kind: 'image',
|
|
453
|
+
width: dimensions.naturalWidth,
|
|
454
|
+
height: dimensions.naturalHeight,
|
|
455
|
+
});
|
|
456
|
+
const image = KritzelImage.create(core, config);
|
|
457
|
+
image.assetId = asset.id;
|
|
458
|
+
image.mimeType = asset.mimeType;
|
|
459
|
+
const { scaledWidth, scaledHeight } = image.calculateScaledDimensions({
|
|
460
|
+
width: dimensions.naturalWidth,
|
|
461
|
+
height: dimensions.naturalHeight,
|
|
462
|
+
});
|
|
463
|
+
image.width = scaledWidth;
|
|
464
|
+
image.height = scaledHeight;
|
|
465
|
+
image.resolvedSrc = await core.assetResolver.resolve(asset.id);
|
|
466
|
+
image.loadState = 'ready';
|
|
467
|
+
return image;
|
|
468
|
+
}
|
|
469
|
+
finally {
|
|
470
|
+
URL.revokeObjectURL(objectUrl);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Calculates scaled dimensions for an image while respecting maxWidth and maxHeight constraints.
|
|
475
|
+
* Maintains the original aspect ratio by using the smaller of the two scale ratios.
|
|
476
|
+
* @param img - The HTMLImageElement to calculate dimensions for.
|
|
477
|
+
* @returns An object containing the scaled width and height values.
|
|
478
|
+
*/
|
|
479
|
+
calculateScaledDimensions(img) {
|
|
480
|
+
let scaledWidth = img.width;
|
|
481
|
+
let scaledHeight = img.height;
|
|
482
|
+
if (img.width > this.maxWidth || img.height > this.maxHeight) {
|
|
483
|
+
const widthRatio = this.maxWidth / img.width;
|
|
484
|
+
const heightRatio = this.maxHeight / img.height;
|
|
485
|
+
const scaleRatio = Math.min(widthRatio, heightRatio);
|
|
486
|
+
scaledWidth = img.width * scaleRatio;
|
|
487
|
+
scaledHeight = img.height * scaleRatio;
|
|
488
|
+
}
|
|
489
|
+
return { scaledWidth, scaledHeight };
|
|
490
|
+
}
|
|
491
|
+
getSupportedExportFormats() {
|
|
492
|
+
return ['png'];
|
|
493
|
+
}
|
|
494
|
+
async exportAs(format, context) {
|
|
495
|
+
if (format !== 'png') {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
return context.getObjectAsPngDataUrl(this);
|
|
499
|
+
}
|
|
500
|
+
}
|