@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,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages browser permission checks and prompts for a core instance.
|
|
3
|
+
*
|
|
4
|
+
* Permission-specific prompt logic is routed through a handler registry so new
|
|
5
|
+
* permissions can be added without changing the core control flow.
|
|
6
|
+
*/
|
|
7
|
+
export class KritzelBrowserPermissionManager {
|
|
8
|
+
_isFirefox = /firefox|fxios/i.test(navigator.userAgent);
|
|
9
|
+
_isSafari = /safari/i.test(navigator.userAgent) && !/chrome|chromium|crios|android|edg/i.test(navigator.userAgent);
|
|
10
|
+
_requestHandlers = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new KritzelBrowserPermissionManager instance.
|
|
13
|
+
* @param core - The KritzelCore instance this manager belongs to
|
|
14
|
+
*/
|
|
15
|
+
constructor(_core) {
|
|
16
|
+
this.registerRequestPermissionHandler('clipboard-read', async () => {
|
|
17
|
+
// Firefox and Safari open native paste menus when the clipboard is read
|
|
18
|
+
// proactively, so rely on the permission state instead of an eager read.
|
|
19
|
+
if (this._isFirefox || this._isSafari) {
|
|
20
|
+
return 'granted';
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const status = await navigator.permissions.query({ name: 'clipboard-read' });
|
|
24
|
+
return status.state === 'denied' ? 'denied' : 'granted';
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return 'granted';
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Registers a custom request handler for a browser permission name.
|
|
33
|
+
* Existing handlers are replaced, which makes the registry easy to extend.
|
|
34
|
+
*
|
|
35
|
+
* @param permissionName - The browser permission name to handle
|
|
36
|
+
* @param handler - The request implementation for that permission
|
|
37
|
+
*/
|
|
38
|
+
registerRequestPermissionHandler(permissionName, handler) {
|
|
39
|
+
this._requestHandlers.set(permissionName, handler);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Checks the current state for a browser permission via the Permissions API.
|
|
43
|
+
*
|
|
44
|
+
* @param permissionName - The browser permission name to inspect
|
|
45
|
+
*/
|
|
46
|
+
async checkPermission(permissionName) {
|
|
47
|
+
const status = await navigator.permissions.query({ name: permissionName });
|
|
48
|
+
return status.state;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Requests a browser permission using the registered handler for the given
|
|
52
|
+
* permission name, then falls back to a permission check when no handler is
|
|
53
|
+
* registered.
|
|
54
|
+
*
|
|
55
|
+
* @param permissionName - The browser permission name to request
|
|
56
|
+
*/
|
|
57
|
+
async requestPermission(permissionName) {
|
|
58
|
+
const handler = this._requestHandlers.get(permissionName);
|
|
59
|
+
if (handler) {
|
|
60
|
+
return handler();
|
|
61
|
+
}
|
|
62
|
+
return this.checkPermission(permissionName);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { KritzelImage } from "../objects/image.class";
|
|
2
|
+
import { KritzelText } from "../objects/text.class";
|
|
3
|
+
import { KritzelSelectionGroup } from "../objects/selection-group.class";
|
|
4
|
+
import { KritzelClassHelper } from "../../helpers/class.helper";
|
|
5
|
+
import { KritzelReviver } from "../core/reviver.class";
|
|
6
|
+
import { KritzelPasteIntentProviderRegistry } from "../registries/paste-intent-provider.registry";
|
|
7
|
+
import { KritzelEventPasteIntentProvider } from "../providers/paste-intent/event-paste-intent.provider";
|
|
8
|
+
import { KritzelNavigatorPasteIntentProvider } from "../providers/paste-intent/navigator-paste-intent.provider";
|
|
9
|
+
import { KritzelIosPasteIntentProvider } from "../providers/paste-intent/ios-paste-intent.provider";
|
|
10
|
+
import { CLIPBOARD_PAYLOAD_PREFIX } from "./clipboard.types";
|
|
11
|
+
import imageCompression from "browser-image-compression";
|
|
12
|
+
import { KritzelImageFileHelper } from "../../helpers/image-file.helper";
|
|
13
|
+
/**
|
|
14
|
+
* Manages clipboard operations (copy/cut/paste) for a core instance.
|
|
15
|
+
*
|
|
16
|
+
* The system clipboard is the preferred source of truth: copy serializes the current
|
|
17
|
+
* selection into a Kritzel payload, paste reads + revives it.
|
|
18
|
+
*
|
|
19
|
+
* A copy also mirrors the payload into an in-memory session buffer. On platforms where
|
|
20
|
+
* eventless programmatic clipboard access is unavailable (notably iOS Safari, where the
|
|
21
|
+
* context menu triggers copy/paste without a native ClipboardEvent), the session buffer
|
|
22
|
+
* is used as the fallback source so internal object copy/paste keeps working.
|
|
23
|
+
*/
|
|
24
|
+
export class KritzelClipboardManager {
|
|
25
|
+
_core;
|
|
26
|
+
_pasteIntentRegistry;
|
|
27
|
+
/**
|
|
28
|
+
* In-memory mirror of the most recent copy payload. Acts as the fallback clipboard
|
|
29
|
+
* source when the system clipboard cannot be read programmatically (e.g. iOS Safari
|
|
30
|
+
* context-menu paste). Reset is not required; a new copy overwrites it.
|
|
31
|
+
*/
|
|
32
|
+
_sessionClipboardPayload = null;
|
|
33
|
+
/**
|
|
34
|
+
* In-memory cascade offset (world units) applied to successive pastes of the same
|
|
35
|
+
* clipboard content so they don't stack exactly on top of each other. Reset on copy/cut.
|
|
36
|
+
*/
|
|
37
|
+
_pasteOffset = 0;
|
|
38
|
+
constructor(core) {
|
|
39
|
+
this._core = core;
|
|
40
|
+
this._pasteIntentRegistry = new KritzelPasteIntentProviderRegistry(this._core);
|
|
41
|
+
// Provider order is intentional: iOS eventless path should short-circuit,
|
|
42
|
+
// native paste events remain preferred, and async navigator APIs are fallback.
|
|
43
|
+
this._pasteIntentRegistry.register(new KritzelIosPasteIntentProvider());
|
|
44
|
+
this._pasteIntentRegistry.register(new KritzelEventPasteIntentProvider());
|
|
45
|
+
this._pasteIntentRegistry.register(new KritzelNavigatorPasteIntentProvider());
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The most recent copy payload mirrored in memory, used as a fallback clipboard
|
|
49
|
+
* source when the system clipboard cannot be read programmatically.
|
|
50
|
+
*/
|
|
51
|
+
get sessionClipboardPayload() {
|
|
52
|
+
return this._sessionClipboardPayload;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Serializes an object for the clipboard payload. Groups additionally embed their
|
|
56
|
+
* (recursively serialized) children under `__children__` so the payload is self-contained.
|
|
57
|
+
*/
|
|
58
|
+
serializeForClipboard(object) {
|
|
59
|
+
const serialized = (typeof object.serialize === 'function' ? object.serialize() : object);
|
|
60
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
61
|
+
serialized.__children__ = object.children.map(child => this.serializeForClipboard(child));
|
|
62
|
+
}
|
|
63
|
+
return serialized;
|
|
64
|
+
}
|
|
65
|
+
serializeClipboardPayload(payload) {
|
|
66
|
+
return `${CLIPBOARD_PAYLOAD_PREFIX}${JSON.stringify(payload)}`;
|
|
67
|
+
}
|
|
68
|
+
async writeBrowserClipboardPayload(payload, event) {
|
|
69
|
+
const serialized = this.serializeClipboardPayload(payload);
|
|
70
|
+
if (event?.clipboardData) {
|
|
71
|
+
event.clipboardData.setData('text/plain', serialized);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (typeof navigator === 'undefined' || !navigator.clipboard?.writeText) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
await navigator.clipboard.writeText(serialized);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Ignore clipboard permission failures and keep the local clipboard working.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Revives a single serialized clipboard object (and its embedded group children).
|
|
86
|
+
* IDs are NOT regenerated here; see regenerateIdsAndRemapAnchors.
|
|
87
|
+
*/
|
|
88
|
+
reviveClipboardObject(serialized) {
|
|
89
|
+
const reviver = new KritzelReviver(this._core);
|
|
90
|
+
const { __children__, ...objectData } = serialized;
|
|
91
|
+
const revived = reviver.revive(objectData);
|
|
92
|
+
if (!revived) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (__children__ && KritzelClassHelper.isInstanceOf(revived, 'KritzelGroup')) {
|
|
96
|
+
const children = __children__.map(child => this.reviveClipboardObject(child)).filter((child) => child != null);
|
|
97
|
+
revived._pendingChildren = children;
|
|
98
|
+
revived.childIds = children.map(child => child.id);
|
|
99
|
+
}
|
|
100
|
+
return revived;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Assigns fresh unique IDs to every revived object (including nested group children),
|
|
104
|
+
* keeping group.childIds in sync and remapping line anchors that reference copied
|
|
105
|
+
* siblings to their new IDs. Anchors pointing at objects outside the pasted set are
|
|
106
|
+
* left untouched so they stay connected to the existing object.
|
|
107
|
+
*/
|
|
108
|
+
regenerateIdsAndRemapAnchors(topLevel) {
|
|
109
|
+
const all = [];
|
|
110
|
+
const hasOnlyTopLevelLines = topLevel.length > 0 && topLevel.every(object => KritzelClassHelper.isInstanceOf(object, 'KritzelLine'));
|
|
111
|
+
const collect = (objects) => {
|
|
112
|
+
for (const object of objects) {
|
|
113
|
+
all.push(object);
|
|
114
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
115
|
+
collect(object._pendingChildren);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
collect(topLevel);
|
|
120
|
+
const idMap = new Map();
|
|
121
|
+
for (const object of all) {
|
|
122
|
+
const newId = object.generateId();
|
|
123
|
+
idMap.set(object.id, newId);
|
|
124
|
+
object.id = newId;
|
|
125
|
+
object.isMounted = false;
|
|
126
|
+
}
|
|
127
|
+
for (const object of all) {
|
|
128
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
129
|
+
object.childIds = object.childIds.map(id => idMap.get(id) ?? id);
|
|
130
|
+
}
|
|
131
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelLine')) {
|
|
132
|
+
if (object.startAnchor && idMap.has(object.startAnchor.objectId)) {
|
|
133
|
+
object.startAnchor = { objectId: idMap.get(object.startAnchor.objectId) };
|
|
134
|
+
}
|
|
135
|
+
else if (hasOnlyTopLevelLines) {
|
|
136
|
+
object.startAnchor = undefined;
|
|
137
|
+
}
|
|
138
|
+
if (object.endAnchor && idMap.has(object.endAnchor.objectId)) {
|
|
139
|
+
object.endAnchor = { objectId: idMap.get(object.endAnchor.objectId) };
|
|
140
|
+
}
|
|
141
|
+
else if (hasOnlyTopLevelLines) {
|
|
142
|
+
object.endAnchor = undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Copies currently selected objects into internal clipboard state.
|
|
149
|
+
*/
|
|
150
|
+
copy(event) {
|
|
151
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
152
|
+
if (!selectionGroup) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const payload = {
|
|
156
|
+
version: 1,
|
|
157
|
+
sourceWorkspaceId: this._core.store.state.activeWorkspace?.id,
|
|
158
|
+
objects: selectionGroup.objects.sort((a, b) => a.zIndex - b.zIndex).map(obj => this.serializeForClipboard(obj)),
|
|
159
|
+
};
|
|
160
|
+
// A fresh copy resets the cascade so the first paste lands at the default offset.
|
|
161
|
+
this._pasteOffset = 0;
|
|
162
|
+
// Mirror the payload in memory so eventless paste still works where the system
|
|
163
|
+
// clipboard is not programmatically accessible (e.g. iOS Safari context menu).
|
|
164
|
+
this._sessionClipboardPayload = payload;
|
|
165
|
+
void this.writeBrowserClipboardPayload(payload, event);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Cuts currently selected objects (copy then delete).
|
|
169
|
+
*/
|
|
170
|
+
cut(event) {
|
|
171
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
172
|
+
if (!selectionGroup) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.copy(event);
|
|
176
|
+
this._core.delete();
|
|
177
|
+
}
|
|
178
|
+
materializeKritzelObjects(intent) {
|
|
179
|
+
const objects = intent.payload.objects.map(object => this.reviveClipboardObject(object)).filter((object) => object != null);
|
|
180
|
+
this.regenerateIdsAndRemapAnchors(objects);
|
|
181
|
+
return objects;
|
|
182
|
+
}
|
|
183
|
+
async materializeImageFiles(intent) {
|
|
184
|
+
try {
|
|
185
|
+
const scale = this._core.store.state.scale;
|
|
186
|
+
const offset = 25 / scale;
|
|
187
|
+
const preparePromises = intent.files.map(async (file, index) => {
|
|
188
|
+
const preparedFile = await this.prepareImageFile(file);
|
|
189
|
+
return KritzelImage.fromBlob(this._core, preparedFile, {
|
|
190
|
+
translateX: index * offset,
|
|
191
|
+
translateY: index * offset,
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
return await Promise.all(preparePromises);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
console.error('Failed to import pasted image files:', err);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async prepareImageFile(file) {
|
|
202
|
+
if (KritzelImageFileHelper.isGifFile(file)) {
|
|
203
|
+
return file;
|
|
204
|
+
}
|
|
205
|
+
return imageCompression(file, { maxWidthOrHeight: 1200 });
|
|
206
|
+
}
|
|
207
|
+
async materializePlainText(intent) {
|
|
208
|
+
const textObject = KritzelText.create(this._core);
|
|
209
|
+
const paragraphs = intent.text.split('\n').map(line => {
|
|
210
|
+
if (line.length === 0) {
|
|
211
|
+
return { type: 'paragraph' }; // Empty paragraph
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
type: 'paragraph',
|
|
215
|
+
content: [{ type: 'text', text: line }],
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
textObject.setContent({
|
|
219
|
+
type: 'doc',
|
|
220
|
+
content: paragraphs,
|
|
221
|
+
});
|
|
222
|
+
return [textObject];
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Pastes objects from clipboard with optional explicit world coordinates.
|
|
226
|
+
*/
|
|
227
|
+
async paste(x, y, event) {
|
|
228
|
+
const pasteIntent = await this._pasteIntentRegistry.resolve(event);
|
|
229
|
+
let objects = null;
|
|
230
|
+
if (pasteIntent.type === 'kritzel_objects') {
|
|
231
|
+
objects = this.materializeKritzelObjects(pasteIntent);
|
|
232
|
+
}
|
|
233
|
+
else if (pasteIntent.type === 'image_files') {
|
|
234
|
+
objects = await this.materializeImageFiles(pasteIntent);
|
|
235
|
+
}
|
|
236
|
+
else if (pasteIntent.type === 'plain_text') {
|
|
237
|
+
objects = await this.materializePlainText(pasteIntent);
|
|
238
|
+
}
|
|
239
|
+
if (!objects || objects.length === 0) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
await this.insertMaterializedObjects(objects, pasteIntent, x, y);
|
|
243
|
+
}
|
|
244
|
+
async insertMaterializedObjects(copiedObjects, pasteIntent, x, y) {
|
|
245
|
+
const activeWorkspace = this._core.store.state.activeWorkspace;
|
|
246
|
+
if (!activeWorkspace) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Determine if we should center the objects in the viewport.
|
|
250
|
+
// This happens if the user specifically pasted from a different workspace,
|
|
251
|
+
// OR if we're inserting brand new external items (like images or text).
|
|
252
|
+
const isDifferentWorkspace = copiedObjects.some(obj => obj.workspaceId !== activeWorkspace.id);
|
|
253
|
+
const isNewExternalContent = pasteIntent.type !== 'kritzel_objects';
|
|
254
|
+
const shouldCenterInViewport = isDifferentWorkspace || isNewExternalContent;
|
|
255
|
+
const hasExplicitPastePosition = x !== undefined && y !== undefined;
|
|
256
|
+
const minX = Math.min(...copiedObjects.map(obj => obj.translateX));
|
|
257
|
+
const minY = Math.min(...copiedObjects.map(obj => obj.translateY));
|
|
258
|
+
let pasteX;
|
|
259
|
+
let pasteY;
|
|
260
|
+
const step = 25 / this._core.store.state.scale;
|
|
261
|
+
if (x !== undefined && y !== undefined) {
|
|
262
|
+
pasteX = x;
|
|
263
|
+
pasteY = y;
|
|
264
|
+
}
|
|
265
|
+
else if (shouldCenterInViewport) {
|
|
266
|
+
pasteX = minX;
|
|
267
|
+
pasteY = minY;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
pasteX = minX + step + this._pasteOffset;
|
|
271
|
+
pasteY = minY + step + this._pasteOffset;
|
|
272
|
+
// Advance the cascade so the next same-content paste is offset further.
|
|
273
|
+
this._pasteOffset += step;
|
|
274
|
+
}
|
|
275
|
+
const offsetX = pasteX - minX;
|
|
276
|
+
const offsetY = pasteY - minY;
|
|
277
|
+
this._core.removeSelectionGroup();
|
|
278
|
+
this._core.removeSelectionBox();
|
|
279
|
+
const selectionGroup = KritzelSelectionGroup.create(this._core);
|
|
280
|
+
const baseZIndex = this._core.store.currentZIndex;
|
|
281
|
+
this._core.store.objects.transaction(() => {
|
|
282
|
+
const flushPendingChildren = (group, parentZIndex) => {
|
|
283
|
+
if (group._pendingChildren.length === 0) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const pendingChildren = group._pendingChildren;
|
|
287
|
+
group._pendingChildren = [];
|
|
288
|
+
pendingChildren.forEach((child, childIndex) => {
|
|
289
|
+
if (child.workspaceId !== activeWorkspace.id) {
|
|
290
|
+
child.workspaceId = activeWorkspace.id;
|
|
291
|
+
}
|
|
292
|
+
child.updatePosition(child.translateX + offsetX, child.translateY + offsetY);
|
|
293
|
+
child.zIndex = parentZIndex + childIndex + 1;
|
|
294
|
+
if (KritzelClassHelper.isInstanceOf(child, 'KritzelGroup')) {
|
|
295
|
+
flushPendingChildren(child, child.zIndex);
|
|
296
|
+
}
|
|
297
|
+
this._core.addObject(child);
|
|
298
|
+
});
|
|
299
|
+
group.finalize();
|
|
300
|
+
};
|
|
301
|
+
const newlyAddedObjects = [];
|
|
302
|
+
copiedObjects.forEach((obj, i) => {
|
|
303
|
+
if (obj.workspaceId !== activeWorkspace.id) {
|
|
304
|
+
obj.workspaceId = activeWorkspace.id;
|
|
305
|
+
}
|
|
306
|
+
obj.updatePosition(obj.translateX + offsetX, obj.translateY + offsetY);
|
|
307
|
+
obj.zIndex = baseZIndex + i;
|
|
308
|
+
if (KritzelClassHelper.isInstanceOf(obj, 'KritzelGroup')) {
|
|
309
|
+
flushPendingChildren(obj, obj.zIndex);
|
|
310
|
+
}
|
|
311
|
+
this._core.addObject(obj);
|
|
312
|
+
newlyAddedObjects.push(obj);
|
|
313
|
+
selectionGroup.addOrRemove(obj);
|
|
314
|
+
});
|
|
315
|
+
this._core.engine.emitObjectsAdded(newlyAddedObjects);
|
|
316
|
+
});
|
|
317
|
+
this._core.anchorManager.rebuildIndex();
|
|
318
|
+
selectionGroup.isSelected = true;
|
|
319
|
+
if (copiedObjects.length === 1) {
|
|
320
|
+
selectionGroup.rotation = copiedObjects[0].rotation;
|
|
321
|
+
}
|
|
322
|
+
if (shouldCenterInViewport && !hasExplicitPastePosition) {
|
|
323
|
+
selectionGroup.centerInViewport();
|
|
324
|
+
}
|
|
325
|
+
this._core.addSelectionGroup(selectionGroup);
|
|
326
|
+
this._core.engine.viewport?.bringIntoViewIfNeeded(selectionGroup);
|
|
327
|
+
this._core.store.state.isSelecting = false;
|
|
328
|
+
// Use a double requestAnimationFrame to ensure the browser has fully rendered the DOM,
|
|
329
|
+
// and objects like KritzelText have executed their own internal size-adjustment rAF calls.
|
|
330
|
+
await new Promise(resolve => {
|
|
331
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
332
|
+
});
|
|
333
|
+
// Re-evaluate bounding box dimensions now that any DOM nodes (like ProseMirror text editors)
|
|
334
|
+
// have mounted and calculated their actual bounds.
|
|
335
|
+
selectionGroup.refreshObjectDimensions();
|
|
336
|
+
// We should update it if the centerInViewport or width adjustments changed it significantly
|
|
337
|
+
if (shouldCenterInViewport && !hasExplicitPastePosition) {
|
|
338
|
+
selectionGroup.centerInViewport();
|
|
339
|
+
}
|
|
340
|
+
this._core.engine.emitObjectsChange();
|
|
341
|
+
this._core.rerender();
|
|
342
|
+
this._core.store.setState('activeTool', this._core.toolRegistry.getTool('selection'));
|
|
343
|
+
this._core.engine.emitObjectsChange();
|
|
344
|
+
this._core.rerender();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CLIPBOARD_PAYLOAD_PREFIX = 'kritzel-clipboard/v1:';
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { KritzelCursorHelper } from "../../helpers/cursor.helper";
|
|
2
|
+
/**
|
|
3
|
+
* Manages cursor state and updates across the application.
|
|
4
|
+
* Handles cursor changes based on handle hovers, tool states, and interactions.
|
|
5
|
+
*/
|
|
6
|
+
export class KritzelCursorManager {
|
|
7
|
+
_core;
|
|
8
|
+
_targetElement = null;
|
|
9
|
+
_shadowRoot = null;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new KritzelCursorManager instance.
|
|
12
|
+
* @param core - The KritzelCore instance that provides access to the store and other core functionality.
|
|
13
|
+
*/
|
|
14
|
+
constructor(core) {
|
|
15
|
+
this._core = core;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sets the target element where cursor styles will be applied.
|
|
19
|
+
* Resets any cursor styles on the previous target element before setting the new one.
|
|
20
|
+
* Also sets the `--kritzel-global-pointer-cursor` CSS variable for child components to use.
|
|
21
|
+
* @param element - The HTML element to apply cursor styles to, or null to clear the target.
|
|
22
|
+
*/
|
|
23
|
+
setTargetElement(element) {
|
|
24
|
+
// Reset cursor on old target
|
|
25
|
+
if (this._targetElement) {
|
|
26
|
+
this._targetElement.style.cursor = '';
|
|
27
|
+
this._targetElement.style.removeProperty('--kritzel-global-pointer-cursor');
|
|
28
|
+
}
|
|
29
|
+
this._targetElement = element;
|
|
30
|
+
// Set the pointer cursor CSS variable for child components to use
|
|
31
|
+
if (this._targetElement) {
|
|
32
|
+
this._targetElement.style.setProperty('--kritzel-global-pointer-cursor', KritzelCursorHelper.getPointerCursor());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Gets the current cursor target element.
|
|
37
|
+
* @returns The HTML element where cursor styles are applied, or null if not set.
|
|
38
|
+
*/
|
|
39
|
+
getTargetElement() {
|
|
40
|
+
return this._targetElement;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Sets the shadow root used for element detection in hover state calculations.
|
|
44
|
+
* Required for `elementsFromPoint()` to work within the shadow DOM.
|
|
45
|
+
* @param shadowRoot - The ShadowRoot instance of the component.
|
|
46
|
+
*/
|
|
47
|
+
setShadowRoot(shadowRoot) {
|
|
48
|
+
this._shadowRoot = shadowRoot;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resets cursor to default state by setting both icon and iconActive to 'default'.
|
|
52
|
+
* Should be called when all pointers are released to return to the standard cursor.
|
|
53
|
+
*/
|
|
54
|
+
resetToDefault() {
|
|
55
|
+
this._core.store.state.cursor = { icon: 'default', iconActive: 'default' };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detects handle hover states using elementsFromPoint() to work with overlapped elements.
|
|
59
|
+
* This approach finds all elements at the pointer position instead of relying on pointerenter/pointerleave,
|
|
60
|
+
* which allows proper detection even when elements overlap.
|
|
61
|
+
*
|
|
62
|
+
* Updates the cursor state based on which handle type is being hovered:
|
|
63
|
+
* - Resize handle overlays: Sets a rotated vertical move cursor based on handle position and selection rotation.
|
|
64
|
+
* - Rotation handle overlays: Sets a hand cursor that changes to grab when active.
|
|
65
|
+
* - Line handle overlays: Sets a hand cursor that changes to grab when active.
|
|
66
|
+
* - No handle: Resets to default cursor.
|
|
67
|
+
*
|
|
68
|
+
* @param ev - The PointerEvent containing the cursor position (clientX, clientY).
|
|
69
|
+
*/
|
|
70
|
+
updateHoverState(ev) {
|
|
71
|
+
if (this._core.store.isPointerDown)
|
|
72
|
+
return;
|
|
73
|
+
if (!this._shadowRoot)
|
|
74
|
+
return;
|
|
75
|
+
const elementsAtPoint = this._shadowRoot.elementsFromPoint(ev.clientX, ev.clientY);
|
|
76
|
+
if (!elementsAtPoint || elementsAtPoint.length === 0)
|
|
77
|
+
return;
|
|
78
|
+
// Check for resize handle overlays (selection group)
|
|
79
|
+
const resizeHandleOverlay = elementsAtPoint.find(el => el.classList.contains('resize-handle-overlay'));
|
|
80
|
+
if (resizeHandleOverlay) {
|
|
81
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
82
|
+
const rotationDegrees = selectionGroup?.rotationDegrees ?? 0;
|
|
83
|
+
// Determine rotation offset based on handle position
|
|
84
|
+
const isTopLeft = resizeHandleOverlay.classList.contains('top-left');
|
|
85
|
+
const isBottomRight = resizeHandleOverlay.classList.contains('bottom-right');
|
|
86
|
+
const rotationOffset = (isTopLeft || isBottomRight) ? -45 : 45;
|
|
87
|
+
this._core.store.state.cursor = { icon: 'move-vertical', rotation: rotationDegrees + rotationOffset };
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Check for rotation handle overlay
|
|
91
|
+
const rotationHandleOverlay = elementsAtPoint.find(el => el.classList.contains('rotation-handle-overlay'));
|
|
92
|
+
if (rotationHandleOverlay) {
|
|
93
|
+
this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Check for line handle overlays (selection line)
|
|
97
|
+
const lineHandleOverlay = elementsAtPoint.find(el => el.classList.contains('selection-line-handle-overlay'));
|
|
98
|
+
if (lineHandleOverlay) {
|
|
99
|
+
this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Reset cursor if not hovering any handle
|
|
103
|
+
this._core.store.state.cursor = { icon: 'default', iconActive: 'default' };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Applies the current cursor state to the target element.
|
|
107
|
+
* Reads the cursor configuration from the store state and uses KritzelCursorHelper
|
|
108
|
+
* to generate the appropriate cursor value. Uses the active icon when pointer is down,
|
|
109
|
+
* otherwise uses the default icon.
|
|
110
|
+
* Should be called in the render loop to keep the cursor in sync with state.
|
|
111
|
+
*/
|
|
112
|
+
applyCursor() {
|
|
113
|
+
const state = this._core.store.state;
|
|
114
|
+
const isPointerDown = this._core.store.isPointerDown;
|
|
115
|
+
const icon = state.cursor?.icon;
|
|
116
|
+
const iconActive = state.cursor?.iconActive ?? icon;
|
|
117
|
+
const rotation = state.cursor?.rotation;
|
|
118
|
+
const cursor = KritzelCursorHelper.getCursor({
|
|
119
|
+
iconName: isPointerDown ? iconActive : icon,
|
|
120
|
+
rotation: rotation,
|
|
121
|
+
});
|
|
122
|
+
if (this._targetElement) {
|
|
123
|
+
this._targetElement.style.cursor = cursor;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Cleans up cursor state when the component is disconnected.
|
|
128
|
+
* Removes cursor styles and CSS custom properties from the target element,
|
|
129
|
+
* then clears all internal references to allow garbage collection.
|
|
130
|
+
*/
|
|
131
|
+
cleanup() {
|
|
132
|
+
if (this._targetElement) {
|
|
133
|
+
this._targetElement.style.cursor = '';
|
|
134
|
+
this._targetElement.style.removeProperty('--kritzel-pointer-cursor');
|
|
135
|
+
}
|
|
136
|
+
this._targetElement = null;
|
|
137
|
+
this._shadowRoot = null;
|
|
138
|
+
}
|
|
139
|
+
}
|