@editframe/elements 0.37.3-beta → 0.38.1
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 +2 -2
- 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 +5 -8
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/gui/EFFocusOverlay.js +3 -3
- package/dist/gui/EFFocusOverlay.js.map +1 -1
- package/dist/gui/EFOverlayItem.d.ts +2 -2
- package/dist/gui/EFOverlayLayer.d.ts +2 -2
- package/dist/gui/EFPause.d.ts +2 -2
- package/dist/gui/EFPause.js +1 -1
- package/dist/gui/EFPlay.d.ts +2 -2
- package/dist/gui/EFPlay.js +1 -1
- package/dist/gui/EFPreview.js +1 -1
- package/dist/gui/EFResizableBox.d.ts +2 -2
- package/dist/gui/EFResizableBox.js +5 -5
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +2 -2
- package/dist/gui/EFScrubber.js +8 -13
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +6 -2
- package/dist/gui/EFTimeDisplay.js +25 -7
- package/dist/gui/EFTimeDisplay.js.map +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +2 -2
- package/dist/gui/EFTimelineRuler.js +3 -3
- package/dist/gui/EFTimelineRuler.js.map +1 -1
- package/dist/gui/EFToggleLoop.d.ts +2 -2
- package/dist/gui/EFToggleLoop.js +1 -1
- package/dist/gui/EFTogglePlay.d.ts +2 -2
- package/dist/gui/EFTogglePlay.js +1 -1
- package/dist/gui/EFTransformHandles.d.ts +2 -2
- 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 +5 -3
- 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 +3 -4
- 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 +2 -2
- package/dist/gui/tree/EFTree.js +8 -14
- package/dist/gui/tree/EFTree.js.map +1 -1
- package/dist/gui/tree/EFTreeItem.d.ts +2 -2
- 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.d.ts +134 -32
- package/dist/preview/renderTimegroupToCanvas.js +321 -146
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
- package/dist/preview/renderTimegroupToCanvas.types.d.ts +51 -0
- package/dist/preview/renderTimegroupToVideo.d.ts +20 -35
- package/dist/preview/renderTimegroupToVideo.js +94 -106
- package/dist/preview/renderTimegroupToVideo.js.map +1 -1
- package/dist/preview/renderTimegroupToVideo.types.d.ts +42 -0
- package/dist/preview/renderVideoToVideo.js +286 -0
- package/dist/preview/renderVideoToVideo.js.map +1 -0
- package/dist/preview/renderers.d.ts +56 -0
- package/dist/preview/renderers.js +13 -1
- 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.d.ts +13 -0
- package/dist/preview/rendering/inlineImages.js +7 -44
- package/dist/preview/rendering/inlineImages.js.map +1 -1
- package/dist/preview/rendering/loadImage.d.ts +8 -0
- 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 +45 -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/tsdown.config.ts +6 -1
- 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/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":"FetchMixin.js","names":["fetchPromise: Promise<Response>"],"sources":["../../src/elements/FetchMixin.ts"],"sourcesContent":["import type { LitElement } from \"lit\";\n\nexport declare class FetchMixinInterface {\n fetch: typeof fetch;\n}\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\nexport function FetchMixin<T extends Constructor<LitElement>>(superClass: T) {\n class FetchElement extends superClass {\n fetch = (url: string, init?: RequestInit): Promise<Response> => {\n try {\n let fetchPromise: Promise<Response>;\n\n // Look for context providers up the DOM tree\n const workbench = this.closest(\"ef-workbench\") as any;\n if (workbench?.fetch) {\n fetchPromise = workbench.fetch(url, init);\n } else {\n const preview = this.closest(\"ef-preview\") as any;\n if (preview?.fetch) {\n fetchPromise = preview.fetch(url, init);\n } else {\n const configuration = this.closest(\"ef-configuration\") as any;\n if (configuration?.fetch) {\n fetchPromise = configuration.fetch(url, init);\n } else {\n // Fallback to window.fetch\n fetchPromise = window.fetch(url, init);\n }\n }\n }\n\n // Wrap the promise to catch rejections and log the URL\n // Return the promise chain so errors are logged but still propagate\n return fetchPromise.catch((error) => {\n // Don't log AbortError - these are intentional request cancellations\n const isAbortError
|
|
1
|
+
{"version":3,"file":"FetchMixin.js","names":["fetchPromise: Promise<Response>"],"sources":["../../src/elements/FetchMixin.ts"],"sourcesContent":["import type { LitElement } from \"lit\";\n\nexport declare class FetchMixinInterface {\n fetch: typeof fetch;\n}\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\nexport function FetchMixin<T extends Constructor<LitElement>>(superClass: T) {\n class FetchElement extends superClass {\n fetch = (url: string, init?: RequestInit): Promise<Response> => {\n try {\n let fetchPromise: Promise<Response>;\n\n // Look for context providers up the DOM tree\n const workbench = this.closest(\"ef-workbench\") as any;\n if (workbench?.fetch) {\n fetchPromise = workbench.fetch(url, init);\n } else {\n const preview = this.closest(\"ef-preview\") as any;\n if (preview?.fetch) {\n fetchPromise = preview.fetch(url, init);\n } else {\n const configuration = this.closest(\"ef-configuration\") as any;\n if (configuration?.fetch) {\n fetchPromise = configuration.fetch(url, init);\n } else {\n // Fallback to window.fetch\n fetchPromise = window.fetch(url, init);\n }\n }\n }\n\n // Wrap the promise to catch rejections and log the URL\n // Return the promise chain so errors are logged but still propagate\n return fetchPromise.catch((error) => {\n // Don't log AbortError - these are intentional request cancellations\n const isAbortError =\n error instanceof Error &&\n (error.name === \"AbortError\" ||\n error.message.includes(\"signal is aborted\") ||\n error.message.includes(\"The user aborted a request\"));\n\n // Don't log errors if element is disconnected from DOM\n // This happens during scenario transitions when elements are removed mid-fetch\n // The browser throws TypeError: \"Failed to fetch\" when the page navigates\n const isDisconnected = !this.isConnected;\n\n // Also suppress \"Failed to fetch\" TypeError when disconnected\n // These occur when the browser aborts a request due to page navigation,\n // but doesn't throw a proper AbortError\n const isNavigationAbort =\n isDisconnected &&\n error instanceof TypeError &&\n error.message === \"Failed to fetch\";\n\n // For AbortErrors, navigation aborts, and disconnected elements,\n // re-throw the original error without enhancement to preserve error type\n if (isAbortError || isNavigationAbort || isDisconnected) {\n throw error;\n }\n\n // Log unexpected errors\n console.error(\n \"FetchMixin fetch error\",\n url,\n error,\n window.location.href,\n );\n\n // Create a new error with the URL in the message, preserving the original error type\n const ErrorConstructor =\n error instanceof Error ? error.constructor : Error;\n const enhancedError = new (ErrorConstructor as typeof Error)(\n `Failed to fetch: ${url}. Original error: ${error instanceof Error ? error.message : String(error)}`,\n );\n // Preserve the original error's properties\n if (error instanceof Error) {\n // Some error types (like DOMException) have read-only name property\n // Use try-catch to handle cases where name cannot be set\n try {\n enhancedError.name = error.name;\n } catch {\n // If name is read-only, use Object.defineProperty as fallback\n try {\n Object.defineProperty(enhancedError, \"name\", {\n value: error.name,\n writable: true,\n enumerable: false,\n configurable: true,\n });\n } catch {\n // If that also fails, just skip setting name\n }\n }\n enhancedError.stack = error.stack;\n // Copy any additional properties from the original error\n Object.assign(enhancedError, error);\n }\n throw enhancedError;\n });\n } catch (error) {\n console.error(\"FetchMixin error (synchronous)\", url, error);\n throw error;\n }\n };\n }\n\n return FetchElement as Constructor<FetchMixinInterface> & T;\n}\n"],"mappings":";AAOA,SAAgB,WAA8C,YAAe;CAC3E,MAAM,qBAAqB,WAAW;;;iBAC3B,KAAa,SAA0C;AAC9D,QAAI;KACF,IAAIA;KAGJ,MAAM,YAAY,KAAK,QAAQ,eAAe;AAC9C,SAAI,WAAW,MACb,gBAAe,UAAU,MAAM,KAAK,KAAK;UACpC;MACL,MAAM,UAAU,KAAK,QAAQ,aAAa;AAC1C,UAAI,SAAS,MACX,gBAAe,QAAQ,MAAM,KAAK,KAAK;WAClC;OACL,MAAM,gBAAgB,KAAK,QAAQ,mBAAmB;AACtD,WAAI,eAAe,MACjB,gBAAe,cAAc,MAAM,KAAK,KAAK;WAG7C,gBAAe,OAAO,MAAM,KAAK,KAAK;;;AAO5C,YAAO,aAAa,OAAO,UAAU;MAEnC,MAAM,eACJ,iBAAiB,UAChB,MAAM,SAAS,gBACd,MAAM,QAAQ,SAAS,oBAAoB,IAC3C,MAAM,QAAQ,SAAS,6BAA6B;MAKxD,MAAM,iBAAiB,CAAC,KAAK;MAK7B,MAAM,oBACJ,kBACA,iBAAiB,aACjB,MAAM,YAAY;AAIpB,UAAI,gBAAgB,qBAAqB,eACvC,OAAM;AAIR,cAAQ,MACN,0BACA,KACA,OACA,OAAO,SAAS,KACjB;MAKD,MAAM,gBAAgB,KADpB,iBAAiB,QAAQ,MAAM,cAAc,OAE7C,oBAAoB,IAAI,oBAAoB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACnG;AAED,UAAI,iBAAiB,OAAO;AAG1B,WAAI;AACF,sBAAc,OAAO,MAAM;eACrB;AAEN,YAAI;AACF,gBAAO,eAAe,eAAe,QAAQ;UAC3C,OAAO,MAAM;UACb,UAAU;UACV,YAAY;UACZ,cAAc;UACf,CAAC;gBACI;;AAIV,qBAAc,QAAQ,MAAM;AAE5B,cAAO,OAAO,eAAe,MAAM;;AAErC,YAAM;OACN;aACK,OAAO;AACd,aAAQ,MAAM,kCAAkC,KAAK,MAAM;AAC3D,WAAM;;;;;AAKZ,QAAO"}
|
|
@@ -4,7 +4,6 @@ import { LitElement, ReactiveController } from "lit";
|
|
|
4
4
|
|
|
5
5
|
declare class TargetController implements ReactiveController {
|
|
6
6
|
private host;
|
|
7
|
-
private targetController;
|
|
8
7
|
private currentTargetString;
|
|
9
8
|
constructor(host: LitElement & {
|
|
10
9
|
targetElement: Element | null;
|
|
@@ -12,8 +11,6 @@ declare class TargetController implements ReactiveController {
|
|
|
12
11
|
});
|
|
13
12
|
private registryCallback;
|
|
14
13
|
private updateTarget;
|
|
15
|
-
private connectToTarget;
|
|
16
|
-
private disconnectFromTarget;
|
|
17
14
|
private get registry();
|
|
18
15
|
hostDisconnected(): void;
|
|
19
16
|
hostConnected(): void;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { LitElement } from "lit";
|
|
2
|
-
|
|
3
1
|
//#region src/elements/TargetController.ts
|
|
4
2
|
const EF_TARGETABLE = Symbol("EF_TARGETABLE");
|
|
5
3
|
var TargetRegistry = class {
|
|
@@ -73,23 +71,8 @@ const EFTargetable = (superClass) => {
|
|
|
73
71
|
Object.defineProperty(TargetableElement.prototype, EF_TARGETABLE, { value: true });
|
|
74
72
|
return TargetableElement;
|
|
75
73
|
};
|
|
76
|
-
var TargetUpdateController = class {
|
|
77
|
-
constructor(host) {
|
|
78
|
-
this.host = host;
|
|
79
|
-
}
|
|
80
|
-
hostConnected() {
|
|
81
|
-
this.host.requestUpdate();
|
|
82
|
-
}
|
|
83
|
-
hostDisconnected() {
|
|
84
|
-
this.host.requestUpdate();
|
|
85
|
-
}
|
|
86
|
-
hostUpdate() {
|
|
87
|
-
this.host.requestUpdate();
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
74
|
var TargetController = class {
|
|
91
75
|
constructor(host) {
|
|
92
|
-
this.targetController = null;
|
|
93
76
|
this.currentTargetString = null;
|
|
94
77
|
this.registryCallback = (target) => {
|
|
95
78
|
this.host.targetElement = target ?? null;
|
|
@@ -100,34 +83,28 @@ var TargetController = class {
|
|
|
100
83
|
if (this.currentTargetString) this.registry.subscribe(this.currentTargetString, this.registryCallback);
|
|
101
84
|
}
|
|
102
85
|
updateTarget() {
|
|
103
|
-
if (!this.host.target)
|
|
86
|
+
if (!this.host.target) {
|
|
87
|
+
if (this.host.targetElement !== null) {
|
|
88
|
+
this.host.targetElement = null;
|
|
89
|
+
this.host.requestUpdate("targetElement");
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
104
93
|
let newTarget = this.registry.get(this.host.target);
|
|
94
|
+
if (!newTarget) {
|
|
95
|
+
const container = this.host.closest("ef-timegroup, ef-configuration") || this.host.getRootNode();
|
|
96
|
+
if (container && "querySelector" in container) newTarget = container.querySelector(`#${CSS.escape(this.host.target)}`);
|
|
97
|
+
}
|
|
105
98
|
if (!newTarget) newTarget = document.getElementById(this.host.target);
|
|
106
99
|
if (this.host.targetElement !== newTarget) {
|
|
107
|
-
this.disconnectFromTarget();
|
|
108
100
|
this.host.targetElement = newTarget ?? null;
|
|
109
|
-
this.connectToTarget();
|
|
110
101
|
this.host.requestUpdate("targetElement");
|
|
111
102
|
}
|
|
112
103
|
}
|
|
113
|
-
connectToTarget() {
|
|
114
|
-
if (this.host.targetElement instanceof LitElement) {
|
|
115
|
-
this.targetController = new TargetUpdateController(this.host);
|
|
116
|
-
this.host.targetElement.addController(this.targetController);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
disconnectFromTarget() {
|
|
120
|
-
if (this.host.targetElement instanceof LitElement && this.targetController) {
|
|
121
|
-
this.host.targetElement.removeController(this.targetController);
|
|
122
|
-
this.targetController = null;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
104
|
get registry() {
|
|
126
105
|
return getRegistry(this.host.getRootNode());
|
|
127
106
|
}
|
|
128
|
-
hostDisconnected() {
|
|
129
|
-
this.disconnectFromTarget();
|
|
130
|
-
}
|
|
107
|
+
hostDisconnected() {}
|
|
131
108
|
hostConnected() {
|
|
132
109
|
this.updateTarget();
|
|
133
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TargetController.js","names":["#registry"
|
|
1
|
+
{"version":3,"file":"TargetController.js","names":["#registry"],"sources":["../../src/elements/TargetController.ts"],"sourcesContent":["import { LitElement, type ReactiveController } from \"lit\";\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n// Symbol to identify elements that can be targeted\nconst EF_TARGETABLE = Symbol(\"EF_TARGETABLE\");\n\nclass TargetRegistry {\n private idMap = new Map<string, LitElement>();\n private callbacks = new Map<\n string,\n Set<(target: LitElement | undefined) => void>\n >();\n\n subscribe(id: string, callback: (target: LitElement | undefined) => void) {\n this.callbacks.set(id, this.callbacks.get(id) ?? new Set());\n this.callbacks.get(id)?.add(callback);\n }\n\n unsubscribe(\n id: string | null,\n callback: (target: LitElement | undefined) => void,\n ) {\n if (id === null) {\n return;\n }\n this.callbacks.get(id)?.delete(callback);\n if (this.callbacks.get(id)?.size === 0) {\n this.callbacks.delete(id);\n }\n }\n\n get(id: string) {\n return this.idMap.get(id);\n }\n\n register(id: string, target: LitElement) {\n this.idMap.set(id, target);\n for (const callback of this.callbacks.get(id) ?? []) {\n callback(target);\n }\n }\n\n unregister(id: string, target: LitElement) {\n if (this.idMap.get(id) !== target) {\n // Avoid unregistering a target that is not the current target\n return;\n }\n for (const callback of this.callbacks.get(id) ?? []) {\n callback(undefined);\n }\n this.idMap.delete(id);\n this.callbacks.delete(id);\n }\n}\n\n// Map of root nodes to their target registries\nconst documentRegistries = new WeakMap<Node, TargetRegistry>();\n\nconst getRegistry = (root: Node) => {\n let registry = documentRegistries.get(root);\n if (!registry) {\n registry = new TargetRegistry();\n documentRegistries.set(root, registry);\n }\n return registry;\n};\n\nexport declare class TargetableMixinInterface {\n id: string;\n}\n\nexport const isEFTargetable = (obj: any): obj is TargetableMixinInterface =>\n obj[EF_TARGETABLE];\n\nexport const EFTargetable = <T extends Constructor<LitElement>>(\n superClass: T,\n) => {\n class TargetableElement extends superClass {\n #registry: TargetRegistry | null = null;\n\n static get observedAttributes(): string[] {\n // Get parent's observed attributes\n const parentAttributes = (superClass as any).observedAttributes || [];\n // Add 'id' if not already present\n return [...new Set([...parentAttributes, \"id\"])];\n }\n\n private updateRegistry(oldValue: string, newValue: string) {\n if (!this.#registry) return;\n if (oldValue === newValue) return;\n\n if (oldValue) {\n this.#registry.unregister(oldValue, this);\n }\n if (newValue) {\n this.#registry.register(newValue, this);\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.#registry = getRegistry(this.getRootNode());\n const initialId = this.getAttribute(\"id\");\n if (initialId) {\n this.updateRegistry(\"\", initialId);\n }\n }\n\n attributeChangedCallback(\n name: string,\n old: string | null,\n value: string | null,\n ) {\n super.attributeChangedCallback(name, old, value);\n if (name === \"id\") {\n this.updateRegistry(old ?? \"\", value ?? \"\");\n }\n }\n\n disconnectedCallback() {\n if (this.#registry) {\n this.updateRegistry(this.id, \"\");\n this.#registry = null;\n }\n super.disconnectedCallback();\n }\n }\n\n Object.defineProperty(TargetableElement.prototype, EF_TARGETABLE, {\n value: true,\n });\n\n return TargetableElement as T;\n};\n\nexport class TargetController implements ReactiveController {\n private host: LitElement & { targetElement: Element | null; target: string };\n private currentTargetString: string | null = null;\n\n constructor(\n host: LitElement & { targetElement: Element | null; target: string },\n ) {\n this.host = host;\n this.host.addController(this);\n this.currentTargetString = this.host.target;\n if (this.currentTargetString) {\n this.registry.subscribe(this.currentTargetString, this.registryCallback);\n }\n }\n\n private registryCallback = (target: LitElement | undefined) => {\n this.host.targetElement = target ?? null;\n };\n\n private updateTarget() {\n if (!this.host.target) {\n if (this.host.targetElement !== null) {\n this.host.targetElement = null;\n this.host.requestUpdate(\"targetElement\");\n }\n return;\n }\n\n let newTarget = this.registry.get(this.host.target);\n\n if (!newTarget) {\n const container =\n (this.host as Element).closest(\"ef-timegroup, ef-configuration\") ||\n (this.host as Element).getRootNode();\n\n if (container && \"querySelector\" in container) {\n newTarget = (container as Element).querySelector(\n `#${CSS.escape(this.host.target)}`,\n ) as LitElement | undefined;\n }\n }\n\n if (!newTarget) {\n newTarget = document.getElementById(this.host.target) as\n | LitElement\n | undefined;\n }\n\n if (this.host.targetElement !== newTarget) {\n this.host.targetElement = newTarget ?? (null as Element | null);\n this.host.requestUpdate(\"targetElement\");\n }\n }\n\n private get registry() {\n const root = this.host.getRootNode();\n return getRegistry(root);\n }\n\n hostDisconnected() {}\n\n hostConnected() {\n this.updateTarget();\n }\n\n hostUpdate() {\n if (this.currentTargetString !== this.host.target) {\n this.registry.unsubscribe(\n this.currentTargetString,\n this.registryCallback,\n );\n this.registry.subscribe(this.host.target, this.registryCallback);\n this.updateTarget();\n this.currentTargetString = this.host.target;\n }\n }\n}\n"],"mappings":";AAKA,MAAM,gBAAgB,OAAO,gBAAgB;AAE7C,IAAM,iBAAN,MAAqB;;+BACH,IAAI,KAAyB;mCACzB,IAAI,KAGrB;;CAEH,UAAU,IAAY,UAAoD;AACxE,OAAK,UAAU,IAAI,IAAI,KAAK,UAAU,IAAI,GAAG,oBAAI,IAAI,KAAK,CAAC;AAC3D,OAAK,UAAU,IAAI,GAAG,EAAE,IAAI,SAAS;;CAGvC,YACE,IACA,UACA;AACA,MAAI,OAAO,KACT;AAEF,OAAK,UAAU,IAAI,GAAG,EAAE,OAAO,SAAS;AACxC,MAAI,KAAK,UAAU,IAAI,GAAG,EAAE,SAAS,EACnC,MAAK,UAAU,OAAO,GAAG;;CAI7B,IAAI,IAAY;AACd,SAAO,KAAK,MAAM,IAAI,GAAG;;CAG3B,SAAS,IAAY,QAAoB;AACvC,OAAK,MAAM,IAAI,IAAI,OAAO;AAC1B,OAAK,MAAM,YAAY,KAAK,UAAU,IAAI,GAAG,IAAI,EAAE,CACjD,UAAS,OAAO;;CAIpB,WAAW,IAAY,QAAoB;AACzC,MAAI,KAAK,MAAM,IAAI,GAAG,KAAK,OAEzB;AAEF,OAAK,MAAM,YAAY,KAAK,UAAU,IAAI,GAAG,IAAI,EAAE,CACjD,UAAS,OAAU;AAErB,OAAK,MAAM,OAAO,GAAG;AACrB,OAAK,UAAU,OAAO,GAAG;;;AAK7B,MAAM,qCAAqB,IAAI,SAA+B;AAE9D,MAAM,eAAe,SAAe;CAClC,IAAI,WAAW,mBAAmB,IAAI,KAAK;AAC3C,KAAI,CAAC,UAAU;AACb,aAAW,IAAI,gBAAgB;AAC/B,qBAAmB,IAAI,MAAM,SAAS;;AAExC,QAAO;;AAUT,MAAa,gBACX,eACG;CACH,MAAM,0BAA0B,WAAW;EACzC,YAAmC;EAEnC,WAAW,qBAA+B;GAExC,MAAM,mBAAoB,WAAmB,sBAAsB,EAAE;AAErE,UAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,kBAAkB,KAAK,CAAC,CAAC;;EAGlD,AAAQ,eAAe,UAAkB,UAAkB;AACzD,OAAI,CAAC,MAAKA,SAAW;AACrB,OAAI,aAAa,SAAU;AAE3B,OAAI,SACF,OAAKA,SAAU,WAAW,UAAU,KAAK;AAE3C,OAAI,SACF,OAAKA,SAAU,SAAS,UAAU,KAAK;;EAI3C,oBAAoB;AAClB,SAAM,mBAAmB;AACzB,SAAKA,WAAY,YAAY,KAAK,aAAa,CAAC;GAChD,MAAM,YAAY,KAAK,aAAa,KAAK;AACzC,OAAI,UACF,MAAK,eAAe,IAAI,UAAU;;EAItC,yBACE,MACA,KACA,OACA;AACA,SAAM,yBAAyB,MAAM,KAAK,MAAM;AAChD,OAAI,SAAS,KACX,MAAK,eAAe,OAAO,IAAI,SAAS,GAAG;;EAI/C,uBAAuB;AACrB,OAAI,MAAKA,UAAW;AAClB,SAAK,eAAe,KAAK,IAAI,GAAG;AAChC,UAAKA,WAAY;;AAEnB,SAAM,sBAAsB;;;AAIhC,QAAO,eAAe,kBAAkB,WAAW,eAAe,EAChE,OAAO,MACR,CAAC;AAEF,QAAO;;AAGT,IAAa,mBAAb,MAA4D;CAI1D,YACE,MACA;6BAJ2C;2BAajB,WAAmC;AAC7D,QAAK,KAAK,gBAAgB,UAAU;;AATpC,OAAK,OAAO;AACZ,OAAK,KAAK,cAAc,KAAK;AAC7B,OAAK,sBAAsB,KAAK,KAAK;AACrC,MAAI,KAAK,oBACP,MAAK,SAAS,UAAU,KAAK,qBAAqB,KAAK,iBAAiB;;CAQ5E,AAAQ,eAAe;AACrB,MAAI,CAAC,KAAK,KAAK,QAAQ;AACrB,OAAI,KAAK,KAAK,kBAAkB,MAAM;AACpC,SAAK,KAAK,gBAAgB;AAC1B,SAAK,KAAK,cAAc,gBAAgB;;AAE1C;;EAGF,IAAI,YAAY,KAAK,SAAS,IAAI,KAAK,KAAK,OAAO;AAEnD,MAAI,CAAC,WAAW;GACd,MAAM,YACH,KAAK,KAAiB,QAAQ,iCAAiC,IAC/D,KAAK,KAAiB,aAAa;AAEtC,OAAI,aAAa,mBAAmB,UAClC,aAAa,UAAsB,cACjC,IAAI,IAAI,OAAO,KAAK,KAAK,OAAO,GACjC;;AAIL,MAAI,CAAC,UACH,aAAY,SAAS,eAAe,KAAK,KAAK,OAAO;AAKvD,MAAI,KAAK,KAAK,kBAAkB,WAAW;AACzC,QAAK,KAAK,gBAAgB,aAAc;AACxC,QAAK,KAAK,cAAc,gBAAgB;;;CAI5C,IAAY,WAAW;AAErB,SAAO,YADM,KAAK,KAAK,aAAa,CACZ;;CAG1B,mBAAmB;CAEnB,gBAAgB;AACd,OAAK,cAAc;;CAGrB,aAAa;AACX,MAAI,KAAK,wBAAwB,KAAK,KAAK,QAAQ;AACjD,QAAK,SAAS,YACZ,KAAK,qBACL,KAAK,iBACN;AACD,QAAK,SAAS,UAAU,KAAK,KAAK,QAAQ,KAAK,iBAAiB;AAChE,QAAK,cAAc;AACnB,QAAK,sBAAsB,KAAK,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimegroupController.js","names":["host: EFTimegroup","child: { currentTimeMs: number; startTimeMs?: number } & LitElement"],"sources":["../../src/elements/TimegroupController.ts"],"sourcesContent":["import type { LitElement, ReactiveController } from \"lit\";\nimport type { EFTimegroup } from \"./EFTimegroup.js\";\n\nexport class TimegroupController implements ReactiveController {\n constructor(\n private host: EFTimegroup,\n private child: { currentTimeMs: number; startTimeMs?: number } & LitElement,\n ) {\n this.host.addController(this);\n }\n\n remove() {\n this.host.removeController(this);\n }\n\n hostDisconnected(): void {\n this.host.removeController(this);\n }\n\n hostUpdated(): void {\n // Defer update to avoid Lit warning about scheduling updates after update completed\n // This batches updates and prevents cascading update cycles\n Promise.resolve().then(() => {\n // Skip setting currentTimeMs for timegroup children - they compute ownCurrentTimeMs\n // from the root timegroup via EFTemporal. Setting it directly causes an infinite loop\n // because the @property decorator on currentTime triggers reactive updates.\n if (
|
|
1
|
+
{"version":3,"file":"TimegroupController.js","names":["host: EFTimegroup","child: { currentTimeMs: number; startTimeMs?: number } & LitElement"],"sources":["../../src/elements/TimegroupController.ts"],"sourcesContent":["import type { LitElement, ReactiveController } from \"lit\";\nimport type { EFTimegroup } from \"./EFTimegroup.js\";\n\nexport class TimegroupController implements ReactiveController {\n constructor(\n private host: EFTimegroup,\n private child: { currentTimeMs: number; startTimeMs?: number } & LitElement,\n ) {\n this.host.addController(this);\n }\n\n remove() {\n this.host.removeController(this);\n }\n\n hostDisconnected(): void {\n this.host.removeController(this);\n }\n\n hostUpdated(): void {\n // Defer update to avoid Lit warning about scheduling updates after update completed\n // This batches updates and prevents cascading update cycles\n Promise.resolve().then(() => {\n // Skip setting currentTimeMs for timegroup children - they compute ownCurrentTimeMs\n // from the root timegroup via EFTemporal. Setting it directly causes an infinite loop\n // because the @property decorator on currentTime triggers reactive updates.\n if (\"mode\" in this.child && \"isRootTimegroup\" in this.child) {\n // Child is a timegroup - just request update, don't set currentTimeMs\n this.child.requestUpdate();\n return;\n }\n\n this.child.requestUpdate();\n const newChildTimeMs =\n this.host.currentTimeMs - (this.child.startTimeMs ?? 0);\n this.child.currentTimeMs = newChildTimeMs;\n });\n }\n}\n"],"mappings":";AAGA,IAAa,sBAAb,MAA+D;CAC7D,YACE,AAAQA,MACR,AAAQC,OACR;EAFQ;EACA;AAER,OAAK,KAAK,cAAc,KAAK;;CAG/B,SAAS;AACP,OAAK,KAAK,iBAAiB,KAAK;;CAGlC,mBAAyB;AACvB,OAAK,KAAK,iBAAiB,KAAK;;CAGlC,cAAoB;AAGlB,UAAQ,SAAS,CAAC,WAAW;AAI3B,OAAI,UAAU,KAAK,SAAS,qBAAqB,KAAK,OAAO;AAE3D,SAAK,MAAM,eAAe;AAC1B;;AAGF,QAAK,MAAM,eAAe;GAC1B,MAAM,iBACJ,KAAK,KAAK,iBAAiB,KAAK,MAAM,eAAe;AACvD,QAAK,MAAM,gBAAgB;IAC3B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EFTimegroup } from "./EFTimegroup.js";
|
|
2
|
+
|
|
3
|
+
//#region src/elements/cloneFactoryRegistry.d.ts
|
|
4
|
+
type CloneFactoryResult = {
|
|
5
|
+
timegroup: EFTimegroup;
|
|
6
|
+
cleanup: () => void;
|
|
7
|
+
};
|
|
8
|
+
type CloneFactory = (container: HTMLElement) => CloneFactoryResult;
|
|
9
|
+
declare function registerCloneFactory(element: EFTimegroup, factory: CloneFactory): void;
|
|
10
|
+
declare function unregisterCloneFactory(element: EFTimegroup): void;
|
|
11
|
+
declare function getCloneFactory(element: EFTimegroup): CloneFactory | undefined;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { CloneFactory, CloneFactoryResult, getCloneFactory, registerCloneFactory, unregisterCloneFactory };
|
|
14
|
+
//# sourceMappingURL=cloneFactoryRegistry.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/elements/cloneFactoryRegistry.ts
|
|
2
|
+
const registry = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function registerCloneFactory(element, factory) {
|
|
4
|
+
registry.set(element, factory);
|
|
5
|
+
}
|
|
6
|
+
function unregisterCloneFactory(element) {
|
|
7
|
+
registry.delete(element);
|
|
8
|
+
}
|
|
9
|
+
function getCloneFactory(element) {
|
|
10
|
+
return registry.get(element);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { getCloneFactory, registerCloneFactory, unregisterCloneFactory };
|
|
15
|
+
//# sourceMappingURL=cloneFactoryRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloneFactoryRegistry.js","names":[],"sources":["../../src/elements/cloneFactoryRegistry.ts"],"sourcesContent":["import type { EFTimegroup } from \"./EFTimegroup.js\";\n\nexport type CloneFactoryResult = {\n timegroup: EFTimegroup;\n cleanup: () => void;\n};\n\nexport type CloneFactory = (container: HTMLElement) => CloneFactoryResult;\n\nconst registry = new WeakMap<EFTimegroup, CloneFactory>();\n\nexport function registerCloneFactory(\n element: EFTimegroup,\n factory: CloneFactory,\n): void {\n registry.set(element, factory);\n}\n\nexport function unregisterCloneFactory(element: EFTimegroup): void {\n registry.delete(element);\n}\n\nexport function getCloneFactory(\n element: EFTimegroup,\n): CloneFactory | undefined {\n return registry.get(element);\n}\n"],"mappings":";AASA,MAAM,2BAAW,IAAI,SAAoC;AAEzD,SAAgB,qBACd,SACA,SACM;AACN,UAAS,IAAI,SAAS,QAAQ;;AAGhC,SAAgB,uBAAuB,SAA4B;AACjE,UAAS,OAAO,QAAQ;;AAG1B,SAAgB,gBACd,SAC0B;AAC1B,QAAO,SAAS,IAAI,QAAQ"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { logger } from "../preview/logger.js";
|
|
2
|
+
|
|
1
3
|
//#region src/elements/renderTemporalAudio.ts
|
|
2
4
|
async function renderTemporalAudio(host, fromMs, toMs, signal) {
|
|
3
5
|
const aacFrames = 48e3 * ((toMs - fromMs) / 1e3) / 1024;
|
|
@@ -10,14 +12,14 @@ async function renderTemporalAudio(host, fromMs, toMs, signal) {
|
|
|
10
12
|
signal?.throwIfAborted();
|
|
11
13
|
}
|
|
12
14
|
const mediaElements = host.getMediaElements();
|
|
13
|
-
|
|
15
|
+
logger.debug(`[renderTemporalAudio] Found ${mediaElements.length} media elements, time range: ${fromMs}-${toMs}ms`);
|
|
14
16
|
await Promise.all(mediaElements.map(async (mediaElement) => {
|
|
15
|
-
|
|
17
|
+
logger.debug(`[renderTemporalAudio] Checking ${mediaElement.tagName} at ${mediaElement.startTimeMs}-${mediaElement.endTimeMs}ms, mute=${mediaElement.mute}`);
|
|
16
18
|
if (mediaElement.mute) return;
|
|
17
19
|
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
18
20
|
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
19
21
|
if (!(mediaStartsBeforeEnd && mediaEndsAfterStart)) {
|
|
20
|
-
|
|
22
|
+
logger.debug(`[renderTemporalAudio] ${mediaElement.tagName} does not overlap`);
|
|
21
23
|
return;
|
|
22
24
|
}
|
|
23
25
|
const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
|
|
@@ -27,13 +29,13 @@ async function renderTemporalAudio(host, fromMs, toMs, signal) {
|
|
|
27
29
|
const mediaSourceFromMs = mediaLocalFromMs + sourceInMs;
|
|
28
30
|
const mediaSourceToMs = mediaLocalToMs + sourceInMs;
|
|
29
31
|
signal?.throwIfAborted();
|
|
30
|
-
|
|
32
|
+
logger.debug(`[renderTemporalAudio] Fetching audio for ${mediaElement.tagName} from ${mediaSourceFromMs}-${mediaSourceToMs}ms`);
|
|
31
33
|
const audio = await mediaElement.fetchAudioSpanningTime(mediaSourceFromMs, mediaSourceToMs, signal);
|
|
32
34
|
if (!audio) {
|
|
33
|
-
|
|
35
|
+
logger.debug(`[renderTemporalAudio] No audio returned for ${mediaElement.tagName}`);
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
logger.debug(`[renderTemporalAudio] Got audio blob size: ${audio.blob.size}, range: ${audio.startMs}-${audio.endMs}ms`);
|
|
37
39
|
const bufferSource = audioContext.createBufferSource();
|
|
38
40
|
let decodedBuffer;
|
|
39
41
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderTemporalAudio.js","names":[],"sources":["../../src/elements/renderTemporalAudio.ts"],"sourcesContent":["import type { EFMedia } from \"./EFMedia.js\";\n\ninterface TemporalAudioHost {\n startTimeMs: number;\n endTimeMs: number;\n durationMs: number;\n getMediaElements(): EFMedia[];\n waitForMediaDurations?(): Promise<void>;\n}\n\nexport async function renderTemporalAudio(\n host: TemporalAudioHost,\n fromMs: number,\n toMs: number,\n signal?: AbortSignal,\n): Promise<AudioBuffer> {\n const durationMs = toMs - fromMs;\n const duration = durationMs / 1000;\n const exactSamples = 48000 * duration;\n const aacFrames = exactSamples / 1024;\n const alignedFrames = Math.round(aacFrames);\n const contextSize = alignedFrames * 1024;\n\n if (contextSize <= 0) {\n throw new Error(\n `Duration must be greater than 0 when rendering audio. ${contextSize}ms`,\n );\n }\n\n // Check abort before starting\n signal?.throwIfAborted();\n\n const audioContext = new OfflineAudioContext(2, contextSize, 48000);\n\n if (host.waitForMediaDurations) {\n await host.waitForMediaDurations();\n // Check abort after potentially slow operation\n signal?.throwIfAborted();\n }\n\n const mediaElements = host.getMediaElements();\n
|
|
1
|
+
{"version":3,"file":"renderTemporalAudio.js","names":[],"sources":["../../src/elements/renderTemporalAudio.ts"],"sourcesContent":["import type { EFMedia } from \"./EFMedia.js\";\nimport { logger } from \"../preview/logger.js\";\n\ninterface TemporalAudioHost {\n startTimeMs: number;\n endTimeMs: number;\n durationMs: number;\n getMediaElements(): EFMedia[];\n waitForMediaDurations?(): Promise<void>;\n}\n\nexport async function renderTemporalAudio(\n host: TemporalAudioHost,\n fromMs: number,\n toMs: number,\n signal?: AbortSignal,\n): Promise<AudioBuffer> {\n const durationMs = toMs - fromMs;\n const duration = durationMs / 1000;\n const exactSamples = 48000 * duration;\n const aacFrames = exactSamples / 1024;\n const alignedFrames = Math.round(aacFrames);\n const contextSize = alignedFrames * 1024;\n\n if (contextSize <= 0) {\n throw new Error(\n `Duration must be greater than 0 when rendering audio. ${contextSize}ms`,\n );\n }\n\n // Check abort before starting\n signal?.throwIfAborted();\n\n const audioContext = new OfflineAudioContext(2, contextSize, 48000);\n\n if (host.waitForMediaDurations) {\n await host.waitForMediaDurations();\n // Check abort after potentially slow operation\n signal?.throwIfAborted();\n }\n\n const mediaElements = host.getMediaElements();\n logger.debug(\n `[renderTemporalAudio] Found ${mediaElements.length} media elements, time range: ${fromMs}-${toMs}ms`,\n );\n\n await Promise.all(\n mediaElements.map(async (mediaElement) => {\n logger.debug(\n `[renderTemporalAudio] Checking ${mediaElement.tagName} at ${mediaElement.startTimeMs}-${mediaElement.endTimeMs}ms, mute=${mediaElement.mute}`,\n );\n\n if (mediaElement.mute) {\n return;\n }\n\n const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;\n const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;\n const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;\n if (!mediaOverlaps) {\n logger.debug(\n `[renderTemporalAudio] ${mediaElement.tagName} does not overlap`,\n );\n return;\n }\n\n const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);\n const mediaLocalToMs = Math.min(\n mediaElement.endTimeMs - mediaElement.startTimeMs,\n toMs - mediaElement.startTimeMs,\n );\n\n if (mediaLocalFromMs >= mediaLocalToMs) {\n return;\n }\n\n const sourceInMs =\n mediaElement.sourceInMs || mediaElement.trimStartMs || 0;\n const mediaSourceFromMs = mediaLocalFromMs + sourceInMs;\n const mediaSourceToMs = mediaLocalToMs + sourceInMs;\n\n // Check abort before processing each media element\n signal?.throwIfAborted();\n\n logger.debug(\n `[renderTemporalAudio] Fetching audio for ${mediaElement.tagName} from ${mediaSourceFromMs}-${mediaSourceToMs}ms`,\n );\n const audio = await mediaElement.fetchAudioSpanningTime(\n mediaSourceFromMs,\n mediaSourceToMs,\n signal,\n );\n if (!audio) {\n logger.debug(\n `[renderTemporalAudio] No audio returned for ${mediaElement.tagName}`,\n );\n return;\n }\n logger.debug(\n `[renderTemporalAudio] Got audio blob size: ${audio.blob.size}, range: ${audio.startMs}-${audio.endMs}ms`,\n );\n\n const bufferSource = audioContext.createBufferSource();\n\n // Decode audio data with error handling for invalid/incomplete audio\n let decodedBuffer;\n try {\n const arrayBuffer = await audio.blob.arrayBuffer();\n // Skip if buffer is too small to be valid audio\n if (arrayBuffer.byteLength < 100) {\n return;\n }\n decodedBuffer = await audioContext.decodeAudioData(arrayBuffer);\n } catch (decodeError) {\n // Unable to decode audio data - skip this segment silently\n // This can happen with corrupted/incomplete audio segments\n if (\n decodeError instanceof Error &&\n decodeError.message.includes(\"Unable to decode audio data\")\n ) {\n return;\n }\n throw decodeError;\n }\n\n bufferSource.buffer = decodedBuffer;\n bufferSource.connect(audioContext.destination);\n\n const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);\n\n const requestedSourceFromMs = mediaSourceFromMs;\n const actualSourceStartMs = audio.startMs;\n const offsetInBufferMs = requestedSourceFromMs - actualSourceStartMs;\n\n const safeOffsetMs = Math.max(0, offsetInBufferMs);\n\n const requestedDurationMs = mediaSourceToMs - mediaSourceFromMs;\n const availableAudioMs = audio.endMs - audio.startMs;\n const actualDurationMs = Math.min(\n requestedDurationMs,\n availableAudioMs - safeOffsetMs,\n );\n\n if (actualDurationMs <= 0) {\n return;\n }\n\n bufferSource.start(\n ctxStartMs / 1000,\n safeOffsetMs / 1000,\n actualDurationMs / 1000,\n );\n }),\n );\n\n return audioContext.startRendering();\n}\n"],"mappings":";;;AAWA,eAAsB,oBACpB,MACA,QACA,MACA,QACsB;CAItB,MAAM,YADe,SAFF,OAAO,UACI,OAEG;CAEjC,MAAM,cADgB,KAAK,MAAM,UAAU,GACP;AAEpC,KAAI,eAAe,EACjB,OAAM,IAAI,MACR,yDAAyD,YAAY,IACtE;AAIH,SAAQ,gBAAgB;CAExB,MAAM,eAAe,IAAI,oBAAoB,GAAG,aAAa,KAAM;AAEnE,KAAI,KAAK,uBAAuB;AAC9B,QAAM,KAAK,uBAAuB;AAElC,UAAQ,gBAAgB;;CAG1B,MAAM,gBAAgB,KAAK,kBAAkB;AAC7C,QAAO,MACL,+BAA+B,cAAc,OAAO,+BAA+B,OAAO,GAAG,KAAK,IACnG;AAED,OAAM,QAAQ,IACZ,cAAc,IAAI,OAAO,iBAAiB;AACxC,SAAO,MACL,kCAAkC,aAAa,QAAQ,MAAM,aAAa,YAAY,GAAG,aAAa,UAAU,WAAW,aAAa,OACzI;AAED,MAAI,aAAa,KACf;EAGF,MAAM,uBAAuB,aAAa,eAAe;EACzD,MAAM,sBAAsB,aAAa,aAAa;AAEtD,MAAI,EADkB,wBAAwB,sBAC1B;AAClB,UAAO,MACL,yBAAyB,aAAa,QAAQ,mBAC/C;AACD;;EAGF,MAAM,mBAAmB,KAAK,IAAI,GAAG,SAAS,aAAa,YAAY;EACvE,MAAM,iBAAiB,KAAK,IAC1B,aAAa,YAAY,aAAa,aACtC,OAAO,aAAa,YACrB;AAED,MAAI,oBAAoB,eACtB;EAGF,MAAM,aACJ,aAAa,cAAc,aAAa,eAAe;EACzD,MAAM,oBAAoB,mBAAmB;EAC7C,MAAM,kBAAkB,iBAAiB;AAGzC,UAAQ,gBAAgB;AAExB,SAAO,MACL,4CAA4C,aAAa,QAAQ,QAAQ,kBAAkB,GAAG,gBAAgB,IAC/G;EACD,MAAM,QAAQ,MAAM,aAAa,uBAC/B,mBACA,iBACA,OACD;AACD,MAAI,CAAC,OAAO;AACV,UAAO,MACL,+CAA+C,aAAa,UAC7D;AACD;;AAEF,SAAO,MACL,8CAA8C,MAAM,KAAK,KAAK,WAAW,MAAM,QAAQ,GAAG,MAAM,MAAM,IACvG;EAED,MAAM,eAAe,aAAa,oBAAoB;EAGtD,IAAI;AACJ,MAAI;GACF,MAAM,cAAc,MAAM,MAAM,KAAK,aAAa;AAElD,OAAI,YAAY,aAAa,IAC3B;AAEF,mBAAgB,MAAM,aAAa,gBAAgB,YAAY;WACxD,aAAa;AAGpB,OACE,uBAAuB,SACvB,YAAY,QAAQ,SAAS,8BAA8B,CAE3D;AAEF,SAAM;;AAGR,eAAa,SAAS;AACtB,eAAa,QAAQ,aAAa,YAAY;EAE9C,MAAM,aAAa,KAAK,IAAI,GAAG,aAAa,cAAc,OAAO;EAIjE,MAAM,mBAFwB,oBACF,MAAM;EAGlC,MAAM,eAAe,KAAK,IAAI,GAAG,iBAAiB;EAElD,MAAM,sBAAsB,kBAAkB;EAC9C,MAAM,mBAAmB,MAAM,QAAQ,MAAM;EAC7C,MAAM,mBAAmB,KAAK,IAC5B,qBACA,mBAAmB,aACpB;AAED,MAAI,oBAAoB,EACtB;AAGF,eAAa,MACX,aAAa,KACb,eAAe,KACf,mBAAmB,IACpB;GACD,CACH;AAED,QAAO,aAAa,gBAAgB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//#region src/elements/setupTemporalHierarchy.ts
|
|
2
|
+
/**
|
|
3
|
+
* Manually wire up the temporal element hierarchy (parent/root timegroup references).
|
|
4
|
+
*
|
|
5
|
+
* ## Why this is needed
|
|
6
|
+
*
|
|
7
|
+
* Lit Context (`@provide`/`@consume`) relies on `context-request` DOM events. When a consumer
|
|
8
|
+
* connects, it dispatches a `context-request` event that bubbles up to find a provider.
|
|
9
|
+
*
|
|
10
|
+
* **The problem:** When HTML is loaded via `loadURL()` (our rendering path), custom elements
|
|
11
|
+
* connect in depth-first order - children BEFORE parents. This means:
|
|
12
|
+
* 1. `ef-video` connects → dispatches `context-request` event
|
|
13
|
+
* 2. `ef-timegroup` hasn't connected yet → no provider listening → event is lost
|
|
14
|
+
* 3. `ef-timegroup` connects → creates provider → but too late
|
|
15
|
+
*
|
|
16
|
+
* DOM events are point-in-time; once missed, they're gone. There's no retroactive discovery.
|
|
17
|
+
*
|
|
18
|
+
* Without proper parent/root timegroup references:
|
|
19
|
+
* - Child temporal elements can't compute their `ownCurrentTimeMs` (stays at 0)
|
|
20
|
+
* - Video/audio elements can't seek to correct timestamps
|
|
21
|
+
* - Nested timegroups can't calculate their start times correctly
|
|
22
|
+
*
|
|
23
|
+
* ## When to use
|
|
24
|
+
*
|
|
25
|
+
* Call this function after:
|
|
26
|
+
* 1. All elements are connected to DOM (`connectedCallback` has fired)
|
|
27
|
+
* 2. All custom elements have upgraded (`updateComplete` has resolved)
|
|
28
|
+
* 3. Before any time-based operations (seeking, rendering)
|
|
29
|
+
*
|
|
30
|
+
* ## Implementation
|
|
31
|
+
*
|
|
32
|
+
* This function manually traverses the DOM tree and sets:
|
|
33
|
+
* - `parentTimegroup`: The immediate parent timegroup (used for start time calculations)
|
|
34
|
+
* - `rootTimegroup`: The root timegroup (used for ownCurrentTimeMs calculations)
|
|
35
|
+
*
|
|
36
|
+
* This replicates what Lit Context's `@provide`/`@consume` decorators would do if elements
|
|
37
|
+
* connected in parent-first order (as happens with declarative HTML parsing).
|
|
38
|
+
*
|
|
39
|
+
* @param searchRoot - The root element to search within (typically document.body or ef-workbench)
|
|
40
|
+
* @param rootTimegroup - The root timegroup element that should be the hierarchy root
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const rootTimegroup = document.querySelector('ef-timegroup');
|
|
45
|
+
* await rootTimegroup.updateComplete;
|
|
46
|
+
* setupTemporalHierarchy(document.body, rootTimegroup);
|
|
47
|
+
* await rootTimegroup.seekForRender(100); // Now all children can compute correct times
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
function setupTemporalHierarchy(searchRoot, rootTimegroup) {
|
|
51
|
+
const temporals = searchRoot.querySelectorAll("ef-video, ef-audio, ef-image, ef-text, ef-waveform, ef-timegroup");
|
|
52
|
+
for (const el of temporals) {
|
|
53
|
+
if (el === rootTimegroup || !el.isConnected) continue;
|
|
54
|
+
const parentTg = el.parentElement?.closest("ef-timegroup") || rootTimegroup;
|
|
55
|
+
if ("parentTimegroup" in el) el.parentTimegroup = parentTg;
|
|
56
|
+
if ("rootTimegroup" in el) el.rootTimegroup = rootTimegroup;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
export { setupTemporalHierarchy };
|
|
62
|
+
//# sourceMappingURL=setupTemporalHierarchy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTemporalHierarchy.js","names":[],"sources":["../../src/elements/setupTemporalHierarchy.ts"],"sourcesContent":["/**\n * Manually wire up the temporal element hierarchy (parent/root timegroup references).\n *\n * ## Why this is needed\n *\n * Lit Context (`@provide`/`@consume`) relies on `context-request` DOM events. When a consumer\n * connects, it dispatches a `context-request` event that bubbles up to find a provider.\n *\n * **The problem:** When HTML is loaded via `loadURL()` (our rendering path), custom elements\n * connect in depth-first order - children BEFORE parents. This means:\n * 1. `ef-video` connects → dispatches `context-request` event\n * 2. `ef-timegroup` hasn't connected yet → no provider listening → event is lost\n * 3. `ef-timegroup` connects → creates provider → but too late\n *\n * DOM events are point-in-time; once missed, they're gone. There's no retroactive discovery.\n *\n * Without proper parent/root timegroup references:\n * - Child temporal elements can't compute their `ownCurrentTimeMs` (stays at 0)\n * - Video/audio elements can't seek to correct timestamps\n * - Nested timegroups can't calculate their start times correctly\n *\n * ## When to use\n *\n * Call this function after:\n * 1. All elements are connected to DOM (`connectedCallback` has fired)\n * 2. All custom elements have upgraded (`updateComplete` has resolved)\n * 3. Before any time-based operations (seeking, rendering)\n *\n * ## Implementation\n *\n * This function manually traverses the DOM tree and sets:\n * - `parentTimegroup`: The immediate parent timegroup (used for start time calculations)\n * - `rootTimegroup`: The root timegroup (used for ownCurrentTimeMs calculations)\n *\n * This replicates what Lit Context's `@provide`/`@consume` decorators would do if elements\n * connected in parent-first order (as happens with declarative HTML parsing).\n *\n * @param searchRoot - The root element to search within (typically document.body or ef-workbench)\n * @param rootTimegroup - The root timegroup element that should be the hierarchy root\n *\n * @example\n * ```typescript\n * const rootTimegroup = document.querySelector('ef-timegroup');\n * await rootTimegroup.updateComplete;\n * setupTemporalHierarchy(document.body, rootTimegroup);\n * await rootTimegroup.seekForRender(100); // Now all children can compute correct times\n * ```\n */\nexport function setupTemporalHierarchy(\n searchRoot: Element,\n rootTimegroup: any,\n): void {\n const temporalSelectors =\n \"ef-video, ef-audio, ef-image, ef-text, ef-waveform, ef-timegroup\";\n const temporals = searchRoot.querySelectorAll(temporalSelectors);\n\n for (const el of temporals) {\n // Skip the root timegroup itself and disconnected elements\n if (el === rootTimegroup || !(el as any).isConnected) {\n continue;\n }\n\n // Find immediate parent timegroup (may be nested, e.g., timegroup within timegroup)\n // Use closest() starting from parentElement to avoid matching the element itself\n const parentTg =\n (el.parentElement?.closest(\"ef-timegroup\") as any) || rootTimegroup;\n\n // Set both parent and root references\n // - parentTimegroup: Used for start time calculations (evaluateStartTime)\n // - rootTimegroup: Used for ownCurrentTimeMs calculations (determineCurrentTimeSource)\n if (\"parentTimegroup\" in el) {\n (el as any).parentTimegroup = parentTg;\n }\n if (\"rootTimegroup\" in el) {\n (el as any).rootTimegroup = rootTimegroup;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,uBACd,YACA,eACM;CAGN,MAAM,YAAY,WAAW,iBAD3B,mEAC8D;AAEhE,MAAK,MAAM,MAAM,WAAW;AAE1B,MAAI,OAAO,iBAAiB,CAAE,GAAW,YACvC;EAKF,MAAM,WACH,GAAG,eAAe,QAAQ,eAAe,IAAY;AAKxD,MAAI,qBAAqB,GACvB,CAAC,GAAW,kBAAkB;AAEhC,MAAI,mBAAmB,GACrB,CAAC,GAAW,gBAAgB"}
|
|
@@ -26,15 +26,9 @@ const domStructureChanged = /* @__PURE__ */ new WeakMap();
|
|
|
26
26
|
const lastAnimationCount = /* @__PURE__ */ new WeakMap();
|
|
27
27
|
/**
|
|
28
28
|
* Tracks which animations have already been validated to avoid duplicate warnings.
|
|
29
|
+
* Uses animation name + duration as the unique key.
|
|
29
30
|
*/
|
|
30
|
-
const validatedAnimations = /* @__PURE__ */ new
|
|
31
|
-
/**
|
|
32
|
-
* Checks if an element is in a render clone (static DOM context).
|
|
33
|
-
* Render clones are in containers with class "ef-render-clone-container".
|
|
34
|
-
*/
|
|
35
|
-
const isRenderClone = (element) => {
|
|
36
|
-
return element.closest(".ef-render-clone-container") !== null;
|
|
37
|
-
};
|
|
31
|
+
const validatedAnimations = /* @__PURE__ */ new Set();
|
|
38
32
|
/**
|
|
39
33
|
* Validates that an animation is still valid and controllable.
|
|
40
34
|
* Animations become invalid when:
|
|
@@ -65,22 +59,14 @@ const isAnimationValid = (animation, currentAnimations) => {
|
|
|
65
59
|
* For prime timeline (interactive), discovery is responsive to DOM changes.
|
|
66
60
|
*
|
|
67
61
|
* Also cleans up invalid animations (cancelled, removed from DOM, etc.)
|
|
68
|
-
*
|
|
62
|
+
*
|
|
69
63
|
* @param providedAnimations - Optional pre-discovered animations to avoid redundant getAnimations() calls
|
|
70
64
|
*/
|
|
71
65
|
const discoverAndTrackAnimations = (element, providedAnimations) => {
|
|
72
|
-
|
|
73
|
-
const hasTrackedAnimations = animationTracker.has(element);
|
|
66
|
+
animationTracker.has(element);
|
|
74
67
|
const structureChanged = domStructureChanged.get(element) ?? true;
|
|
75
|
-
if (isClone && hasTrackedAnimations && !structureChanged) {
|
|
76
|
-
const rootTracked$1 = animationTracker.get(element);
|
|
77
|
-
return {
|
|
78
|
-
tracked: rootTracked$1,
|
|
79
|
-
current: Array.from(rootTracked$1)
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
68
|
const currentAnimations = providedAnimations ?? element.getAnimations({ subtree: true });
|
|
83
|
-
|
|
69
|
+
domStructureChanged.set(element, false);
|
|
84
70
|
lastAnimationCount.set(element, currentAnimations.length);
|
|
85
71
|
for (const animation of currentAnimations) {
|
|
86
72
|
const effect = animation.effect;
|
|
@@ -114,13 +100,11 @@ const discoverAndTrackAnimations = (element, providedAnimations) => {
|
|
|
114
100
|
anims.push(animation);
|
|
115
101
|
}
|
|
116
102
|
}
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
for (const animation of tracked) if (!isAnimationValid(animation, currentElAnimations)) tracked.delete(animation);
|
|
123
|
-
if (tracked.size === 0) animationTracker.delete(el);
|
|
103
|
+
if (structureChanged) for (const [el, tracked] of elementAnimationsMap) {
|
|
104
|
+
const existingTracked = animationTracker.get(el);
|
|
105
|
+
if (existingTracked) {
|
|
106
|
+
for (const animation of existingTracked) if (!isAnimationValid(animation, tracked)) existingTracked.delete(animation);
|
|
107
|
+
if (existingTracked.size === 0) animationTracker.delete(el);
|
|
124
108
|
}
|
|
125
109
|
}
|
|
126
110
|
return {
|
|
@@ -187,21 +171,7 @@ var VisibilityPolicy = class {
|
|
|
187
171
|
return element.tagName === "EF-TEXT-SEGMENT";
|
|
188
172
|
}
|
|
189
173
|
};
|
|
190
|
-
/**
|
|
191
|
-
* Animation policy: determines when animations should be coordinated.
|
|
192
|
-
*
|
|
193
|
-
* WHY: When an animation reaches exactly the end time of an element, using exclusive
|
|
194
|
-
* end would make the element invisible, causing the animation to be removed from the
|
|
195
|
-
* DOM and creating a visual jump. By using inclusive end, we ensure animations remain
|
|
196
|
-
* coordinated even at exact boundary times, providing smooth visual transitions.
|
|
197
|
-
*/
|
|
198
|
-
var AnimationPolicy = class {
|
|
199
|
-
shouldIncludeEndBoundary(_element) {
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
174
|
const visibilityPolicy = new VisibilityPolicy();
|
|
204
|
-
const animationPolicy = new AnimationPolicy();
|
|
205
175
|
/**
|
|
206
176
|
* Determines if an element should be visible based on its phase and visibility policy.
|
|
207
177
|
*/
|
|
@@ -212,11 +182,20 @@ const shouldBeVisible = (phase, element) => {
|
|
|
212
182
|
};
|
|
213
183
|
/**
|
|
214
184
|
* Determines if animations should be coordinated based on element phase and animation policy.
|
|
185
|
+
*
|
|
186
|
+
* CRITICAL: Always returns true to support scrubbing to arbitrary times.
|
|
187
|
+
*
|
|
188
|
+
* Previously, this function skipped coordination for before-start and after-end phases as an
|
|
189
|
+
* optimization for live playback. However, this broke scrubbing scenarios where we seek to
|
|
190
|
+
* arbitrary times (timeline scrubbing, thumbnails, video export).
|
|
191
|
+
*
|
|
192
|
+
* The performance cost of always coordinating is minimal:
|
|
193
|
+
* - Animations only update when element time changes
|
|
194
|
+
* - Paused animation updates are optimized by the browser
|
|
195
|
+
* - The benefit is correct animation state at all times, regardless of phase
|
|
215
196
|
*/
|
|
216
|
-
const shouldCoordinateAnimations = (
|
|
217
|
-
|
|
218
|
-
if (phase === "active") return true;
|
|
219
|
-
return animationPolicy.shouldIncludeEndBoundary(element);
|
|
197
|
+
const shouldCoordinateAnimations = (_phase, _element) => {
|
|
198
|
+
return true;
|
|
220
199
|
};
|
|
221
200
|
/**
|
|
222
201
|
* Evaluates what the element's state should be based on the timeline.
|
|
@@ -236,21 +215,6 @@ const evaluateTemporalState = (element) => {
|
|
|
236
215
|
};
|
|
237
216
|
};
|
|
238
217
|
/**
|
|
239
|
-
* Evaluates element visibility state specifically for animation coordination.
|
|
240
|
-
* Uses inclusive end boundaries to prevent animation jumps at exact boundaries.
|
|
241
|
-
*
|
|
242
|
-
* This is exported for external use cases that need animation-specific visibility
|
|
243
|
-
* evaluation without the full ElementUpdateContext.
|
|
244
|
-
*/
|
|
245
|
-
const evaluateAnimationVisibilityState = (element) => {
|
|
246
|
-
const state = evaluateTemporalState(element);
|
|
247
|
-
const shouldCoordinate = shouldCoordinateAnimations(state.phase, element);
|
|
248
|
-
return {
|
|
249
|
-
...state,
|
|
250
|
-
isVisible: shouldCoordinate
|
|
251
|
-
};
|
|
252
|
-
};
|
|
253
|
-
/**
|
|
254
218
|
* Capability check: determines if an element supports stagger offset.
|
|
255
219
|
* Encapsulates the knowledge of which element types support this feature.
|
|
256
220
|
*/
|
|
@@ -422,22 +386,20 @@ const hasTransformAnimation = (keyframes) => {
|
|
|
422
386
|
};
|
|
423
387
|
/**
|
|
424
388
|
* Validates CSS animation fill-mode to prevent flashing issues.
|
|
425
|
-
*
|
|
389
|
+
*
|
|
426
390
|
* CRITICAL: Editframe's timeline system pauses animations and manually controls them
|
|
427
391
|
* via animation.currentTime. This means elements exist in the DOM before their animations
|
|
428
392
|
* start. Without proper fill-mode, elements will "flash" to their natural state before
|
|
429
393
|
* the animation begins.
|
|
430
|
-
*
|
|
394
|
+
*
|
|
431
395
|
* Common issues:
|
|
432
396
|
* - Delayed animations without 'backwards': Element shows natural state during delay
|
|
433
397
|
* - Fade-in without 'backwards': Element visible before fade starts
|
|
434
398
|
* - Fade-out without 'forwards': Element snaps back after fade completes
|
|
435
|
-
*
|
|
399
|
+
*
|
|
436
400
|
* Only runs in development mode to avoid performance impact in production.
|
|
437
401
|
*/
|
|
438
402
|
const validateAnimationFillMode = (animation, timing) => {
|
|
439
|
-
if (validatedAnimations.has(animation)) return;
|
|
440
|
-
validatedAnimations.add(animation);
|
|
441
403
|
const effect = animation.effect;
|
|
442
404
|
if (!validateAnimationEffect(effect)) return;
|
|
443
405
|
const fill = effect.getTiming().fill || "none";
|
|
@@ -448,18 +410,21 @@ const validateAnimationFillMode = (animation, timing) => {
|
|
|
448
410
|
const animationNameValue = window.getComputedStyle(target).animationName;
|
|
449
411
|
if (animationNameValue && animationNameValue !== "none") animationName = animationNameValue.split(",")[0]?.trim() || "unknown";
|
|
450
412
|
}
|
|
413
|
+
const validationKey = `${animationName}-${timing.duration}`;
|
|
414
|
+
if (validatedAnimations.has(validationKey)) return;
|
|
415
|
+
validatedAnimations.add(validationKey);
|
|
451
416
|
const warnings = [];
|
|
452
417
|
if (timing.delay > 0 && fill !== "backwards" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}" has a ${timing.delay}ms delay but no 'backwards' fill-mode.`, ` This will cause the element to show its natural state during the delay, then suddenly jump when the animation starts.`, ` Fix: Add 'backwards' or 'both' to the animation shorthand.`, ` Example: animation: ${animationName} ${timing.duration}ms ${timing.delay}ms backwards;`);
|
|
453
418
|
try {
|
|
454
419
|
const keyframes = effect.getKeyframes();
|
|
455
420
|
const fadePattern = detectFadePattern(keyframes);
|
|
456
421
|
const hasTransform = hasTransformAnimation(keyframes);
|
|
457
|
-
if ((fadePattern === "fade-in" || hasTransform) && fill !== "backwards" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}"
|
|
458
|
-
if (fadePattern === "fade-out" && fill !== "forwards" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}"
|
|
459
|
-
if (fadePattern === "both" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}"
|
|
422
|
+
if ((fadePattern === "fade-in" || hasTransform) && fill !== "backwards" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}" modifies initial state but lacks 'backwards' fill-mode.`, ` The element will be visible in its natural state before the animation starts.`, ` Fix: Add 'backwards' or 'both' to the animation.`, ` Example: animation: ${animationName} ${timing.duration}ms backwards;`);
|
|
423
|
+
if (fadePattern === "fade-out" && fill !== "forwards" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}" modifies final state but lacks 'forwards' fill-mode.`, ` The element will snap back to its natural state after the animation completes.`, ` Fix: Add 'forwards' or 'both' to the animation.`, ` Example: animation: ${animationName} ${timing.duration}ms forwards;`);
|
|
424
|
+
if (fadePattern === "both" && fill !== "both") warnings.push(`⚠️ Animation "${animationName}" modifies both initial and final state but doesn't use 'both' fill-mode.`, ` Fix: Use 'both' to apply initial and final states.`, ` Example: animation: ${animationName} ${timing.duration}ms both;`);
|
|
460
425
|
} catch (e) {}
|
|
461
|
-
if (warnings.length > 0) {
|
|
462
|
-
console.
|
|
426
|
+
if (warnings.length > 0 && typeof window !== "undefined" && window.__EDITFRAME_FILL_MODE_WARNINGS__) {
|
|
427
|
+
console.groupCollapsed("%c🎬 Editframe Animation Fill-Mode Warning", "color: #f59e0b; font-weight: bold");
|
|
463
428
|
warnings.forEach((warning) => console.log(warning));
|
|
464
429
|
console.log("\n📚 Learn more: https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode");
|
|
465
430
|
console.groupEnd();
|
|
@@ -602,31 +567,41 @@ const evaluateElementState = (element) => {
|
|
|
602
567
|
*/
|
|
603
568
|
const updateAnimations = (element) => {
|
|
604
569
|
const allAnimations = element.getAnimations({ subtree: true });
|
|
605
|
-
const
|
|
570
|
+
const rootContext = evaluateElementState(element);
|
|
571
|
+
const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
|
|
572
|
+
const { elements: collectedElements, pruned } = deepGetTemporalElements(element, timelineTimeMs);
|
|
573
|
+
for (const prunedElement of pruned) prunedElement.style.setProperty("display", "none");
|
|
574
|
+
const childContexts = [];
|
|
575
|
+
for (const temporalElement of collectedElements) if (!pruned.has(temporalElement)) childContexts.push(evaluateElementState(temporalElement));
|
|
576
|
+
const visibleChildContexts = [];
|
|
577
|
+
for (const ctx of childContexts) if (shouldBeVisible(ctx.state.phase, ctx.element)) visibleChildContexts.push(ctx);
|
|
578
|
+
const temporalSet = new Set(visibleChildContexts.map((c) => c.element));
|
|
579
|
+
temporalSet.add(element);
|
|
580
|
+
const childAnimations = /* @__PURE__ */ new Map();
|
|
606
581
|
for (const animation of allAnimations) {
|
|
607
582
|
const effect = animation.effect;
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
583
|
+
const target = effect && effect instanceof KeyframeEffect ? effect.target : null;
|
|
584
|
+
if (!target || !(target instanceof Element)) continue;
|
|
585
|
+
let node = target;
|
|
586
|
+
while (node) {
|
|
587
|
+
if (temporalSet.has(node)) {
|
|
588
|
+
let anims = childAnimations.get(node);
|
|
589
|
+
if (!anims) {
|
|
590
|
+
anims = [];
|
|
591
|
+
childAnimations.set(node, anims);
|
|
592
|
+
}
|
|
593
|
+
anims.push(animation);
|
|
594
|
+
break;
|
|
614
595
|
}
|
|
615
|
-
|
|
596
|
+
node = node.parentElement;
|
|
616
597
|
}
|
|
617
598
|
}
|
|
618
|
-
|
|
619
|
-
const
|
|
620
|
-
applyAnimationCoordination(rootContext.element, rootContext.state.phase, animationsByElement.get(rootContext.element));
|
|
621
|
-
childContexts.forEach((context) => {
|
|
622
|
-
applyAnimationCoordination(context.element, context.state.phase, animationsByElement.get(context.element));
|
|
623
|
-
});
|
|
599
|
+
applyAnimationCoordination(rootContext.element, rootContext.state.phase, allAnimations);
|
|
600
|
+
for (const context of visibleChildContexts) applyAnimationCoordination(context.element, context.state.phase, childAnimations.get(context.element) || []);
|
|
624
601
|
applyVisualState(rootContext.element, rootContext.state);
|
|
625
|
-
|
|
626
|
-
applyVisualState(context.element, context.state);
|
|
627
|
-
});
|
|
602
|
+
for (const context of childContexts) applyVisualState(context.element, context.state);
|
|
628
603
|
};
|
|
629
604
|
|
|
630
605
|
//#endregion
|
|
631
|
-
export { cleanupTrackedAnimations,
|
|
606
|
+
export { cleanupTrackedAnimations, updateAnimations };
|
|
632
607
|
//# sourceMappingURL=updateAnimations.js.map
|