@hyperframes/studio 0.8.50 → 0.8.52
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/assets/{hyperframes-player-CxxDxHTW.js → hyperframes-player-I5YRzB02.js} +3 -3
- package/dist/assets/{index-Dt3qBI-9.js → index-BTAfgesM.js} +1 -1
- package/dist/assets/index-CxAu_Okg.css +1 -0
- package/dist/assets/index-DocJlW2v.js +376 -0
- package/dist/assets/{index-DUAIWxkI.js → index-Du5x7KUR.js} +1 -1
- package/dist/index.d.ts +419 -20
- package/dist/index.html +2 -2
- package/dist/index.js +7496 -8288
- package/dist/index.js.map +1 -1
- package/dist/styles/tailwind-preset.js.map +1 -1
- package/package.json +13 -12
- package/src/App.tsx +131 -143
- package/src/captions/components/CaptionAnimationPanel.tsx +4 -4
- package/src/captions/components/CaptionOverlay.sender.test.tsx +52 -0
- package/src/captions/components/CaptionOverlay.tsx +8 -4
- package/src/captions/components/CaptionOverlayUtils.ts +2 -3
- package/src/captions/components/CaptionPropertyPanel.tsx +3 -3
- package/src/captions/components/CaptionTimeline.tsx +1 -1
- package/src/captions/components/shared.tsx +2 -2
- package/src/components/AskAgentModal.tsx +5 -5
- package/src/components/EditorShell.tsx +8 -7
- package/src/components/ExternalFileConflictBanner.tsx +16 -16
- package/src/components/LintModal.tsx +6 -16
- package/src/components/MediaPreview.tsx +2 -2
- package/src/components/RightPanelTabs.test.tsx +151 -0
- package/src/components/RightPanelTabs.tsx +59 -0
- package/src/components/SaveQueuePausedBanner.tsx +2 -2
- package/src/components/StudioHeader.dom.test.tsx +181 -0
- package/src/components/StudioHeader.tsx +110 -210
- package/src/components/StudioLeftSidebar.tsx +7 -4
- package/src/components/StudioOverlays.tsx +1 -1
- package/src/components/StudioRightPanel.tsx +51 -39
- package/src/components/StudioToast.tsx +2 -2
- package/src/components/TimelineHistoryButtons.dom.test.tsx +117 -0
- package/src/components/TimelineHistoryButtons.tsx +54 -0
- package/src/components/TimelineToolbar.test.tsx +8 -0
- package/src/components/TimelineToolbar.tsx +8 -12
- package/src/components/dock/Dock.test.tsx +260 -0
- package/src/components/dock/Dock.tsx +281 -0
- package/src/components/dock/dock.css +28 -0
- package/src/components/dock/dockAccessibility.test.ts +166 -0
- package/src/components/dock/dockAccessibility.ts +98 -0
- package/src/components/dock/dockLayout.test.ts +134 -0
- package/src/components/dock/dockLayout.ts +105 -0
- package/src/components/dock/dockLayoutSchema.ts +66 -0
- package/src/components/dock/dockLayoutStore.ts +91 -0
- package/src/components/dock/dockTestHarness.ts +11 -0
- package/src/components/dock/panelRegistry.ts +67 -0
- package/src/components/editor/AnimationCard.tsx +4 -4
- package/src/components/editor/AnimationCardParts.tsx +6 -6
- package/src/components/editor/BlockParamsPanel.tsx +4 -4
- package/src/components/editor/BorderRadiusEditor.tsx +1 -1
- package/src/components/editor/CanvasContextMenu.tsx +1 -1
- package/src/components/editor/ComputedTweenNotice.tsx +1 -1
- package/src/components/editor/DomEditOverlay.tsx +1 -1
- package/src/components/editor/EaseCurveSection.tsx +1 -1
- package/src/components/editor/EaseParamFields.tsx +5 -5
- package/src/components/editor/FileTree.tsx +4 -4
- package/src/components/editor/FileTreeIcons.tsx +1 -1
- package/src/components/editor/FileTreeNodes.tsx +13 -13
- package/src/components/editor/InlineTextToolbar.tsx +1 -1
- package/src/components/editor/InspectorHeaderActions.tsx +3 -3
- package/src/components/editor/KeyframeDiamond.tsx +1 -1
- package/src/components/editor/KeyframeEaseList.tsx +1 -1
- package/src/components/editor/LayersPanel.test.ts +97 -1
- package/src/components/editor/LayersPanel.tsx +7 -5
- package/src/components/editor/MarqueeOverlay.tsx +1 -1
- package/src/components/editor/OffCanvasIndicators.tsx +1 -1
- package/src/components/editor/PreviewGuides.tsx +1 -1
- package/src/components/editor/PromotableControl.tsx +2 -2
- package/src/components/editor/PropertyPanelEmptyState.tsx +7 -7
- package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
- package/src/components/editor/SnapToolbar.tsx +2 -2
- package/src/components/editor/TimelineFxPopover.tsx +1 -1
- package/src/components/editor/TopologyLens.test.tsx +28 -0
- package/src/components/editor/TopologyLens.tsx +7 -5
- package/src/components/editor/Transform3DCube.tsx +2 -2
- package/src/components/editor/audioFxRevealTarget.ts +1 -0
- package/src/components/editor/domEditing.test.ts +1 -1
- package/src/components/editor/domEditingAgentPrompt.test.ts +8 -6
- package/src/components/editor/domEditingAgentPrompt.ts +4 -3
- package/src/components/editor/propertyPanelColor.tsx +11 -11
- package/src/components/editor/propertyPanelColorCurveGraph.tsx +1 -1
- package/src/components/editor/propertyPanelColorGradingControls.tsx +7 -9
- package/src/components/editor/propertyPanelColorGradingSection.tsx +6 -6
- package/src/components/editor/propertyPanelColorGradingSlider.tsx +5 -5
- package/src/components/editor/propertyPanelColorWheels.tsx +1 -1
- package/src/components/editor/propertyPanelCommitField.tsx +1 -1
- package/src/components/editor/propertyPanelFill.tsx +4 -4
- package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +7 -7
- package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
- package/src/components/editor/propertyPanelFlatMediaSection.tsx +3 -3
- package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +1 -1
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +10 -10
- package/src/components/editor/propertyPanelFlatSelectRow.tsx +3 -3
- package/src/components/editor/propertyPanelFlatTextSection.test.tsx +8 -9
- package/src/components/editor/propertyPanelFlatTextSection.tsx +5 -5
- package/src/components/editor/propertyPanelFlatToggle.tsx +1 -1
- package/src/components/editor/propertyPanelFont.tsx +5 -5
- package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.test.tsx +1 -1
- package/src/components/editor/propertyPanelFxControls.tsx +6 -6
- package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
- package/src/components/editor/propertyPanelFxPresetStyle.ts +2 -2
- package/src/components/editor/propertyPanelGradingNumberField.tsx +1 -1
- package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
- package/src/components/editor/propertyPanelPrimitives.tsx +7 -7
- package/src/components/editor/propertyPanelSections.tsx +8 -8
- package/src/components/editor/useColorGradingController.test.ts +38 -0
- package/src/components/editor/useColorGradingController.ts +9 -1
- package/src/components/editor/useColorGradingPreviews.test.ts +76 -0
- package/src/components/editor/useColorGradingPreviews.ts +11 -1
- package/src/components/editor/usePreviewCompositionRect.test.tsx +95 -0
- package/src/components/editor/usePreviewCompositionRect.ts +21 -0
- package/src/components/feedback/StudioFeedbackCard.tsx +7 -7
- package/src/components/feedback/feedbackTrigger.ts +0 -1
- package/src/components/nle/AssetPreviewOverlay.tsx +6 -2
- package/src/components/nle/CompositionBreadcrumb.tsx +3 -3
- package/src/components/nle/NLEPreview.tsx +3 -3
- package/src/components/nle/PreviewOverlays.tsx +6 -6
- package/src/components/nle/PreviewPane.tsx +3 -3
- package/src/components/nle/TimelinePane.tsx +3 -3
- package/src/components/nle/TimelineResizeDivider.tsx +2 -2
- package/src/components/panels/SlideshowPanel.tsx +2 -2
- package/src/components/panels/SlideshowSubPanels.tsx +20 -17
- package/src/components/panels/VariablesBindElement.tsx +2 -2
- package/src/components/panels/VariablesDeclarationForm.tsx +2 -2
- package/src/components/panels/VariablesOtherCompositions.tsx +1 -1
- package/src/components/panels/VariablesPanel.tsx +3 -3
- package/src/components/panels/VariablesValueControls.tsx +2 -2
- package/src/components/pointerTargetSize.test.tsx +8 -0
- package/src/components/renders/FfmpegRequiredNotice.tsx +5 -5
- package/src/components/renders/RenderQueue.test.tsx +7 -0
- package/src/components/renders/RenderQueue.tsx +7 -7
- package/src/components/renders/RenderQueueItem.tsx +6 -6
- package/src/components/sidebar/AssetCard.tsx +8 -8
- package/src/components/sidebar/AssetContextMenu.tsx +8 -8
- package/src/components/sidebar/AssetsTab.tsx +2 -2
- package/src/components/sidebar/AudioRow.tsx +6 -6
- package/src/components/sidebar/BlocksTab.tsx +6 -6
- package/src/components/sidebar/CompositionsTab.tsx +5 -5
- package/src/components/sidebar/GlobalAssetsView.tsx +1 -1
- package/src/components/sidebar/LeftSidebar.lintBadge.test.tsx +58 -0
- package/src/components/sidebar/LeftSidebar.tsx +19 -5
- package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
- package/src/components/timelineToolbarStyles.ts +5 -0
- package/src/components/ui/Button.test.tsx +252 -0
- package/src/components/ui/Button.tsx +89 -126
- package/src/components/ui/IconButton.tsx +38 -0
- package/src/components/ui/Input.tsx +115 -0
- package/src/components/ui/Menu.test.tsx +374 -0
- package/src/components/ui/Menu.tsx +213 -0
- package/src/components/ui/NumberField.tsx +122 -0
- package/src/components/ui/Popover.tsx +74 -0
- package/src/components/ui/SearchInput.tsx +2 -2
- package/src/components/ui/Select.tsx +100 -0
- package/src/components/ui/Slider.tsx +153 -0
- package/src/components/ui/Tabs.test.tsx +98 -0
- package/src/components/ui/Tabs.tsx +71 -0
- package/src/components/ui/Toggle.tsx +63 -0
- package/src/components/ui/Tooltip.test.tsx +110 -0
- package/src/components/ui/Tooltip.tsx +38 -112
- package/src/components/ui/cn.test.ts +30 -0
- package/src/components/ui/cn.ts +25 -0
- package/src/components/ui/index.ts +29 -2
- package/src/components/ui/mountHost.testHelpers.ts +24 -0
- package/src/components/ui/valueControls.test.tsx +524 -0
- package/src/hooks/useAppHotkeys.ts +21 -80
- package/src/hooks/useCaptionDetection.sender.test.tsx +46 -0
- package/src/hooks/useCaptionDetection.ts +3 -1
- package/src/hooks/useEditHistoryActions.test.tsx +90 -0
- package/src/hooks/useEditHistoryActions.ts +106 -0
- package/src/hooks/useLintModal.test.tsx +65 -0
- package/src/hooks/useLintModal.ts +3 -0
- package/src/hooks/useSdkSession.lifecycle.test.tsx +49 -4
- package/src/hooks/useSdkSession.ts +43 -10
- package/src/hooks/useServerConnection.hashProject.test.tsx +94 -0
- package/src/hooks/useServerConnection.ts +43 -10
- package/src/hooks/useTimelineAssetDropOps.test.tsx +41 -1
- package/src/hooks/useTimelineAssetDropOps.ts +52 -11
- package/src/index.ts +51 -0
- package/src/main.tsx +9 -3
- package/src/player/components/AudioWaveform.tsx +1 -1
- package/src/player/components/AutomationSelectionMenu.tsx +3 -3
- package/src/player/components/ClipContextMenu.tsx +3 -3
- package/src/player/components/CompositionThumbnail.test.ts +0 -3
- package/src/player/components/CompositionThumbnail.tsx +3 -4
- package/src/player/components/EditModal.tsx +1 -1
- package/src/player/components/ImageThumbnail.tsx +1 -1
- package/src/player/components/KeyframeDiamondContextMenu.tsx +4 -4
- package/src/player/components/LayerDisclosureRow.tsx +2 -2
- package/src/player/components/PlayerControls.tsx +1 -1
- package/src/player/components/ShortcutsPanel.tsx +9 -9
- package/src/player/components/SpeedMenu.tsx +3 -5
- package/src/player/components/Timeline.tsx +2 -1
- package/src/player/components/TimelineCanvas.tsx +21 -14
- package/src/player/components/TimelineClip.tsx +0 -1
- package/src/player/components/TimelineDiamondConnectors.tsx +1 -1
- package/src/player/components/TimelineEmptyState.tsx +5 -5
- package/src/player/components/TimelineFxButton.tsx +6 -6
- package/src/player/components/TimelineGroupHeader.tsx +5 -5
- package/src/player/components/TimelineGroupLaneLabels.tsx +1 -1
- package/src/player/components/TimelineGroupRow.tsx +1 -1
- package/src/player/components/TimelineLanes.test.tsx +32 -0
- package/src/player/components/TimelineLanes.tsx +2 -5
- package/src/player/components/TimelineLayerGroupHeader.tsx +2 -2
- package/src/player/components/TimelineRuler.tsx +1 -1
- package/src/player/components/TimelineShortcutHint.tsx +1 -1
- package/src/player/components/TimelineTrackHeader.tsx +1 -1
- package/src/player/components/TimelineTrackPlainHeader.tsx +3 -3
- package/src/player/components/TimelineTypes.ts +2 -1
- package/src/player/components/TrackGapContextMenu.tsx +1 -1
- package/src/player/components/VideoThumbnail.tsx +4 -2
- package/src/player/components/VolumeControl.tsx +2 -2
- package/src/player/components/timelineCallbacks.ts +8 -8
- package/src/player/components/timelineClipDragPreview.ts +51 -27
- package/src/player/components/timelineClipDragTypes.ts +3 -0
- package/src/player/components/timelineDragDrop.test.tsx +61 -1
- package/src/player/components/timelineDragDrop.ts +57 -15
- package/src/player/components/timelineLaneProps.ts +3 -0
- package/src/player/components/timelineSnapping.test.ts +27 -0
- package/src/player/components/timelineSnapping.ts +14 -1
- package/src/player/components/trackHeaderLabelRows.tsx +4 -4
- package/src/player/components/useTimelineClipDrag.resize.test.tsx +136 -2
- package/src/player/components/useTimelineClipDrag.ts +30 -3
- package/src/player/lib/describeClips.ts +3 -54
- package/src/player/lib/playbackShortcuts.ts +2 -0
- package/src/player/store/previewIframeStore.notify.test.tsx +75 -0
- package/src/player/store/previewIframeStore.test.tsx +29 -0
- package/src/player/store/previewIframeStore.ts +25 -0
- package/src/renderQueueExports.test.tsx +58 -0
- package/src/styles/classCandidates.test.ts +105 -0
- package/src/styles/classCandidates.ts +281 -0
- package/src/styles/hex-baseline.json +84 -0
- package/src/styles/hexRatchet.test.ts +201 -0
- package/src/styles/iconTokens.ts +20 -0
- package/src/styles/palette-reset.css +6 -0
- package/src/styles/studio.css +24 -21
- package/src/styles/styleSources.test.ts +20 -0
- package/src/styles/styleSources.ts +47 -0
- package/src/styles/tailwind-preset.shared.js +3 -0
- package/src/styles/theme.css +243 -0
- package/src/styles/theme.test.ts +183 -0
- package/src/styles/tokenGate.test.ts +109 -0
- package/src/utils/sourcePatcher.ts +1 -1
- package/src/utils/studioHelpers.test.ts +18 -0
- package/src/utils/studioHelpers.ts +11 -1
- package/src/utils/studioUiPreferences.ts +7 -0
- package/src/utils/timelineDropTrackInsert.test.ts +134 -0
- package/src/utils/timelineDropTrackInsert.ts +83 -0
- package/src/utils/typingTarget.ts +4 -0
- package/dist/assets/index-n2ml4tUn.js +0 -442
- package/dist/assets/index-pO6p0H27.css +0 -1
- package/src/components/PanelTabButton.tsx +0 -31
- package/src/components/storyboard/AgentChatMessageButton.test.tsx +0 -47
- package/src/components/storyboard/AgentChatMessageButton.tsx +0 -45
- package/src/components/storyboard/FramePoster.test.tsx +0 -61
- package/src/components/storyboard/FramePoster.tsx +0 -86
- package/src/components/storyboard/StoryboardDirection.tsx +0 -45
- package/src/components/storyboard/StoryboardFrameFocus.tsx +0 -412
- package/src/components/storyboard/StoryboardFrameTile.tsx +0 -117
- package/src/components/storyboard/StoryboardGrid.tsx +0 -55
- package/src/components/storyboard/StoryboardLoaded.tsx +0 -307
- package/src/components/storyboard/StoryboardReviewGuide.tsx +0 -300
- package/src/components/storyboard/StoryboardScriptPanel.tsx +0 -26
- package/src/components/storyboard/StoryboardSourceEditor.tsx +0 -231
- package/src/components/storyboard/StoryboardStatusLegend.tsx +0 -21
- package/src/components/storyboard/StoryboardView.tsx +0 -169
- package/src/components/storyboard/StoryboardViewModeGuard.test.tsx +0 -187
- package/src/components/storyboard/frameComments.test.ts +0 -95
- package/src/components/storyboard/frameComments.ts +0 -115
- package/src/components/storyboard/frameStatus.ts +0 -36
- package/src/components/storyboard/storyboardReviewStage.test.ts +0 -40
- package/src/components/storyboard/storyboardReviewStage.ts +0 -45
- package/src/components/storyboard/useFrameComments.ts +0 -98
- package/src/contexts/ViewModeContext.tsx +0 -142
- package/src/hooks/useProjectSignaturePoll.test.tsx +0 -135
- package/src/hooks/useProjectSignaturePoll.ts +0 -68
- package/src/hooks/useStoryboard.ts +0 -99
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/styles/tailwind-preset.shared.js","../../src/styles/tailwind-preset.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/styles/tailwind-preset.shared.js","../../src/styles/tailwind-preset.ts"],"sourcesContent":["/** @deprecated Superseded by `src/styles/theme.css` (published as\n * `@hyperframes/studio/theme.css`); kept one more major for Tailwind v3\n * consumers. Values are byte-identical; theme.test.ts fails if they drift. */\nconst studioPreset = {\n theme: {\n extend: {\n colors: {\n studio: {\n bg: \"#0a0a0a\",\n surface: \"#141414\",\n border: \"#262626\",\n text: \"#e5e5e5\",\n muted: \"#737373\",\n accent: \"#3CE6AC\",\n },\n panel: {\n bg: \"#0C0C0E\",\n // Open inspector-section body — slightly lighter than headers (bg)\n // so the recessed scrollable region reads distinct.\n \"bg-inset\": \"#121214\",\n input: \"#161618\",\n surface: \"#18181B\",\n hover: \"#27272A\",\n border: \"#1E1E1E\",\n \"border-input\": \"#27272A\",\n hairline: \"#1A1A1C\",\n \"text-0\": \"#FAFAFA\",\n \"text-1\": \"#E4E4E7\",\n \"text-2\": \"#A1A1AA\",\n \"text-3\": \"#71717A\",\n \"text-4\": \"#52525B\",\n \"text-5\": \"#3F3F46\",\n accent: \"#3CE6AC\",\n danger: \"#EF4444\",\n media: \"#00E3FF\",\n container: \"#F5A623\",\n },\n },\n },\n },\n plugins: [],\n};\n\nexport default studioPreset;\n","import studioPreset from \"./tailwind-preset.shared.js\";\n\nexport default studioPreset;\n"],"mappings":";;;AAGA,IAAM,eAAe;AAAA,EACnB,OAAO;AAAA,IACL,QAAQ;AAAA,MACN,QAAQ;AAAA,QACN,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,QACV;AAAA,QACA,OAAO;AAAA,UACL,IAAI;AAAA;AAAA;AAAA,UAGJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,gBAAgB;AAAA,UAChB,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,SAAS,CAAC;AACZ;AAEA,IAAO,iCAAQ;;;ACzCf,IAAO,0BAAQ;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.52",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,12 +23,14 @@
|
|
|
23
23
|
"import": "./dist/styles/tailwind-preset.js",
|
|
24
24
|
"types": "./dist/styles/tailwind-preset.d.ts"
|
|
25
25
|
},
|
|
26
|
+
"./theme.css": "./src/styles/theme.css",
|
|
26
27
|
"./package.json": "./package.json"
|
|
27
28
|
},
|
|
28
29
|
"publishConfig": {
|
|
29
30
|
"access": "public"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
33
|
+
"@base-ui/react": "1.7.0",
|
|
32
34
|
"@codemirror/autocomplete": "^6.20.1",
|
|
33
35
|
"@codemirror/commands": "^6.10.3",
|
|
34
36
|
"@codemirror/lang-css": "^6.3.1",
|
|
@@ -44,32 +46,31 @@
|
|
|
44
46
|
"@phosphor-icons/react": "^2.1.10",
|
|
45
47
|
"@tanstack/react-virtual": "^3.14.6",
|
|
46
48
|
"bpm-detective": "^2.0.5",
|
|
47
|
-
"
|
|
49
|
+
"cn": "0.2.4",
|
|
50
|
+
"dockview-react": "8.3.1",
|
|
48
51
|
"gsap": "^3.13.0",
|
|
49
|
-
"marked": "^14.1.4",
|
|
50
52
|
"mediabunny": "^1.45.3",
|
|
51
|
-
"@hyperframes/
|
|
52
|
-
"@hyperframes/
|
|
53
|
-
"@hyperframes/
|
|
54
|
-
"@hyperframes/
|
|
55
|
-
"@hyperframes/
|
|
53
|
+
"@hyperframes/core": "0.8.52",
|
|
54
|
+
"@hyperframes/player": "0.8.52",
|
|
55
|
+
"@hyperframes/sdk": "0.8.52",
|
|
56
|
+
"@hyperframes/parsers": "0.8.52",
|
|
57
|
+
"@hyperframes/studio-server": "0.8.52"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
60
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
58
61
|
"@types/react": "19",
|
|
59
62
|
"@types/react-dom": "19",
|
|
60
63
|
"@vitejs/plugin-react": "^4.0.0",
|
|
61
|
-
"autoprefixer": "^10.4.0",
|
|
62
64
|
"chokidar": "^4.0.3",
|
|
63
65
|
"fake-indexeddb": "^6.2.5",
|
|
64
|
-
"postcss": "^8.4.0",
|
|
65
66
|
"puppeteer-core": "^25.2.1",
|
|
66
|
-
"tailwindcss": "^3.
|
|
67
|
+
"tailwindcss": "^4.3.3",
|
|
67
68
|
"tsup": "^8.0.0",
|
|
68
69
|
"typescript": "^5.0.0",
|
|
69
70
|
"vite": "^6.4.2",
|
|
70
71
|
"vitest": "^4.1.11",
|
|
71
72
|
"zustand": "^5.0.0",
|
|
72
|
-
"@hyperframes/producer": "0.8.
|
|
73
|
+
"@hyperframes/producer": "0.8.52"
|
|
73
74
|
},
|
|
74
75
|
"peerDependencies": {
|
|
75
76
|
"react": "19",
|
package/src/App.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useOwnPreviewIframe, usePreviewIframeStore } from "./player/store/previewIframeStore";
|
|
1
2
|
import { buildProjectApiPath } from "./utils/projectRouting";
|
|
2
3
|
import { useState, useCallback, useRef, useMemo, useLayoutEffect } from "react";
|
|
3
4
|
import type { LeftSidebarHandle, SidebarTab } from "./components/sidebar/LeftSidebar";
|
|
@@ -53,8 +54,6 @@ import { StudioRightPanel } from "./components/StudioRightPanel";
|
|
|
53
54
|
import { TimelineToolbar } from "./components/TimelineToolbar";
|
|
54
55
|
import { StudioPlaybackProvider, StudioShellProvider } from "./contexts/StudioContext";
|
|
55
56
|
import { PanelLayoutProvider } from "./contexts/PanelLayoutContext";
|
|
56
|
-
import { ViewModeProvider, useViewModeState } from "./contexts/ViewModeContext";
|
|
57
|
-
import { StoryboardView } from "./components/storyboard/StoryboardView";
|
|
58
57
|
import { FileManagerProvider } from "./contexts/FileManagerContext";
|
|
59
58
|
import { DomEditProvider } from "./contexts/DomEditContext";
|
|
60
59
|
import { StudioSplash } from "./components/StudioSplash";
|
|
@@ -68,10 +67,9 @@ const getTimelineSelectionSet = () => usePlayerStore.getState().selectedElementI
|
|
|
68
67
|
export function StudioApp() {
|
|
69
68
|
const { projectId, resolving, waitingForServer } = useServerConnection();
|
|
70
69
|
const initialUrlStateRef = useRef(readStudioUrlStateFromWindow());
|
|
71
|
-
const viewModeValue = useViewModeState();
|
|
72
70
|
useStudioSessionStart(projectId, resolving, waitingForServer);
|
|
73
71
|
const [compIdToSrc, setCompIdToSrc] = useState<Map<string, string>>(new Map());
|
|
74
|
-
const
|
|
72
|
+
const previewIframe = useOwnPreviewIframe();
|
|
75
73
|
const [compositionLoading, setCompositionLoading] = useState(true);
|
|
76
74
|
const [refreshKey, setRefreshKey] = useState(0);
|
|
77
75
|
const [previewDocumentVersion, refreshPreviewDocumentVersion] = usePreviewDocumentVersion();
|
|
@@ -327,10 +325,8 @@ export function StudioApp() {
|
|
|
327
325
|
effectiveTimelineDuration,
|
|
328
326
|
});
|
|
329
327
|
const compositionDimensions = useCompositionDimensions(previewIframeRef);
|
|
330
|
-
const { lintModal, linting, handleLint, closeLintModal, findingsByFile } =
|
|
331
|
-
projectId,
|
|
332
|
-
refreshKey,
|
|
333
|
-
);
|
|
328
|
+
const { lintModal, linting, handleLint, closeLintModal, findingsByFile, hasLintError } =
|
|
329
|
+
useLintModal(projectId, refreshKey);
|
|
334
330
|
const frameCapture = useFrameCapture({
|
|
335
331
|
projectId,
|
|
336
332
|
activeCompPath,
|
|
@@ -364,7 +360,7 @@ export function StudioApp() {
|
|
|
364
360
|
const handlePreviewIframeRef = useCallback(
|
|
365
361
|
(iframe: HTMLIFrameElement | null) => {
|
|
366
362
|
previewIframeRef.current = iframe;
|
|
367
|
-
|
|
363
|
+
usePreviewIframeStore.getState().setIframe(iframe);
|
|
368
364
|
appHotkeys.syncPreviewHotkeys(iframe);
|
|
369
365
|
resetConsoleErrors();
|
|
370
366
|
refreshPreviewDocumentVersion();
|
|
@@ -441,144 +437,136 @@ export function StudioApp() {
|
|
|
441
437
|
return (
|
|
442
438
|
<StudioShellProvider value={studioCtxValue}>
|
|
443
439
|
<StudioPlaybackProvider value={studioCtxValue}>
|
|
444
|
-
<
|
|
445
|
-
<
|
|
446
|
-
<
|
|
447
|
-
<
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
440
|
+
<PanelLayoutProvider value={panelLayout}>
|
|
441
|
+
<FileManagerProvider value={fileManager}>
|
|
442
|
+
<DomEditProvider value={domEditSession}>
|
|
443
|
+
<div
|
|
444
|
+
className="flex flex-col h-full w-full bg-neutral-950 relative"
|
|
445
|
+
onDragOver={fileDrop.onDragOver}
|
|
446
|
+
onDrop={fileDrop.onDrop}
|
|
447
|
+
>
|
|
448
|
+
<StudioHeader
|
|
449
|
+
captureFrameHref={frameCapture.captureFrameHref}
|
|
450
|
+
captureFrameFilename={frameCapture.captureFrameFilename}
|
|
451
|
+
handleCaptureFrameClick={frameCapture.handleCaptureFrameClick}
|
|
452
|
+
refreshCaptureFrameTime={frameCapture.refreshCaptureFrameTime}
|
|
453
|
+
capturing={frameCapture.capturing}
|
|
454
|
+
inspectorButtonActive={inspectorButtonActive}
|
|
455
|
+
inspectorPanelActive={inspectorPanelActive}
|
|
456
|
+
onExport={() => {
|
|
457
|
+
void (async () => {
|
|
458
|
+
await previewPersistence.waitForPendingDomEditSaves();
|
|
459
|
+
await renderQueue.startRender(undefined);
|
|
460
|
+
})();
|
|
461
|
+
}}
|
|
462
|
+
/>
|
|
463
|
+
{previewPersistence.domEditSaveQueuePaused && !externalFileChanges.blocked && (
|
|
464
|
+
<SaveQueuePausedBanner
|
|
465
|
+
message={previewPersistence.domEditSaveQueuePaused}
|
|
466
|
+
onRetry={previewPersistence.resetDomEditSaveQueueBreaker}
|
|
467
467
|
/>
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
<ExternalFileConflictBanner coordinator={externalFileChanges} />
|
|
475
|
-
{viewModeValue.viewMode === "storyboard" && (
|
|
476
|
-
<StoryboardView
|
|
477
|
-
projectId={projectId}
|
|
468
|
+
)}
|
|
469
|
+
<ExternalFileConflictBanner coordinator={externalFileChanges} />
|
|
470
|
+
<EditorShell
|
|
471
|
+
left={
|
|
472
|
+
<StudioLeftSidebar
|
|
473
|
+
leftSidebarRef={leftSidebarRef}
|
|
478
474
|
onSelectComposition={handleSelectComposition}
|
|
475
|
+
onAddBlock={handleAddBlock}
|
|
476
|
+
onPreviewBlock={setBlockPreview}
|
|
477
|
+
onLint={handleLint}
|
|
478
|
+
linting={linting}
|
|
479
|
+
lintFindingCount={lintModal?.length ?? findingsByFile.size}
|
|
480
|
+
lintFindingsByFile={findingsByFile}
|
|
481
|
+
lintHasError={hasLintError}
|
|
482
|
+
onAddAssetToTimeline={handleAddAssetAtPlayhead}
|
|
483
|
+
onAddCompositionToTimeline={handleAddCompositionAtPlayhead}
|
|
479
484
|
/>
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
485
|
+
}
|
|
486
|
+
right={
|
|
487
|
+
panelLayout.effectiveRightCollapsed ? null : (
|
|
488
|
+
<StudioRightPanel
|
|
489
|
+
designPanelActive={designPanelActive}
|
|
490
|
+
activeBlockParams={activeBlockParams}
|
|
491
|
+
onCloseBlockParams={() => {
|
|
492
|
+
setActiveBlockParams(null);
|
|
493
|
+
panelLayout.setRightPanelTab("design");
|
|
494
|
+
}}
|
|
495
|
+
recordingState={gestureState}
|
|
496
|
+
recordingDuration={gestureRecording.recordingDuration}
|
|
497
|
+
onToggleRecording={handleToggleRecording}
|
|
498
|
+
sdkSession={sdkHandle.session}
|
|
499
|
+
publishSdkSession={sdkHandle.publish}
|
|
500
|
+
forceReloadSdkSession={sdkHandle.forceReload}
|
|
501
|
+
reloadPreview={reloadPreview}
|
|
502
|
+
recordEdit={editHistory.recordEdit}
|
|
503
|
+
onToggleElementHidden={timelineEditing.handleToggleElementHidden}
|
|
504
|
+
onAutoGroupCarveSources={timelineEditing.handleAutoGroupCarveSources}
|
|
505
|
+
onAddMediaOverlay={handleAddMediaOverlay}
|
|
495
506
|
/>
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
compositionSize={compositionDimensions ?? undefined}
|
|
560
|
-
mode="recording"
|
|
561
|
-
/>
|
|
562
|
-
) : undefined
|
|
563
|
-
}
|
|
564
|
-
/>
|
|
565
|
-
<StudioOverlays
|
|
566
|
-
projectId={projectId}
|
|
567
|
-
projectDir={fileManager.projectDir}
|
|
568
|
-
lintModal={lintModal}
|
|
569
|
-
closeLintModal={closeLintModal}
|
|
570
|
-
consoleErrors={consoleErrors}
|
|
571
|
-
clearConsoleErrors={() => setConsoleErrors(null)}
|
|
572
|
-
domEditSession={domEditSession}
|
|
573
|
-
activeCompPath={activeCompPath}
|
|
574
|
-
toasts={toasts}
|
|
575
|
-
dismissToast={dismissToast}
|
|
576
|
-
/>
|
|
577
|
-
</div>
|
|
578
|
-
</DomEditProvider>
|
|
579
|
-
</FileManagerProvider>
|
|
580
|
-
</PanelLayoutProvider>
|
|
581
|
-
</ViewModeProvider>
|
|
507
|
+
)
|
|
508
|
+
}
|
|
509
|
+
timelineToolbar={timelineToolbar}
|
|
510
|
+
renderClipContent={renderClipContent}
|
|
511
|
+
handleTimelineElementDelete={timelineEditing.handleTimelineElementDelete}
|
|
512
|
+
handleTimelineAssetDrop={timelineEditing.handleTimelineAssetDrop}
|
|
513
|
+
handleTimelineBlockDrop={handleTimelineBlockDrop}
|
|
514
|
+
handleTimelineCompositionDrop={timelineEditing.handleTimelineCompositionDrop}
|
|
515
|
+
handlePreviewBlockDrop={handlePreviewBlockDrop}
|
|
516
|
+
handleTimelineFileDrop={timelineEditing.handleTimelineFileDrop}
|
|
517
|
+
handleTimelineElementMove={timelineEditing.handleTimelineElementMove}
|
|
518
|
+
handleTimelineElementsMove={handleTimelineElementsMove}
|
|
519
|
+
handleTimelineElementResize={timelineEditing.handleTimelineElementResize}
|
|
520
|
+
handleTimelineGroupResize={timelineEditing.handleTimelineGroupResize}
|
|
521
|
+
handleToggleTrackHidden={timelineEditing.handleToggleTrackHidden}
|
|
522
|
+
setAudioGroupAttribute={timelineEditing.setAudioGroupAttribute}
|
|
523
|
+
handleGroupClips={timelineEditing.handleAutoGroupCarveSources}
|
|
524
|
+
setElementFxAttribute={timelineEditing.setElementFxAttribute}
|
|
525
|
+
handleBlockedTimelineEdit={timelineEditing.handleBlockedTimelineEdit}
|
|
526
|
+
handleTimelineElementSplit={timelineEditing.handleTimelineElementSplit}
|
|
527
|
+
handleRazorSplit={timelineEditing.handleRazorSplit}
|
|
528
|
+
handleRazorSplitAll={timelineEditing.handleRazorSplitAll}
|
|
529
|
+
onCopyClip={handleCopy}
|
|
530
|
+
onPasteClip={handlePaste}
|
|
531
|
+
onDuplicateClip={handleDuplicate}
|
|
532
|
+
canPasteClip={canPaste}
|
|
533
|
+
setCompIdToSrc={setCompIdToSrc}
|
|
534
|
+
setCompositionLoading={setCompositionLoading}
|
|
535
|
+
shouldShowMotionPath={shouldShowMotionPath}
|
|
536
|
+
shouldShowSelectedDomBounds={shouldShowSelectedDomBounds}
|
|
537
|
+
isGestureRecording={gestureState === "recording"}
|
|
538
|
+
recordingState={gestureState}
|
|
539
|
+
onToggleRecording={handleToggleRecording}
|
|
540
|
+
blockPreview={blockPreview}
|
|
541
|
+
gestureOverlay={
|
|
542
|
+
gestureState === "recording" && previewIframe ? (
|
|
543
|
+
<GestureTrailOverlay
|
|
544
|
+
samples={gestureRecording.samplesRef.current}
|
|
545
|
+
sampleCount={gestureRecording.samplesRef.current.length}
|
|
546
|
+
trail={gestureRecording.trailRef.current}
|
|
547
|
+
canvasRect={canvasRectRef.current!}
|
|
548
|
+
compositionSize={compositionDimensions ?? undefined}
|
|
549
|
+
mode="recording"
|
|
550
|
+
/>
|
|
551
|
+
) : undefined
|
|
552
|
+
}
|
|
553
|
+
/>
|
|
554
|
+
<StudioOverlays
|
|
555
|
+
projectId={projectId}
|
|
556
|
+
projectDir={fileManager.projectDir}
|
|
557
|
+
lintModal={lintModal}
|
|
558
|
+
closeLintModal={closeLintModal}
|
|
559
|
+
consoleErrors={consoleErrors}
|
|
560
|
+
clearConsoleErrors={() => setConsoleErrors(null)}
|
|
561
|
+
domEditSession={domEditSession}
|
|
562
|
+
activeCompPath={activeCompPath}
|
|
563
|
+
toasts={toasts}
|
|
564
|
+
dismissToast={dismissToast}
|
|
565
|
+
/>
|
|
566
|
+
</div>
|
|
567
|
+
</DomEditProvider>
|
|
568
|
+
</FileManagerProvider>
|
|
569
|
+
</PanelLayoutProvider>
|
|
582
570
|
</StudioPlaybackProvider>
|
|
583
571
|
</StudioShellProvider>
|
|
584
572
|
);
|
|
@@ -171,7 +171,7 @@ function AnimationPhase({
|
|
|
171
171
|
}}
|
|
172
172
|
className="flex-1 accent-studio-accent disabled:opacity-40"
|
|
173
173
|
/>
|
|
174
|
-
<span className="text-2xs text-neutral-400 font-mono w-8 text-right
|
|
174
|
+
<span className="text-2xs text-neutral-400 font-mono w-8 text-right shrink-0">
|
|
175
175
|
{intensity.toFixed(2)}
|
|
176
176
|
</span>
|
|
177
177
|
</div>
|
|
@@ -249,7 +249,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
|
|
|
249
249
|
return (
|
|
250
250
|
<div className="flex flex-col h-full min-h-0">
|
|
251
251
|
{gated && (
|
|
252
|
-
<div className="
|
|
252
|
+
<div className="shrink-0 mx-3 mt-2 px-2 py-1.5 rounded-sm border border-amber-500/30 bg-amber-500/10">
|
|
253
253
|
<p className="text-2xs text-amber-300/90 leading-snug">
|
|
254
254
|
Animation editing isn't applied to playback or saved yet, so these controls are
|
|
255
255
|
disabled.
|
|
@@ -286,13 +286,13 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
|
|
|
286
286
|
</div>
|
|
287
287
|
|
|
288
288
|
{/* Footer */}
|
|
289
|
-
<div className="
|
|
289
|
+
<div className="shrink-0 px-3 py-2 border-t border-neutral-800">
|
|
290
290
|
<button
|
|
291
291
|
type="button"
|
|
292
292
|
onClick={handleApplyToAll}
|
|
293
293
|
disabled={gated}
|
|
294
294
|
title={gated ? "Disabled until animation editing is applied to playback" : undefined}
|
|
295
|
-
className="w-full py-1.5 rounded border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-studio-accent transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
|
|
295
|
+
className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-studio-accent transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
|
|
296
296
|
>
|
|
297
297
|
Apply to all groups
|
|
298
298
|
</button>
|
|
@@ -4,6 +4,7 @@ import { createRoot } from "react-dom/client";
|
|
|
4
4
|
import { expect, it, vi } from "vitest";
|
|
5
5
|
import { CaptionOverlay } from "./CaptionOverlay";
|
|
6
6
|
import { useCaptionStore } from "../store";
|
|
7
|
+
import { usePreviewIframeStore } from "../../player/store/previewIframeStore";
|
|
7
8
|
|
|
8
9
|
Reflect.set(globalThis, "IS_REACT_ACT_ENVIRONMENT", true);
|
|
9
10
|
|
|
@@ -45,3 +46,54 @@ it("only schedules caption layout for messages from its preview", () => {
|
|
|
45
46
|
vi.unstubAllGlobals();
|
|
46
47
|
}
|
|
47
48
|
});
|
|
49
|
+
|
|
50
|
+
it("observes and accepts messages from the promoted iframe, not the old one", () => {
|
|
51
|
+
const host = document.createElement("div");
|
|
52
|
+
const a = document.createElement("iframe");
|
|
53
|
+
const b = document.createElement("iframe");
|
|
54
|
+
document.body.append(host, a, b);
|
|
55
|
+
const ref = { current: a };
|
|
56
|
+
const root = createRoot(host);
|
|
57
|
+
const schedule = vi.fn(() => 1);
|
|
58
|
+
const observed: Element[] = [];
|
|
59
|
+
vi.stubGlobal("requestAnimationFrame", schedule);
|
|
60
|
+
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
|
61
|
+
vi.stubGlobal(
|
|
62
|
+
"ResizeObserver",
|
|
63
|
+
class {
|
|
64
|
+
observe(el: Element) {
|
|
65
|
+
observed.push(el);
|
|
66
|
+
}
|
|
67
|
+
disconnect() {}
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
useCaptionStore.getState().setEditMode(true);
|
|
71
|
+
const send = (source: MessageEventSource | null) =>
|
|
72
|
+
act(() => {
|
|
73
|
+
window.dispatchEvent(new MessageEvent("message", { source, data: { source: "hf-preview" } }));
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
act(() => usePreviewIframeStore.getState().setIframe(a));
|
|
77
|
+
act(() => root.render(<CaptionOverlay iframeRef={ref} />));
|
|
78
|
+
expect(observed).toContain(a);
|
|
79
|
+
expect(observed).not.toContain(b);
|
|
80
|
+
act(() => {
|
|
81
|
+
ref.current = b;
|
|
82
|
+
usePreviewIframeStore.getState().setIframe(b);
|
|
83
|
+
});
|
|
84
|
+
expect(observed).toContain(b);
|
|
85
|
+
schedule.mockClear();
|
|
86
|
+
send(a.contentWindow);
|
|
87
|
+
expect(schedule).not.toHaveBeenCalled();
|
|
88
|
+
send(b.contentWindow);
|
|
89
|
+
expect(schedule).toHaveBeenCalledOnce();
|
|
90
|
+
} finally {
|
|
91
|
+
act(() => root.unmount());
|
|
92
|
+
usePreviewIframeStore.setState({ iframe: null });
|
|
93
|
+
useCaptionStore.getState().reset();
|
|
94
|
+
host.remove();
|
|
95
|
+
a.remove();
|
|
96
|
+
b.remove();
|
|
97
|
+
vi.unstubAllGlobals();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { memo, useState, useCallback, useRef } from "react";
|
|
1
|
+
import { memo, useEffect, useState, useCallback, useRef } from "react";
|
|
2
|
+
import { useLivePreviewIframe } from "../../player/store/previewIframeStore";
|
|
2
3
|
import { useCaptionStore } from "../store";
|
|
3
4
|
import { usePlayerStore } from "../../player";
|
|
4
|
-
import { useMountEffect } from "../../hooks/useMountEffect";
|
|
5
5
|
import { shouldHandleCaptionNudgeKey, isEditableEventTarget } from "../keyboard";
|
|
6
6
|
import {
|
|
7
7
|
readWordBoxes,
|
|
@@ -32,6 +32,7 @@ function syncToStore(segmentId: string, el: HTMLElement, iframeWin: Window) {
|
|
|
32
32
|
|
|
33
33
|
export const CaptionOverlay = memo(function CaptionOverlay({ iframeRef }: CaptionOverlayProps) {
|
|
34
34
|
const isEditMode = useCaptionStore((s) => s.isEditMode);
|
|
35
|
+
const livePreviewIframe = useLivePreviewIframe();
|
|
35
36
|
const model = useCaptionStore((s) => s.model);
|
|
36
37
|
const selectedSegmentIds = useCaptionStore((s) => s.selectedSegmentIds);
|
|
37
38
|
const selectSegment = useCaptionStore((s) => s.selectSegment);
|
|
@@ -81,7 +82,9 @@ export const CaptionOverlay = memo(function CaptionOverlay({ iframeRef }: Captio
|
|
|
81
82
|
| null
|
|
82
83
|
>(null);
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
// The observer and message filter bind to the live iframe element, which a promoted reload replaces.
|
|
86
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
87
|
+
useEffect(() => {
|
|
85
88
|
if (!isEditMode) return;
|
|
86
89
|
|
|
87
90
|
// Let undo/redo (useAppHotkeys) reapply restored models to this iframe.
|
|
@@ -240,7 +243,8 @@ export const CaptionOverlay = memo(function CaptionOverlay({ iframeRef }: Captio
|
|
|
240
243
|
window.removeEventListener("keydown", handleKeyDown);
|
|
241
244
|
cancelDragRef.current = null;
|
|
242
245
|
};
|
|
243
|
-
|
|
246
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
247
|
+
}, [livePreviewIframe]);
|
|
244
248
|
|
|
245
249
|
const getCssScale = useCallback(() => {
|
|
246
250
|
const iframe = iframeRef.current;
|
|
@@ -221,9 +221,8 @@ export function registerCaptionIframe(ref: React.RefObject<HTMLIFrameElement | n
|
|
|
221
221
|
|
|
222
222
|
/**
|
|
223
223
|
* True when the caption preview iframe is mounted AND visible. The caption
|
|
224
|
-
* store's isEditMode stays true while the preview is merely hidden
|
|
225
|
-
*
|
|
226
|
-
* the user can actually see the captions the undo would change.
|
|
224
|
+
* store's isEditMode stays true while the preview is merely hidden, so hotkeys must not
|
|
225
|
+
* route ⌘Z to the caption stack unless the user can see the captions the undo would change.
|
|
227
226
|
*/
|
|
228
227
|
export function isCaptionPreviewVisible(): boolean {
|
|
229
228
|
const iframe = registeredIframe?.current;
|
|
@@ -213,7 +213,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
|
|
|
213
213
|
return (
|
|
214
214
|
<div className="flex flex-col h-full min-h-0">
|
|
215
215
|
{/* Header */}
|
|
216
|
-
<div className="px-3 py-2 border-b border-neutral-800
|
|
216
|
+
<div className="px-3 py-2 border-b border-neutral-800 shrink-0">
|
|
217
217
|
<div className="flex items-center justify-between mb-1.5">
|
|
218
218
|
<span className="text-2xs text-neutral-500">{countLabel}</span>
|
|
219
219
|
</div>
|
|
@@ -225,7 +225,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
|
|
|
225
225
|
aria-selected={activeTab === "style"}
|
|
226
226
|
onClick={() => setActiveTab("style")}
|
|
227
227
|
className={[
|
|
228
|
-
"flex-1 py-0.5 rounded text-2xs font-medium transition-colors",
|
|
228
|
+
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
|
|
229
229
|
activeTab === "style"
|
|
230
230
|
? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
|
|
231
231
|
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
|
|
@@ -239,7 +239,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
|
|
|
239
239
|
aria-selected={activeTab === "animation"}
|
|
240
240
|
onClick={() => setActiveTab("animation")}
|
|
241
241
|
className={[
|
|
242
|
-
"flex-1 py-0.5 rounded text-2xs font-medium transition-colors",
|
|
242
|
+
"flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
|
|
243
243
|
activeTab === "animation"
|
|
244
244
|
? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
|
|
245
245
|
: "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
|
|
@@ -109,7 +109,7 @@ export const CaptionTimeline = memo(function CaptionTimeline({
|
|
|
109
109
|
tabIndex={0}
|
|
110
110
|
aria-label={`Caption word "${seg.text}"`}
|
|
111
111
|
aria-pressed={isSelected}
|
|
112
|
-
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-white outline-
|
|
112
|
+
className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-white outline-hidden${
|
|
113
113
|
isSelected ? " ring-1 ring-white/50 z-10" : ""
|
|
114
114
|
}`}
|
|
115
115
|
style={{
|
|
@@ -2,7 +2,7 @@ import type React from "react";
|
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
|
|
4
4
|
export const inputCls =
|
|
5
|
-
"w-full bg-neutral-900 border border-neutral-800 rounded px-1.5 py-0.5 text-2xs text-neutral-200 font-mono outline-
|
|
5
|
+
"w-full bg-neutral-900 border border-neutral-800 rounded-sm px-1.5 py-0.5 text-2xs text-neutral-200 font-mono outline-hidden focus:border-studio-accent disabled:opacity-40 disabled:cursor-not-allowed";
|
|
6
6
|
|
|
7
7
|
export function Section({ label, children }: { label: string; children: React.ReactNode }) {
|
|
8
8
|
return (
|
|
@@ -20,7 +20,7 @@ export function Section({ label, children }: { label: string; children: React.Re
|
|
|
20
20
|
export function Row({ label, children }: { label: string; children: React.ReactNode }) {
|
|
21
21
|
return (
|
|
22
22
|
<div className="flex items-center gap-2">
|
|
23
|
-
<span className="text-2xs text-neutral-600 w-14 text-right
|
|
23
|
+
<span className="text-2xs text-neutral-600 w-14 text-right shrink-0">{label}</span>
|
|
24
24
|
<div className="flex-1 min-w-0">{children}</div>
|
|
25
25
|
</div>
|
|
26
26
|
);
|