@editframe/elements 0.37.2-beta → 0.38.0
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/dist/EF_FRAMEGEN.js +17 -14
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/EF_RENDERING.js.map +1 -1
- package/dist/canvas/EFCanvas.d.ts +9 -2
- package/dist/canvas/EFCanvas.js +14 -4
- package/dist/canvas/EFCanvas.js.map +1 -1
- package/dist/canvas/EFCanvasItem.d.ts +4 -4
- package/dist/canvas/overlays/SelectionOverlay.d.ts +10 -2
- package/dist/canvas/overlays/SelectionOverlay.js +5 -12
- package/dist/canvas/overlays/SelectionOverlay.js.map +1 -1
- package/dist/canvas/overlays/overlayState.js.map +1 -1
- package/dist/canvas/selection/SelectionController.js.map +1 -1
- package/dist/elements/EFAudio.d.ts +1 -11
- package/dist/elements/EFAudio.js +2 -10
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +5 -9
- package/dist/elements/EFCaptions.js +34 -11
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +10 -8
- package/dist/elements/EFImage.js +117 -32
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +2 -2
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +15 -92
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +10 -11
- package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
- package/dist/elements/EFMedia/{AssetIdMediaEngine.js → FileMediaEngine.js} +44 -24
- package/dist/elements/EFMedia/FileMediaEngine.js.map +1 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +14 -13
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +12 -7
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
- package/dist/elements/EFMedia/shared/timeoutUtils.js +44 -0
- package/dist/elements/EFMedia/shared/timeoutUtils.js.map +1 -0
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +1 -1
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +4 -4
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +14 -8
- package/dist/elements/EFMedia.js +52 -19
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +2 -2
- package/dist/elements/EFPanZoom.js +1 -1
- package/dist/elements/EFPanZoom.js.map +1 -1
- package/dist/elements/EFSourceMixin.js +16 -8
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +7 -10
- package/dist/elements/EFSurface.js +4 -43
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +33 -8
- package/dist/elements/EFTemporal.js +92 -40
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +3 -0
- package/dist/elements/EFText.js +54 -21
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.js +8 -4
- package/dist/elements/EFTextSegment.js.map +1 -1
- package/dist/elements/EFTimegroup.d.ts +26 -43
- package/dist/elements/EFTimegroup.js +295 -314
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +44 -42
- package/dist/elements/EFVideo.js +259 -172
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +3 -8
- package/dist/elements/EFWaveform.js +18 -13
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/ElementPositionInfo.js.map +1 -1
- package/dist/elements/FetchMixin.js.map +1 -1
- package/dist/elements/TargetController.d.ts +0 -3
- package/dist/elements/TargetController.js +12 -35
- package/dist/elements/TargetController.js.map +1 -1
- package/dist/elements/TimegroupController.js.map +1 -1
- package/dist/elements/cloneFactoryRegistry.d.ts +14 -0
- package/dist/elements/cloneFactoryRegistry.js +15 -0
- package/dist/elements/cloneFactoryRegistry.js.map +1 -0
- package/dist/elements/renderTemporalAudio.js +8 -6
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/elements/setupTemporalHierarchy.js +62 -0
- package/dist/elements/setupTemporalHierarchy.js.map +1 -0
- package/dist/elements/updateAnimations.js +62 -87
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/getRenderInfo.d.ts +3 -2
- package/dist/getRenderInfo.js +20 -4
- package/dist/getRenderInfo.js.map +1 -1
- package/dist/gui/ContextMixin.js +68 -12
- package/dist/gui/ContextMixin.js.map +1 -1
- package/dist/gui/Controllable.js +1 -1
- package/dist/gui/Controllable.js.map +1 -1
- package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
- package/dist/gui/EFActiveRootTemporal.js.map +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +2 -2
- package/dist/gui/EFControls.js.map +1 -1
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFDial.js +12 -9
- package/dist/gui/EFDial.js.map +1 -1
- package/dist/gui/EFFilmstrip.d.ts +2 -0
- package/dist/gui/EFFilmstrip.js +18 -10
- package/dist/gui/EFFilmstrip.js.map +1 -1
- package/dist/gui/EFFitScale.d.ts +28 -4
- package/dist/gui/EFFitScale.js +88 -26
- package/dist/gui/EFFitScale.js.map +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +4 -4
- package/dist/gui/EFFocusOverlay.js +3 -3
- package/dist/gui/EFFocusOverlay.js.map +1 -1
- package/dist/gui/EFOverlayItem.d.ts +4 -4
- package/dist/gui/EFOverlayLayer.d.ts +4 -4
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPause.js +1 -1
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPlay.js +1 -1
- package/dist/gui/EFPreview.js +1 -1
- package/dist/gui/EFResizableBox.d.ts +4 -4
- package/dist/gui/EFResizableBox.js +5 -5
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +4 -4
- package/dist/gui/EFScrubber.js +8 -13
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +8 -4
- package/dist/gui/EFTimeDisplay.js +25 -7
- package/dist/gui/EFTimeDisplay.js.map +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +4 -4
- package/dist/gui/EFTimelineRuler.js +3 -3
- package/dist/gui/EFTimelineRuler.js.map +1 -1
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFToggleLoop.js +1 -1
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFTogglePlay.js +1 -1
- package/dist/gui/EFTransformHandles.d.ts +4 -4
- package/dist/gui/EFTransformHandles.js +6 -6
- package/dist/gui/EFTransformHandles.js.map +1 -1
- package/dist/gui/EFWorkbench.d.ts +40 -36
- package/dist/gui/EFWorkbench.js +436 -822
- package/dist/gui/EFWorkbench.js.map +1 -1
- package/dist/gui/FitScaleHelpers.js.map +1 -1
- package/dist/gui/PlaybackController.d.ts +3 -8
- package/dist/gui/PlaybackController.js +59 -56
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/TargetOrContextMixin.js +43 -6
- package/dist/gui/TargetOrContextMixin.js.map +1 -1
- package/dist/gui/ef-theme.css +136 -0
- package/dist/gui/hierarchy/EFHierarchy.d.ts +2 -2
- package/dist/gui/hierarchy/EFHierarchy.js +14 -24
- package/dist/gui/hierarchy/EFHierarchy.js.map +1 -1
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
- package/dist/gui/hierarchy/EFHierarchyItem.js +22 -10
- package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -1
- package/dist/gui/icons.js.map +1 -1
- package/dist/gui/previewSettingsContext.d.ts +18 -0
- package/dist/gui/previewSettingsContext.js.map +1 -1
- package/dist/gui/theme.js +34 -0
- package/dist/gui/theme.js.map +1 -0
- package/dist/gui/timeline/EFTimeline.d.ts +2 -2
- package/dist/gui/timeline/EFTimeline.js +70 -52
- package/dist/gui/timeline/EFTimeline.js.map +1 -1
- package/dist/gui/timeline/EFTimelineRow.d.ts +3 -1
- package/dist/gui/timeline/EFTimelineRow.js +55 -32
- package/dist/gui/timeline/EFTimelineRow.js.map +1 -1
- package/dist/gui/timeline/TrimHandles.d.ts +23 -9
- package/dist/gui/timeline/TrimHandles.js +224 -51
- package/dist/gui/timeline/TrimHandles.js.map +1 -1
- package/dist/gui/timeline/flattenHierarchy.js.map +1 -1
- package/dist/gui/timeline/timelineEditingContext.d.ts +34 -0
- package/dist/gui/timeline/timelineEditingContext.js +24 -0
- package/dist/gui/timeline/timelineEditingContext.js.map +1 -0
- package/dist/gui/timeline/timelineStateContext.js.map +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +2 -3
- package/dist/gui/timeline/tracks/CaptionsTrack.js +17 -75
- package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/EFThumbnailStrip.d.ts +52 -0
- package/dist/gui/timeline/tracks/EFThumbnailStrip.js +596 -0
- package/dist/gui/timeline/tracks/EFThumbnailStrip.js.map +1 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TextTrack.d.ts +3 -2
- package/dist/gui/timeline/tracks/TextTrack.js +17 -43
- package/dist/gui/timeline/tracks/TextTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +5 -6
- package/dist/gui/timeline/tracks/TimegroupTrack.js +33 -23
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TrackItem.d.ts +7 -9
- package/dist/gui/timeline/tracks/TrackItem.js +18 -17
- package/dist/gui/timeline/tracks/TrackItem.js.map +1 -1
- package/dist/gui/timeline/tracks/VideoTrack.d.ts +3 -3
- package/dist/gui/timeline/tracks/VideoTrack.js +11 -14
- package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -1
- package/dist/gui/timeline/tracks/waveformUtils.js +1 -1
- package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -1
- package/dist/gui/tree/EFTree.d.ts +4 -4
- package/dist/gui/tree/EFTree.js +8 -14
- package/dist/gui/tree/EFTree.js.map +1 -1
- package/dist/gui/tree/EFTreeItem.d.ts +4 -4
- package/dist/gui/tree/EFTreeItem.js +3 -3
- package/dist/gui/tree/EFTreeItem.js.map +1 -1
- package/dist/gui/tree/treeContext.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/preview/AdaptiveResolutionTracker.js +3 -3
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
- package/dist/preview/FrameController.d.ts +2 -17
- package/dist/preview/FrameController.js +40 -63
- package/dist/preview/FrameController.js.map +1 -1
- package/dist/preview/QualityUpgradeScheduler.d.ts +76 -0
- package/dist/preview/QualityUpgradeScheduler.js +158 -0
- package/dist/preview/QualityUpgradeScheduler.js.map +1 -0
- package/dist/preview/RenderContext.d.ts +119 -1
- package/dist/preview/RenderContext.js +21 -3
- package/dist/preview/RenderContext.js.map +1 -1
- package/dist/preview/RenderProfiler.js.map +1 -1
- package/dist/preview/RenderStats.js +85 -0
- package/dist/preview/RenderStats.js.map +1 -0
- package/dist/preview/encoding/canvasEncoder.js +2 -52
- package/dist/preview/encoding/canvasEncoder.js.map +1 -1
- package/dist/preview/encoding/mainThreadEncoder.js.map +1 -1
- package/dist/preview/encoding/workerEncoder.js.map +1 -1
- package/dist/preview/logger.js.map +1 -1
- package/dist/preview/previewSettings.d.ts +34 -0
- package/dist/preview/previewSettings.js +29 -17
- package/dist/preview/previewSettings.js.map +1 -1
- package/dist/preview/previewTypes.js +4 -4
- package/dist/preview/previewTypes.js.map +1 -1
- package/dist/preview/renderElementToCanvas.d.ts +44 -0
- package/dist/preview/renderElementToCanvas.js +72 -0
- package/dist/preview/renderElementToCanvas.js.map +1 -0
- package/dist/preview/renderTimegroupToCanvas.js +267 -145
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
- package/dist/preview/renderTimegroupToCanvas.types.d.ts +30 -0
- package/dist/preview/renderTimegroupToVideo.js +85 -105
- package/dist/preview/renderTimegroupToVideo.js.map +1 -1
- package/dist/preview/{renderTimegroupToVideo.d.ts → renderTimegroupToVideo.types.d.ts} +9 -9
- package/dist/preview/renderVideoToVideo.js +286 -0
- package/dist/preview/renderVideoToVideo.js.map +1 -0
- package/dist/preview/renderers.js.map +1 -1
- package/dist/preview/rendering/ScaleConfig.js +74 -0
- package/dist/preview/rendering/ScaleConfig.js.map +1 -0
- package/dist/preview/rendering/inlineImages.js +1 -44
- package/dist/preview/rendering/inlineImages.js.map +1 -1
- package/dist/preview/rendering/loadImage.js +22 -0
- package/dist/preview/rendering/loadImage.js.map +1 -0
- package/dist/preview/rendering/renderToImageNative.js +3 -3
- package/dist/preview/rendering/renderToImageNative.js.map +1 -1
- package/dist/preview/rendering/serializeTimelineDirect.js +224 -68
- package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
- package/dist/preview/statsTrackingStrategy.js +1 -101
- package/dist/preview/statsTrackingStrategy.js.map +1 -1
- package/dist/preview/workers/WorkerPool.js +0 -1
- package/dist/preview/workers/WorkerPool.js.map +1 -1
- package/dist/preview/workers/encoderWorkerInline.js +21 -54
- package/dist/preview/workers/encoderWorkerInline.js.map +1 -1
- package/dist/render/EFRenderAPI.d.ts +2 -1
- package/dist/render/EFRenderAPI.js +12 -36
- package/dist/render/EFRenderAPI.js.map +1 -1
- package/dist/render/getRenderData.js +4 -4
- package/dist/render/getRenderData.js.map +1 -1
- package/dist/style.css +114 -163
- package/dist/transcoding/cache/RequestDeduplicator.js +1 -0
- package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
- package/dist/transcoding/types/index.d.ts +1 -1
- package/dist/transcoding/utils/UrlGenerator.js +10 -3
- package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
- package/dist/utils/LRUCache.js +1 -0
- package/dist/utils/LRUCache.js.map +1 -1
- package/dist/utils/frameTime.js +23 -1
- package/dist/utils/frameTime.js.map +1 -1
- package/package.json +21 -8
- package/scripts/build-css.js +8 -1
- package/test/setup.ts +0 -1
- package/test/useAssetMSW.ts +50 -0
- package/test/visualRegressionUtils.ts +23 -9
- package/dist/_virtual/rolldown_runtime.js +0 -27
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +0 -1
- package/dist/elements/EFThumbnailStrip.d.ts +0 -167
- package/dist/elements/EFThumbnailStrip.js +0 -731
- package/dist/elements/EFThumbnailStrip.js.map +0 -1
- package/dist/elements/SessionThumbnailCache.js +0 -154
- package/dist/elements/SessionThumbnailCache.js.map +0 -1
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -688
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +0 -1
- package/dist/node_modules/react/cjs/react.development.js +0 -1521
- package/dist/node_modules/react/cjs/react.development.js.map +0 -1
- package/dist/node_modules/react/index.js +0 -13
- package/dist/node_modules/react/index.js.map +0 -1
- package/dist/node_modules/react/jsx-runtime.js +0 -13
- package/dist/node_modules/react/jsx-runtime.js.map +0 -1
- package/dist/preview/encoding/types.d.ts +0 -1
- package/dist/preview/renderTimegroupPreview.js +0 -686
- package/dist/preview/renderTimegroupPreview.js.map +0 -1
- package/dist/preview/renderTimegroupToCanvas.d.ts +0 -42
- package/dist/preview/rendering/renderToImage.d.ts +0 -2
- package/dist/preview/rendering/renderToImage.js +0 -95
- package/dist/preview/rendering/renderToImage.js.map +0 -1
- package/dist/preview/rendering/renderToImageForeignObject.js +0 -163
- package/dist/preview/rendering/renderToImageForeignObject.js.map +0 -1
- package/dist/preview/rendering/renderToImageNative.d.ts +0 -1
- package/dist/preview/rendering/svgSerializer.js +0 -43
- package/dist/preview/rendering/svgSerializer.js.map +0 -1
- package/dist/preview/rendering/types.d.ts +0 -2
- package/dist/preview/thumbnailCacheSettings.js +0 -52
- package/dist/preview/thumbnailCacheSettings.js.map +0 -1
- package/dist/sandbox/PlaybackControls.d.ts +0 -1
- package/dist/sandbox/PlaybackControls.js +0 -10
- package/dist/sandbox/PlaybackControls.js.map +0 -1
- package/dist/sandbox/ScenarioRunner.d.ts +0 -1
- package/dist/sandbox/ScenarioRunner.js +0 -1
- package/dist/sandbox/defineSandbox.d.ts +0 -1
- package/dist/sandbox/index.d.ts +0 -3
- package/dist/sandbox/index.js +0 -2
- package/test/EFVideo.framegen.browsertest.ts +0 -80
- package/test/thumbnail-performance-test.html +0 -116
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EFTransformHandles.js","names":["EFTransformHandles","overlayStyles: Record<string, string>"],"sources":["../../src/gui/EFTransformHandles.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { panZoomTransformContext } from \"./panZoomTransformContext.js\";\nimport type { PanZoomTransform } from \"../elements/EFPanZoom.js\";\nimport {\n type ResizeHandle,\n calculateDragBounds,\n calculateResizeBounds,\n getResizeHandleCursor,\n} from \"./transformCalculations.js\";\nimport { getCornerPoint, getOppositeCorner } from \"./transformUtils.js\";\n\nconst DEFAULT_MIN_SIZE = 10;\n\nexport interface TransformBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n rotation?: number;\n}\n\n/**\n * Interaction mode enumeration.\n * Only one mode can be active at a time (invariant).\n */\ntype InteractionMode = \"idle\" | \"dragging\" | \"resizing\" | \"rotating\";\n\n@customElement(\"ef-transform-handles\")\nexport class EFTransformHandles extends LitElement {\n @property({ type: Object })\n bounds: TransformBounds = { x: 0, y: 0, width: 100, height: 100 };\n\n @property({ type: Number })\n minSize = DEFAULT_MIN_SIZE;\n\n @property({ type: String })\n target?: string;\n\n @consume({ context: panZoomTransformContext, subscribe: true })\n panZoomTransformFromContext?: PanZoomTransform;\n\n @property({ type: Number, attribute: \"canvas-scale\" })\n canvasScale = 1;\n\n @property({ type: Boolean, attribute: \"enable-rotation\" })\n enableRotation = false;\n\n @property({ type: Boolean, attribute: \"enable-resize\" })\n enableResize = true;\n\n @property({ type: Boolean, attribute: \"corners-only\" })\n cornersOnly = false;\n\n @property({ type: Boolean, attribute: \"lock-aspect-ratio\" })\n lockAspectRatio = false;\n\n @property({ type: Boolean, attribute: \"enable-drag\" })\n enableDrag = true;\n\n @property({ type: Number, attribute: \"rotation-step\" })\n rotationStep?: number;\n\n /**\n * Current interaction mode.\n * Invariant: Only one mode active at a time.\n */\n @state()\n interactionMode: InteractionMode = \"idle\";\n\n /**\n * Active resize handle when in \"resizing\" mode.\n * Only valid when interactionMode === \"resizing\".\n */\n private activeResizeHandle: ResizeHandle | null = null;\n\n /**\n * Mouse start position for calculating deltas.\n * Only valid during active interaction.\n */\n private mouseStart: { x: number; y: number } | null = null;\n\n /**\n * Initial bounds at interaction start - NEVER mutated during interaction.\n * All calculations derive from this + mouse deltas.\n * Note: Not a @state() property to avoid re-renders during interaction.\n */\n private initialBounds: TransformBounds | null = null;\n\n static styles = css`\n :host {\n display: block;\n position: absolute;\n pointer-events: none;\n }\n .overlay {\n position: absolute;\n border: 2px solid var(--ef-transform-handles-border-color, #3b82f6);\n pointer-events: none;\n }\n .overlay.dragging {\n border-color: var(--ef-transform-handles-dragging-border-color, #2563eb);\n }\n .drag-area {\n position: absolute;\n inset: 0;\n cursor: move;\n pointer-events: none;\n }\n /* Only enable pointer events when actively dragging */\n .drag-area:active {\n pointer-events: auto;\n }\n .handle {\n position: absolute;\n width: 8px;\n height: 8px;\n background: var(--ef-transform-handles-handle-color, white);\n border: 1px solid var(--ef-transform-handles-handle-border-color, #3b82f6);\n pointer-events: auto;\n /* Only capture pointer events, allow wheel events to pass through */\n touch-action: none;\n }\n .handle.nw { top: -4px; left: -4px; }\n .handle.n { top: -4px; left: 50%; transform: translateX(-50%); }\n .handle.ne { top: -4px; right: -4px; }\n .handle.e { top: 50%; right: -4px; transform: translateY(-50%); }\n .handle.se { bottom: -4px; right: -4px; }\n .handle.s { bottom: -4px; left: 50%; transform: translateX(-50%); }\n .handle.sw { bottom: -4px; left: -4px; }\n .handle.w { top: 50%; left: -4px; transform: translateY(-50%); }\n .rotate-handle {\n position: absolute;\n top: -30px;\n left: 50%;\n transform: translateX(-50%);\n cursor: grab;\n pointer-events: auto;\n /* Only capture pointer events, allow wheel events to pass through */\n touch-action: none;\n }\n .rotate-handle-circle {\n width: 24px;\n height: 24px;\n background: var(--ef-transform-handles-rotate-handle-color, #10b981);\n border: 2px solid white;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .rotate-handle-circle span {\n font-size: 12px;\n color: white;\n }\n `;\n\n private resizeObserver?: ResizeObserver;\n\n /**\n * Single source of truth for zoom scale.\n * Priority: context > prop > 1.0\n */\n private getZoomScale(): number {\n return this.panZoomTransformFromContext?.scale ?? this.canvasScale ?? 1;\n }\n\n /**\n * Convert screen pixel bounds to canvas coordinates.\n */\n private screenToCanvas(bounds: TransformBounds): TransformBounds {\n const scale = this.getZoomScale();\n return {\n x: bounds.x / scale,\n y: bounds.y / scale,\n width: bounds.width / scale,\n height: bounds.height / scale,\n rotation: bounds.rotation,\n };\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.resizeObserver = new ResizeObserver(() => {\n // Dimensions are read directly when needed\n });\n if (this.offsetParent) {\n this.resizeObserver.observe(this.offsetParent);\n }\n // Forward wheel events to parent panzoom so zoom works even when pointer is over handles\n // Wheel events should pass through, but we'll forward them to ensure panzoom receives them\n this.addEventListener(\n \"wheel\",\n (e: WheelEvent) => {\n // Only forward if not actively interacting with handles\n if (this.interactionMode === \"idle\") {\n // Find parent panzoom and forward the event\n const panZoom = this.closest(\"ef-pan-zoom\");\n if (panZoom) {\n // Create a new wheel event and dispatch it on panzoom\n const wheelEvent = new WheelEvent(\"wheel\", {\n bubbles: true,\n cancelable: true,\n clientX: e.clientX,\n clientY: e.clientY,\n deltaX: e.deltaX,\n deltaY: e.deltaY,\n deltaZ: e.deltaZ,\n deltaMode: e.deltaMode,\n ctrlKey: e.ctrlKey,\n metaKey: e.metaKey,\n shiftKey: e.shiftKey,\n altKey: e.altKey,\n });\n panZoom.dispatchEvent(wheelEvent);\n }\n }\n },\n { passive: true },\n );\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.cleanup();\n }\n\n /**\n * Transition interaction mode state machine.\n * Ensures only one mode is active at a time (invariant).\n */\n private transitionInteractionMode(\n event:\n | \"mousedown-drag\"\n | \"mousedown-resize\"\n | \"mousedown-rotate\"\n | \"mouseup\",\n ): InteractionMode {\n if (event === \"mouseup\") {\n return \"idle\";\n }\n // Only allow transition from idle\n if (this.interactionMode !== \"idle\") {\n return this.interactionMode;\n }\n switch (event) {\n case \"mousedown-drag\":\n return \"dragging\";\n case \"mousedown-resize\":\n return \"resizing\";\n case \"mousedown-rotate\":\n return \"rotating\";\n default:\n return \"idle\";\n }\n }\n\n private handleMouseDown = (e: MouseEvent) => {\n if (!this.enableDrag) return;\n e.stopPropagation();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-drag\");\n this.mouseStart = { x: e.clientX, y: e.clientY };\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n private handleResizeMouseDown = (e: MouseEvent, handle: ResizeHandle) => {\n if (!this.enableResize) return;\n e.stopPropagation();\n e.preventDefault();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-resize\");\n this.activeResizeHandle = handle;\n this.mouseStart = { x: e.clientX, y: e.clientY };\n // Store initial bounds as-is (in screen pixels) - we'll convert to canvas when calculating\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n private handleRotateMouseDown = (e: MouseEvent) => {\n if (!this.enableRotation) return;\n e.stopPropagation();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-rotate\");\n this.mouseStart = { x: e.clientX, y: e.clientY };\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n /**\n * Dispatch bounds change event (one-way data flow).\n * Parent updates element, then reads element and updates handle bounds prop.\n * We don't modify this.bounds directly - always render from prop.\n */\n private dispatchBoundsChange(bounds: TransformBounds): void {\n this.dispatchEvent(\n new CustomEvent(\"bounds-change\", {\n detail: { bounds },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private handleMouseMove = (e: MouseEvent) => {\n if (!this.mouseStart || !this.initialBounds) return;\n\n // Calculate mouse deltas in viewport coordinates\n const screenDeltaX = e.clientX - this.mouseStart.x;\n const screenDeltaY = e.clientY - this.mouseStart.y;\n\n switch (this.interactionMode) {\n case \"dragging\": {\n const zoomScale = this.getZoomScale();\n const initialCanvas = this.screenToCanvas(this.initialBounds);\n\n const newPosition = calculateDragBounds(\n { x: initialCanvas.x, y: initialCanvas.y },\n screenDeltaX,\n screenDeltaY,\n zoomScale,\n );\n\n this.dispatchBoundsChange({\n ...newPosition,\n width: initialCanvas.width,\n height: initialCanvas.height,\n rotation: this.initialBounds.rotation,\n });\n break;\n }\n\n case \"resizing\": {\n if (!this.activeResizeHandle) return;\n\n const zoomScale = this.getZoomScale();\n const initialCanvas = this.screenToCanvas(this.initialBounds);\n const rotation = this.enableRotation\n ? (this.initialBounds.rotation ?? 0)\n : 0;\n\n // Calculate the fixed corner (opposite to handle being dragged)\n const oppositeCorner = getOppositeCorner(this.activeResizeHandle);\n const rotationRadians = (rotation * Math.PI) / 180;\n const fixedCorner = getCornerPoint(\n initialCanvas.x,\n initialCanvas.y,\n initialCanvas.width,\n initialCanvas.height,\n rotationRadians,\n oppositeCorner.x,\n oppositeCorner.y,\n );\n\n const newCanvasBounds = calculateResizeBounds(\n { width: initialCanvas.width, height: initialCanvas.height },\n { x: initialCanvas.x, y: initialCanvas.y },\n fixedCorner,\n this.activeResizeHandle,\n screenDeltaX,\n screenDeltaY,\n rotation,\n this.minSize / zoomScale,\n zoomScale,\n {\n lockAspectRatio: this.lockAspectRatio || e.shiftKey,\n resizeFromCenter: e.ctrlKey || e.metaKey,\n },\n );\n\n // Preserve rotation\n newCanvasBounds.rotation = this.initialBounds.rotation;\n this.dispatchBoundsChange(newCanvasBounds);\n break;\n }\n\n case \"rotating\": {\n // Calculate center in screen coordinates (bounds are overlay-relative)\n const overlayRect = this.offsetParent?.getBoundingClientRect() ?? {\n left: 0,\n top: 0,\n };\n const centerX =\n overlayRect.left +\n this.initialBounds.x +\n this.initialBounds.width / 2;\n const centerY =\n overlayRect.top +\n this.initialBounds.y +\n this.initialBounds.height / 2;\n\n // Calculate angle from mouse start to current position\n const startAngle =\n Math.atan2(this.mouseStart.y - centerY, this.mouseStart.x - centerX) *\n (180 / Math.PI) +\n 90;\n const currentAngle =\n Math.atan2(e.clientY - centerY, e.clientX - centerX) *\n (180 / Math.PI) +\n 90;\n\n // Normalize angle difference to [-180, 180] to avoid wrapping issues\n let deltaAngle = currentAngle - startAngle;\n while (deltaAngle > 180) deltaAngle -= 360;\n while (deltaAngle < -180) deltaAngle += 360;\n\n let newRotation = (this.initialBounds.rotation ?? 0) + deltaAngle;\n if (this.rotationStep !== undefined && this.rotationStep > 0) {\n newRotation =\n Math.round(newRotation / this.rotationStep) * this.rotationStep;\n }\n\n this.dispatchEvent(\n new CustomEvent(\"rotation-change\", {\n detail: { rotation: newRotation },\n bubbles: true,\n composed: true,\n }),\n );\n break;\n }\n\n case \"idle\":\n // No action needed\n break;\n }\n };\n\n private handleMouseUp = () => {\n this.cleanup();\n };\n\n private cleanup() {\n this.interactionMode = this.transitionInteractionMode(\"mouseup\");\n this.activeResizeHandle = null;\n this.mouseStart = null;\n this.initialBounds = null;\n document.removeEventListener(\"mousemove\", this.handleMouseMove);\n document.removeEventListener(\"mouseup\", this.handleMouseUp);\n }\n\n render() {\n // Always render from bounds prop (one-way data flow)\n // During interaction: dispatch events, parent updates element, parent updates handle bounds prop\n const currentBounds = this.bounds;\n const rotation = this.enableRotation ? (currentBounds.rotation ?? 0) : 0;\n\n const overlayStyles: Record<string, string> = {\n left: `${currentBounds.x}px`,\n top: `${currentBounds.y}px`,\n width: `${currentBounds.width}px`,\n height: `${currentBounds.height}px`,\n };\n\n if (this.enableRotation && rotation !== 0) {\n overlayStyles.transform = `rotate(${rotation}deg)`;\n overlayStyles.transformOrigin = \"center\";\n }\n\n const allHandles: ResizeHandle[] = [\n \"nw\",\n \"n\",\n \"ne\",\n \"e\",\n \"se\",\n \"s\",\n \"sw\",\n \"w\",\n ];\n const cornerHandles: ResizeHandle[] = [\"nw\", \"ne\", \"se\", \"sw\"];\n const handles = this.cornersOnly ? cornerHandles : allHandles;\n\n return html`\n <div\n class=\"overlay ${this.interactionMode === \"dragging\" ? \"dragging\" : \"\"}\"\n style=${styleMap(overlayStyles)}\n >\n ${\n this.enableDrag\n ? html`\n <div\n class=\"drag-area\"\n @mousedown=${this.handleMouseDown}\n ></div>\n `\n : \"\"\n }\n ${\n this.enableResize\n ? handles.map((handle) => {\n const rotation = this.enableRotation\n ? (currentBounds.rotation ?? 0)\n : 0;\n const cursor = getResizeHandleCursor(handle, rotation);\n return html`\n <div\n class=\"handle ${handle}\"\n style=${styleMap({ cursor })}\n @mousedown=${(e: MouseEvent) => this.handleResizeMouseDown(e, handle)}\n ></div>\n `;\n })\n : \"\"\n }\n ${\n this.enableRotation\n ? html`\n <div class=\"rotate-handle\" @mousedown=${this.handleRotateMouseDown}>\n <div class=\"rotate-handle-circle\">\n <span>↻</span>\n </div>\n </div>\n `\n : \"\"\n }\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-transform-handles\": EFTransformHandles;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EFTransformHandles.js","names":["EFTransformHandles","overlayStyles: Record<string, string>"],"sources":["../../src/gui/EFTransformHandles.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { panZoomTransformContext } from \"./panZoomTransformContext.js\";\nimport type { PanZoomTransform } from \"../elements/EFPanZoom.js\";\nimport {\n type ResizeHandle,\n calculateDragBounds,\n calculateResizeBounds,\n getResizeHandleCursor,\n} from \"./transformCalculations.js\";\nimport { getCornerPoint, getOppositeCorner } from \"./transformUtils.js\";\n\nconst DEFAULT_MIN_SIZE = 10;\n\nexport interface TransformBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n rotation?: number;\n}\n\n/**\n * Interaction mode enumeration.\n * Only one mode can be active at a time (invariant).\n */\ntype InteractionMode = \"idle\" | \"dragging\" | \"resizing\" | \"rotating\";\n\n@customElement(\"ef-transform-handles\")\nexport class EFTransformHandles extends LitElement {\n @property({ type: Object })\n bounds: TransformBounds = { x: 0, y: 0, width: 100, height: 100 };\n\n @property({ type: Number })\n minSize = DEFAULT_MIN_SIZE;\n\n @property({ type: String })\n target?: string;\n\n @consume({ context: panZoomTransformContext, subscribe: true })\n panZoomTransformFromContext?: PanZoomTransform;\n\n @property({ type: Number, attribute: \"canvas-scale\" })\n canvasScale = 1;\n\n @property({ type: Boolean, attribute: \"enable-rotation\" })\n enableRotation = false;\n\n @property({ type: Boolean, attribute: \"enable-resize\" })\n enableResize = true;\n\n @property({ type: Boolean, attribute: \"corners-only\" })\n cornersOnly = false;\n\n @property({ type: Boolean, attribute: \"lock-aspect-ratio\" })\n lockAspectRatio = false;\n\n @property({ type: Boolean, attribute: \"enable-drag\" })\n enableDrag = true;\n\n @property({ type: Number, attribute: \"rotation-step\" })\n rotationStep?: number;\n\n /**\n * Current interaction mode.\n * Invariant: Only one mode active at a time.\n */\n @state()\n interactionMode: InteractionMode = \"idle\";\n\n /**\n * Active resize handle when in \"resizing\" mode.\n * Only valid when interactionMode === \"resizing\".\n */\n private activeResizeHandle: ResizeHandle | null = null;\n\n /**\n * Mouse start position for calculating deltas.\n * Only valid during active interaction.\n */\n private mouseStart: { x: number; y: number } | null = null;\n\n /**\n * Initial bounds at interaction start - NEVER mutated during interaction.\n * All calculations derive from this + mouse deltas.\n * Note: Not a @state() property to avoid re-renders during interaction.\n */\n private initialBounds: TransformBounds | null = null;\n\n static styles = css`\n :host {\n display: block;\n position: absolute;\n pointer-events: none;\n }\n .overlay {\n position: absolute;\n border: 2px solid var(--ef-transform-handles-border-color, var(--ef-color-primary));\n pointer-events: none;\n }\n .overlay.dragging {\n border-color: var(--ef-transform-handles-dragging-border-color, var(--ef-color-primary));\n }\n .drag-area {\n position: absolute;\n inset: 0;\n cursor: move;\n pointer-events: none;\n }\n /* Only enable pointer events when actively dragging */\n .drag-area:active {\n pointer-events: auto;\n }\n .handle {\n position: absolute;\n width: 8px;\n height: 8px;\n background: var(--ef-transform-handles-handle-color, var(--ef-color-bg-elevated));\n border: 1px solid var(--ef-transform-handles-handle-border-color, var(--ef-color-primary));\n pointer-events: auto;\n /* Only capture pointer events, allow wheel events to pass through */\n touch-action: none;\n }\n .handle.nw { top: -4px; left: -4px; }\n .handle.n { top: -4px; left: 50%; transform: translateX(-50%); }\n .handle.ne { top: -4px; right: -4px; }\n .handle.e { top: 50%; right: -4px; transform: translateY(-50%); }\n .handle.se { bottom: -4px; right: -4px; }\n .handle.s { bottom: -4px; left: 50%; transform: translateX(-50%); }\n .handle.sw { bottom: -4px; left: -4px; }\n .handle.w { top: 50%; left: -4px; transform: translateY(-50%); }\n .rotate-handle {\n position: absolute;\n top: -30px;\n left: 50%;\n transform: translateX(-50%);\n cursor: grab;\n pointer-events: auto;\n /* Only capture pointer events, allow wheel events to pass through */\n touch-action: none;\n }\n .rotate-handle-circle {\n width: 24px;\n height: 24px;\n background: var(--ef-transform-handles-rotate-handle-color, var(--ef-color-success));\n border: 2px solid var(--ef-color-bg-elevated);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .rotate-handle-circle span {\n font-size: 12px;\n color: white;\n }\n `;\n\n private resizeObserver?: ResizeObserver;\n\n /**\n * Single source of truth for zoom scale.\n * Priority: context > prop > 1.0\n */\n private getZoomScale(): number {\n return this.panZoomTransformFromContext?.scale ?? this.canvasScale ?? 1;\n }\n\n /**\n * Convert screen pixel bounds to canvas coordinates.\n */\n private screenToCanvas(bounds: TransformBounds): TransformBounds {\n const scale = this.getZoomScale();\n return {\n x: bounds.x / scale,\n y: bounds.y / scale,\n width: bounds.width / scale,\n height: bounds.height / scale,\n rotation: bounds.rotation,\n };\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.resizeObserver = new ResizeObserver(() => {\n // Dimensions are read directly when needed\n });\n if (this.offsetParent) {\n this.resizeObserver.observe(this.offsetParent);\n }\n // Forward wheel events to parent panzoom so zoom works even when pointer is over handles\n // Wheel events should pass through, but we'll forward them to ensure panzoom receives them\n this.addEventListener(\n \"wheel\",\n (e: WheelEvent) => {\n // Only forward if not actively interacting with handles\n if (this.interactionMode === \"idle\") {\n // Find parent panzoom and forward the event\n const panZoom = this.closest(\"ef-pan-zoom\");\n if (panZoom) {\n // Create a new wheel event and dispatch it on panzoom\n const wheelEvent = new WheelEvent(\"wheel\", {\n bubbles: true,\n cancelable: true,\n clientX: e.clientX,\n clientY: e.clientY,\n deltaX: e.deltaX,\n deltaY: e.deltaY,\n deltaZ: e.deltaZ,\n deltaMode: e.deltaMode,\n ctrlKey: e.ctrlKey,\n metaKey: e.metaKey,\n shiftKey: e.shiftKey,\n altKey: e.altKey,\n });\n panZoom.dispatchEvent(wheelEvent);\n }\n }\n },\n { passive: true },\n );\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.cleanup();\n }\n\n /**\n * Transition interaction mode state machine.\n * Ensures only one mode is active at a time (invariant).\n */\n private transitionInteractionMode(\n event:\n | \"mousedown-drag\"\n | \"mousedown-resize\"\n | \"mousedown-rotate\"\n | \"mouseup\",\n ): InteractionMode {\n if (event === \"mouseup\") {\n return \"idle\";\n }\n // Only allow transition from idle\n if (this.interactionMode !== \"idle\") {\n return this.interactionMode;\n }\n switch (event) {\n case \"mousedown-drag\":\n return \"dragging\";\n case \"mousedown-resize\":\n return \"resizing\";\n case \"mousedown-rotate\":\n return \"rotating\";\n default:\n return \"idle\";\n }\n }\n\n private handleMouseDown = (e: MouseEvent) => {\n if (!this.enableDrag) return;\n e.stopPropagation();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-drag\");\n this.mouseStart = { x: e.clientX, y: e.clientY };\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n private handleResizeMouseDown = (e: MouseEvent, handle: ResizeHandle) => {\n if (!this.enableResize) return;\n e.stopPropagation();\n e.preventDefault();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-resize\");\n this.activeResizeHandle = handle;\n this.mouseStart = { x: e.clientX, y: e.clientY };\n // Store initial bounds as-is (in screen pixels) - we'll convert to canvas when calculating\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n private handleRotateMouseDown = (e: MouseEvent) => {\n if (!this.enableRotation) return;\n e.stopPropagation();\n this.interactionMode = this.transitionInteractionMode(\"mousedown-rotate\");\n this.mouseStart = { x: e.clientX, y: e.clientY };\n this.initialBounds = { ...this.bounds };\n document.addEventListener(\"mousemove\", this.handleMouseMove);\n document.addEventListener(\"mouseup\", this.handleMouseUp);\n };\n\n /**\n * Dispatch bounds change event (one-way data flow).\n * Parent updates element, then reads element and updates handle bounds prop.\n * We don't modify this.bounds directly - always render from prop.\n */\n private dispatchBoundsChange(bounds: TransformBounds): void {\n this.dispatchEvent(\n new CustomEvent(\"bounds-change\", {\n detail: { bounds },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private handleMouseMove = (e: MouseEvent) => {\n if (!this.mouseStart || !this.initialBounds) return;\n\n // Calculate mouse deltas in viewport coordinates\n const screenDeltaX = e.clientX - this.mouseStart.x;\n const screenDeltaY = e.clientY - this.mouseStart.y;\n\n switch (this.interactionMode) {\n case \"dragging\": {\n const zoomScale = this.getZoomScale();\n const initialCanvas = this.screenToCanvas(this.initialBounds);\n\n const newPosition = calculateDragBounds(\n { x: initialCanvas.x, y: initialCanvas.y },\n screenDeltaX,\n screenDeltaY,\n zoomScale,\n );\n\n this.dispatchBoundsChange({\n ...newPosition,\n width: initialCanvas.width,\n height: initialCanvas.height,\n rotation: this.initialBounds.rotation,\n });\n break;\n }\n\n case \"resizing\": {\n if (!this.activeResizeHandle) return;\n\n const zoomScale = this.getZoomScale();\n const initialCanvas = this.screenToCanvas(this.initialBounds);\n const rotation = this.enableRotation\n ? (this.initialBounds.rotation ?? 0)\n : 0;\n\n // Calculate the fixed corner (opposite to handle being dragged)\n const oppositeCorner = getOppositeCorner(this.activeResizeHandle);\n const rotationRadians = (rotation * Math.PI) / 180;\n const fixedCorner = getCornerPoint(\n initialCanvas.x,\n initialCanvas.y,\n initialCanvas.width,\n initialCanvas.height,\n rotationRadians,\n oppositeCorner.x,\n oppositeCorner.y,\n );\n\n const newCanvasBounds = calculateResizeBounds(\n { width: initialCanvas.width, height: initialCanvas.height },\n { x: initialCanvas.x, y: initialCanvas.y },\n fixedCorner,\n this.activeResizeHandle,\n screenDeltaX,\n screenDeltaY,\n rotation,\n this.minSize / zoomScale,\n zoomScale,\n {\n lockAspectRatio: this.lockAspectRatio || e.shiftKey,\n resizeFromCenter: e.ctrlKey || e.metaKey,\n },\n );\n\n // Preserve rotation\n newCanvasBounds.rotation = this.initialBounds.rotation;\n this.dispatchBoundsChange(newCanvasBounds);\n break;\n }\n\n case \"rotating\": {\n // Calculate center in screen coordinates (bounds are overlay-relative)\n const overlayRect = this.offsetParent?.getBoundingClientRect() ?? {\n left: 0,\n top: 0,\n };\n const centerX =\n overlayRect.left +\n this.initialBounds.x +\n this.initialBounds.width / 2;\n const centerY =\n overlayRect.top +\n this.initialBounds.y +\n this.initialBounds.height / 2;\n\n // Calculate angle from mouse start to current position\n const startAngle =\n Math.atan2(this.mouseStart.y - centerY, this.mouseStart.x - centerX) *\n (180 / Math.PI) +\n 90;\n const currentAngle =\n Math.atan2(e.clientY - centerY, e.clientX - centerX) *\n (180 / Math.PI) +\n 90;\n\n // Normalize angle difference to [-180, 180] to avoid wrapping issues\n let deltaAngle = currentAngle - startAngle;\n while (deltaAngle > 180) deltaAngle -= 360;\n while (deltaAngle < -180) deltaAngle += 360;\n\n let newRotation = (this.initialBounds.rotation ?? 0) + deltaAngle;\n if (this.rotationStep !== undefined && this.rotationStep > 0) {\n newRotation =\n Math.round(newRotation / this.rotationStep) * this.rotationStep;\n }\n\n this.dispatchEvent(\n new CustomEvent(\"rotation-change\", {\n detail: { rotation: newRotation },\n bubbles: true,\n composed: true,\n }),\n );\n break;\n }\n\n case \"idle\":\n // No action needed\n break;\n }\n };\n\n private handleMouseUp = () => {\n this.cleanup();\n };\n\n private cleanup() {\n this.interactionMode = this.transitionInteractionMode(\"mouseup\");\n this.activeResizeHandle = null;\n this.mouseStart = null;\n this.initialBounds = null;\n document.removeEventListener(\"mousemove\", this.handleMouseMove);\n document.removeEventListener(\"mouseup\", this.handleMouseUp);\n }\n\n render() {\n // Always render from bounds prop (one-way data flow)\n // During interaction: dispatch events, parent updates element, parent updates handle bounds prop\n const currentBounds = this.bounds;\n const rotation = this.enableRotation ? (currentBounds.rotation ?? 0) : 0;\n\n const overlayStyles: Record<string, string> = {\n left: `${currentBounds.x}px`,\n top: `${currentBounds.y}px`,\n width: `${currentBounds.width}px`,\n height: `${currentBounds.height}px`,\n };\n\n if (this.enableRotation && rotation !== 0) {\n overlayStyles.transform = `rotate(${rotation}deg)`;\n overlayStyles.transformOrigin = \"center\";\n }\n\n const allHandles: ResizeHandle[] = [\n \"nw\",\n \"n\",\n \"ne\",\n \"e\",\n \"se\",\n \"s\",\n \"sw\",\n \"w\",\n ];\n const cornerHandles: ResizeHandle[] = [\"nw\", \"ne\", \"se\", \"sw\"];\n const handles = this.cornersOnly ? cornerHandles : allHandles;\n\n return html`\n <div\n class=\"overlay ${this.interactionMode === \"dragging\" ? \"dragging\" : \"\"}\"\n style=${styleMap(overlayStyles)}\n >\n ${\n this.enableDrag\n ? html`\n <div\n class=\"drag-area\"\n @mousedown=${this.handleMouseDown}\n ></div>\n `\n : \"\"\n }\n ${\n this.enableResize\n ? handles.map((handle) => {\n const rotation = this.enableRotation\n ? (currentBounds.rotation ?? 0)\n : 0;\n const cursor = getResizeHandleCursor(handle, rotation);\n return html`\n <div\n class=\"handle ${handle}\"\n style=${styleMap({ cursor })}\n @mousedown=${(e: MouseEvent) => this.handleResizeMouseDown(e, handle)}\n ></div>\n `;\n })\n : \"\"\n }\n ${\n this.enableRotation\n ? html`\n <div class=\"rotate-handle\" @mousedown=${this.handleRotateMouseDown}>\n <div class=\"rotate-handle-circle\">\n <span>↻</span>\n </div>\n </div>\n `\n : \"\"\n }\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-transform-handles\": EFTransformHandles;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContextMixinInterface } from "./ContextMixin.js";
|
|
2
|
-
import { RenderToVideoOptions } from "../preview/renderTimegroupToVideo.js";
|
|
2
|
+
import { RenderToVideoOptions } from "../preview/renderTimegroupToVideo.types.js";
|
|
3
3
|
import "./EFFitScale.js";
|
|
4
4
|
import * as lit8 from "lit";
|
|
5
5
|
import { LitElement, PropertyValueMap } from "lit";
|
|
@@ -19,10 +19,6 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
19
19
|
private renderMode;
|
|
20
20
|
private presentationMode;
|
|
21
21
|
private previewResolutionScale;
|
|
22
|
-
private debugThumbnailTimestamps;
|
|
23
|
-
private thumbnailCacheMaxSize;
|
|
24
|
-
private thumbnailCacheStats;
|
|
25
|
-
private cacheStatsUpdateInterval;
|
|
26
22
|
private exportOptions;
|
|
27
23
|
private exportAbortController;
|
|
28
24
|
private isPlaying;
|
|
@@ -37,7 +33,25 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
37
33
|
* Mirrors previewSettings.showStats for direct access
|
|
38
34
|
*/
|
|
39
35
|
private showStats;
|
|
40
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Theme mode: 'light', 'dark', or 'system'
|
|
38
|
+
*/
|
|
39
|
+
private themeMode;
|
|
40
|
+
/**
|
|
41
|
+
* Always-on render statistics collection for canvas mode.
|
|
42
|
+
* Collects data regardless of whether stats are visible.
|
|
43
|
+
*/
|
|
44
|
+
private renderStats;
|
|
45
|
+
/**
|
|
46
|
+
* Media query for system theme preference
|
|
47
|
+
*/
|
|
48
|
+
private systemThemeMediaQuery;
|
|
49
|
+
private systemThemeListener;
|
|
50
|
+
/**
|
|
51
|
+
* DOM mode stats strategy (has its own animation loop).
|
|
52
|
+
* Only active in DOM mode.
|
|
53
|
+
*/
|
|
54
|
+
private domStatsStrategy;
|
|
41
55
|
/**
|
|
42
56
|
* Reference for tracking scrubbing state from EFScrubber.
|
|
43
57
|
* Pass this to <ef-scrubber isScrubbingRef={...}> to enable motion detection.
|
|
@@ -49,14 +63,6 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
49
63
|
private playingCheckInterval;
|
|
50
64
|
private adaptiveTracker;
|
|
51
65
|
private savePanZoomDebounceTimer;
|
|
52
|
-
private cloneOverlayRef;
|
|
53
|
-
private cloneRefresh;
|
|
54
|
-
private cloneAnimationFrame;
|
|
55
|
-
private cloneRootElement;
|
|
56
|
-
private cloneTimegroup;
|
|
57
|
-
private structureObserver;
|
|
58
|
-
private rebuildPending;
|
|
59
|
-
private canvasRefresh;
|
|
60
66
|
private canvasPreviewRef;
|
|
61
67
|
private canvasPreviewResult;
|
|
62
68
|
private canvasAnimationFrame;
|
|
@@ -103,6 +109,11 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
103
109
|
* Update motion state by checking timegroup and scrubbing ref.
|
|
104
110
|
*/
|
|
105
111
|
private updateMotionState;
|
|
112
|
+
/**
|
|
113
|
+
* Pause or unpause the canvas overlay components (EFCanvas, SelectionOverlay)
|
|
114
|
+
* to avoid layout-thrashing during playback.
|
|
115
|
+
*/
|
|
116
|
+
private setOverlaysPaused;
|
|
106
117
|
/**
|
|
107
118
|
* Called when motion starts (playing or scrubbing began).
|
|
108
119
|
*/
|
|
@@ -126,18 +137,6 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
126
137
|
* Called from updated() hook when settings change or dependencies become available.
|
|
127
138
|
*/
|
|
128
139
|
private applySettings;
|
|
129
|
-
/**
|
|
130
|
-
* Update or create stats tracking strategy based on current mode and settings.
|
|
131
|
-
*/
|
|
132
|
-
private updateStatsStrategy;
|
|
133
|
-
private initCloneOverlay;
|
|
134
|
-
private finishCloneSetup;
|
|
135
|
-
private rebuildClone;
|
|
136
|
-
private setupStructureObserver;
|
|
137
|
-
private observeShadowRoots;
|
|
138
|
-
private updateCloneTransform;
|
|
139
|
-
private startCloneLoop;
|
|
140
|
-
private stopCloneOverlay;
|
|
141
140
|
private handlePresentationModeChange;
|
|
142
141
|
private initDomMode;
|
|
143
142
|
private stopDomMode;
|
|
@@ -156,10 +155,10 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
156
155
|
private initCanvasMode;
|
|
157
156
|
private stopCanvasMode;
|
|
158
157
|
private updateCanvasTransform;
|
|
159
|
-
initCanvasRenderer(): {
|
|
158
|
+
initCanvasRenderer(): Promise<{
|
|
160
159
|
canvas: HTMLCanvasElement;
|
|
161
160
|
refresh: () => Promise<void>;
|
|
162
|
-
} | null
|
|
161
|
+
} | null>;
|
|
163
162
|
/** Start video export with progress tracking */
|
|
164
163
|
startExport(options?: RenderToVideoOptions): Promise<void>;
|
|
165
164
|
/** Cancel the current export */
|
|
@@ -172,15 +171,20 @@ declare class EFWorkbench extends EFWorkbench_base {
|
|
|
172
171
|
private formatTime;
|
|
173
172
|
private handleCancelClick;
|
|
174
173
|
private handleRenderModeChange;
|
|
175
|
-
private handleResolutionScaleChange;
|
|
176
|
-
private updateThumbnailCacheStats;
|
|
177
|
-
private startCacheStatsUpdates;
|
|
178
|
-
private stopCacheStatsUpdates;
|
|
179
|
-
private handleThumbnailCacheMaxSizeChange;
|
|
180
|
-
private handleClearThumbnailCache;
|
|
181
|
-
private formatBytes;
|
|
182
|
-
private handleDebugThumbnailTimestampsToggle;
|
|
183
174
|
private handleShowStatsToggle;
|
|
175
|
+
private handleShowThumbnailTimestampsToggle;
|
|
176
|
+
/**
|
|
177
|
+
* Get initial theme from localStorage or default to 'dark'
|
|
178
|
+
*/
|
|
179
|
+
private getInitialTheme;
|
|
180
|
+
/**
|
|
181
|
+
* Cycle through theme modes: light → dark → system → light
|
|
182
|
+
*/
|
|
183
|
+
private handleThemeToggle;
|
|
184
|
+
/**
|
|
185
|
+
* Apply the current theme to the document and host element
|
|
186
|
+
*/
|
|
187
|
+
private applyTheme;
|
|
184
188
|
/**
|
|
185
189
|
* Reset and fit the preview to show all content centered.
|
|
186
190
|
* Finds the pan-zoom element and calls fitToContent() on it.
|