@dailies-studio/shot-editor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.vite/manifest.json +382 -0
- package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
- package/dist/assets/AgentPanel-DJEphah0.css +1 -0
- package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
- package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
- package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
- package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
- package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
- package/dist/assets/CurvePane-BjFVabKX.css +1 -0
- package/dist/assets/CurvePane-R22WzllJ.js +1 -0
- package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
- package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
- package/dist/assets/FontPicker-v0IOIArM.css +1 -0
- package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
- package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
- package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
- package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
- package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
- package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
- package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
- package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
- package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
- package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
- package/dist/assets/SoundMode-BmcZru3i.js +3 -0
- package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
- package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
- package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
- package/dist/assets/board-B88EPuLO.css +1 -0
- package/dist/assets/board-CL-he7SL.js +3 -0
- package/dist/assets/components-0oOSPN0l.js +1 -0
- package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
- package/dist/assets/googleFonts-BNon6M7X.js +1 -0
- package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
- package/dist/assets/index-4F5NQmI8.css +1 -0
- package/dist/assets/index-BGHQGV5z.js +117 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/libraryModel-CpIwfFha.js +1 -0
- package/dist/assets/lucide-6iK64tTB.js +9319 -0
- package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
- package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
- package/dist/assets/webmcp-BsB9gxWC.js +2 -0
- package/dist/index.html +34 -3
- package/package.json +12 -9
- package/src/addFamilies.ts +66 -0
- package/src/api.ts +1631 -55
- package/src/app/App.tsx +977 -198
- package/src/app/lazyPanel.tsx +137 -0
- package/src/app/lazySurfaces.tsx +203 -0
- package/src/audio/index.tsx +41 -10
- package/src/audio/meter.ts +485 -0
- package/src/audio/meterMath.ts +273 -0
- package/src/audio/meterStore.ts +155 -0
- package/src/audio/offlineMix.ts +289 -0
- package/src/audio/preview.ts +928 -118
- package/src/bridge.ts +15 -5
- package/src/bridgeTypes.ts +1611 -36
- package/src/channels.ts +17 -32
- package/src/fonts/googleFonts.ts +4 -0
- package/src/hostApi.ts +174 -0
- package/src/icons.tsx +770 -0
- package/src/layerWords.ts +61 -0
- package/src/main.tsx +56 -4
- package/src/panels/ResizeHandle.tsx +33 -43
- package/src/panels/agent/AgentDots.tsx +36 -0
- package/src/panels/agent/AgentPanel.tsx +119 -43
- package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
- package/src/panels/agent/agent.css +113 -97
- package/src/panels/agent/agentGate.ts +35 -0
- package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
- package/src/panels/code/CodeStudio.tsx +373 -0
- package/src/panels/code/FileTree.tsx +265 -0
- package/src/panels/code/codeBufferGuard.ts +52 -0
- package/src/panels/code/codeParts.tsx +321 -0
- package/src/panels/comments/CommentComposer.tsx +239 -0
- package/src/panels/comments/CommentThread.tsx +346 -0
- package/src/panels/comments/CommentsPanel.tsx +336 -0
- package/src/panels/comments/InboxButton.tsx +131 -0
- package/src/panels/comments/MentionMenu.tsx +98 -0
- package/src/panels/comments/parts.tsx +171 -0
- package/src/panels/export/ExportDialog.tsx +919 -96
- package/src/panels/export/ExportScrim.tsx +57 -0
- package/src/panels/files/AssetsTab.tsx +656 -0
- package/src/panels/files/FilePanel.tsx +1466 -216
- package/src/panels/files/LayerMarks.tsx +40 -0
- package/src/panels/files/LeftColumn.tsx +37 -0
- package/src/panels/files/McpSection.tsx +690 -47
- package/src/panels/files/MissingAssetsNotice.tsx +60 -0
- package/src/panels/files/assetDrag.ts +79 -0
- package/src/panels/files/resourceParts.tsx +255 -0
- package/src/panels/fonts/FontPicker.tsx +762 -0
- package/src/panels/fonts/faceCache.ts +207 -0
- package/src/panels/fonts/fontPicker.css +271 -0
- package/src/panels/fonts/pickerModel.ts +265 -0
- package/src/panels/fonts/pickerRequest.ts +46 -0
- package/src/panels/header/AccountAvatar.tsx +76 -0
- package/src/panels/header/AgentChip.tsx +77 -0
- package/src/panels/header/AppMenu.tsx +213 -0
- package/src/panels/header/Header.tsx +564 -84
- package/src/panels/header/HistoryControls.tsx +31 -5
- package/src/panels/header/PresenceStack.tsx +329 -0
- package/src/panels/header/ProjectTitle.tsx +232 -0
- package/src/panels/header/ShareButton.tsx +59 -0
- package/src/panels/header/StatusBadges.tsx +358 -27
- package/src/panels/header/SyncDeletedDialog.tsx +88 -0
- package/src/panels/header/ZoomControls.tsx +46 -15
- package/src/panels/header/agentHandoff.ts +52 -0
- package/src/panels/header/leave.ts +26 -0
- package/src/panels/help/HelpSection.tsx +189 -163
- package/src/panels/insert/InsertDrawer.tsx +723 -0
- package/src/panels/insert/iconSet.ts +109 -0
- package/src/panels/inspector/ExposeDot.tsx +117 -0
- package/src/panels/inspector/FramingRows.tsx +314 -44
- package/src/panels/inspector/InspectorFooter.tsx +91 -0
- package/src/panels/inspector/InspectorHead.tsx +425 -0
- package/src/panels/inspector/InspectorPanel.tsx +408 -124
- package/src/panels/inspector/KeyframeDot.tsx +373 -0
- package/src/panels/inspector/KeyframeSection.tsx +257 -0
- package/src/panels/inspector/MarkerSection.tsx +55 -11
- package/src/panels/inspector/ParamRow.tsx +84 -53
- package/src/panels/inspector/RightColumn.tsx +152 -0
- package/src/panels/inspector/TimeSection.tsx +866 -0
- package/src/panels/inspector/animate/EaseControl.tsx +244 -0
- package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
- package/src/panels/inspector/animate/ShotSection.tsx +562 -48
- package/src/panels/inspector/design/AlignRow.tsx +95 -31
- package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
- package/src/panels/inspector/design/ClonerSection.tsx +323 -62
- package/src/panels/inspector/design/ComponentSection.tsx +50 -43
- package/src/panels/inspector/design/CornerSection.tsx +45 -14
- package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
- package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
- package/src/panels/inspector/design/DeviceSection.tsx +210 -0
- package/src/panels/inspector/design/FillSection.tsx +83 -51
- package/src/panels/inspector/design/FontField.tsx +196 -0
- package/src/panels/inspector/design/HtmlSection.tsx +23 -12
- package/src/panels/inspector/design/InstanceSection.tsx +373 -154
- package/src/panels/inspector/design/MaskSection.tsx +84 -0
- package/src/panels/inspector/design/MaterialSection.tsx +177 -0
- package/src/panels/inspector/design/MediaSection.tsx +273 -120
- package/src/panels/inspector/design/MeshSection.tsx +910 -82
- package/src/panels/inspector/design/PaintRows.tsx +550 -0
- package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
- package/src/panels/inspector/design/ShadowSection.tsx +221 -48
- package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
- package/src/panels/inspector/design/StrokeSection.tsx +228 -43
- package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
- package/src/panels/inspector/design/TransformSection.tsx +244 -50
- package/src/panels/inspector/design/TypographySection.tsx +679 -110
- package/src/panels/inspector/layout.ts +295 -0
- package/src/panels/inspector/propValue.ts +199 -0
- package/src/panels/inspector/scene/CameraSection.tsx +232 -22
- package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
- package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
- package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
- package/src/panels/inspector/scene/SceneSection.tsx +219 -44
- package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
- package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
- package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
- package/src/panels/inspector/timeModel.ts +190 -0
- package/src/panels/inspector/useDocWrite.ts +438 -146
- package/src/panels/library/LibraryBrowser.tsx +435 -0
- package/src/panels/library/LibraryGrid.tsx +190 -0
- package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
- package/src/panels/library/LibraryRail.tsx +84 -0
- package/src/panels/library/LibrarySoundPanel.tsx +293 -0
- package/src/panels/library/SoundHistory.tsx +245 -0
- package/src/panels/library/StockSounds.tsx +390 -0
- package/src/panels/library/libraryModel.ts +147 -0
- package/src/panels/library/stockSearch.ts +77 -0
- package/src/panels/maskMarks.tsx +117 -0
- package/src/panels/material/MaterialCommentNode.tsx +54 -0
- package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
- package/src/panels/material/MaterialGraphMenu.tsx +45 -0
- package/src/panels/material/MaterialGroupNode.tsx +56 -0
- package/src/panels/material/MaterialLibrary.tsx +253 -0
- package/src/panels/material/MaterialNode.tsx +453 -0
- package/src/panels/material/MaterialNodePalette.tsx +349 -0
- package/src/panels/material/MaterialParameterControls.tsx +525 -0
- package/src/panels/material/MaterialRerouteNode.tsx +42 -0
- package/src/panels/material/MaterialWorkspace.tsx +501 -0
- package/src/panels/material/NodePreview.tsx +70 -0
- package/src/panels/material/flowModel.ts +441 -0
- package/src/panels/material/parameterValues.ts +231 -0
- package/src/panels/material/previewScheduler.ts +235 -0
- package/src/panels/material/reactFlow.css +6 -0
- package/src/panels/material/socketGlyph.ts +85 -0
- package/src/panels/material/viewportMemory.ts +58 -0
- package/src/panels/preferences/PreferencesDialog.tsx +215 -0
- package/src/panels/share/ShareComponentDialog.tsx +247 -0
- package/src/panels/stage/StageMenu.tsx +35 -5
- package/src/panels/stage/StagePanel.tsx +338 -23
- package/src/panels/stage/cellSlots.tsx +70 -0
- package/src/panels/storyboard/BoardCanvas.tsx +739 -0
- package/src/panels/storyboard/BoardCursors.tsx +158 -0
- package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
- package/src/panels/storyboard/BoardPlan.tsx +42 -0
- package/src/panels/storyboard/ComponentSheet.tsx +187 -0
- package/src/panels/storyboard/ComponentStage.tsx +235 -0
- package/src/panels/storyboard/MiniSketch.tsx +173 -0
- package/src/panels/storyboard/PartPicker.tsx +64 -0
- package/src/panels/storyboard/PlanPanel.tsx +617 -0
- package/src/panels/storyboard/ReferencePreview.tsx +217 -0
- package/src/panels/storyboard/ShotBrief.tsx +360 -0
- package/src/panels/storyboard/ShotCard.tsx +251 -0
- package/src/panels/storyboard/StagePreview.tsx +348 -0
- package/src/panels/storyboard/StillThumbs.tsx +162 -0
- package/src/panels/storyboard/StoryboardView.tsx +79 -0
- package/src/panels/storyboard/board.css +1065 -0
- package/src/panels/storyboard/board.ts +12 -0
- package/src/panels/storyboard/boardClipboard.ts +111 -0
- package/src/panels/storyboard/boardOrder.ts +68 -0
- package/src/panels/storyboard/boardRows.tsx +425 -0
- package/src/panels/storyboard/liveCap.ts +90 -0
- package/src/panels/storyboard/plan.css +295 -0
- package/src/panels/storyboard/posterCache.ts +133 -0
- package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
- package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
- package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
- package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
- package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
- package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
- package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
- package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
- package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
- package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
- package/src/panels/storyboard/shotboard/sketch.css +1392 -0
- package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
- package/src/panels/storyboard/storyboardDrop.ts +164 -0
- package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
- package/src/panels/studio/ComponentSidePanel.tsx +355 -0
- package/src/panels/studio/ComponentStudio.tsx +243 -0
- package/src/panels/studio/ComponentsHome.tsx +318 -0
- package/src/panels/studio/ComponentsPreview.tsx +179 -0
- package/src/panels/studio/EveryUse.tsx +244 -0
- package/src/panels/studio/ThisUsePanel.tsx +679 -0
- package/src/panels/studio/componentParts.tsx +341 -0
- package/src/panels/studio/components.ts +6 -0
- package/src/panels/studio/newCodeComponent.ts +66 -0
- package/src/panels/timeline/AudioFxButton.tsx +290 -0
- package/src/panels/timeline/AudioLane.tsx +674 -85
- package/src/panels/timeline/BlockRow.tsx +154 -85
- package/src/panels/timeline/ChannelRow.tsx +378 -129
- package/src/panels/timeline/CurvePane.tsx +508 -0
- package/src/panels/timeline/Filmstrip.tsx +361 -0
- package/src/panels/timeline/GenerateDrawer.tsx +407 -0
- package/src/panels/timeline/KeyStretch.tsx +115 -0
- package/src/panels/timeline/LifespanRow.tsx +730 -47
- package/src/panels/timeline/MarkerLane.tsx +46 -8
- package/src/panels/timeline/PlayButton.tsx +91 -0
- package/src/panels/timeline/PropertyPicker.tsx +254 -0
- package/src/panels/timeline/ShotRow.tsx +400 -0
- package/src/panels/timeline/SoundMode.tsx +1406 -0
- package/src/panels/timeline/TimelineDock.tsx +2338 -272
- package/src/panels/timeline/TransportVolume.tsx +163 -0
- package/src/panels/timeline/beatRuler.ts +74 -0
- package/src/panels/timeline/curveModel.ts +500 -0
- package/src/panels/timeline/duckUnderVoice.ts +68 -0
- package/src/panels/timeline/keyframeMenu.ts +138 -0
- package/src/panels/timeline/labelWidth.ts +49 -0
- package/src/panels/timeline/marquee.ts +155 -0
- package/src/panels/timeline/model.ts +1860 -199
- package/src/panels/timeline/snap.ts +125 -43
- package/src/panels/timeline/staggerPreview.tsx +92 -0
- package/src/panels/timeline/takeMeasure.ts +72 -0
- package/src/panels/timeline/useLive.ts +48 -0
- package/src/panels/timeline/viewport.ts +234 -0
- package/src/panels/toolbar/BackChip.tsx +116 -0
- package/src/panels/toolbar/CameraViewBar.tsx +118 -49
- package/src/panels/toolbar/CanvasBar.tsx +117 -0
- package/src/panels/toolbar/InsertButton.tsx +38 -0
- package/src/panels/toolbar/IsolationTrail.tsx +156 -0
- package/src/panels/toolbar/PanelToggles.tsx +86 -0
- package/src/panels/toolbar/ShadingBar.tsx +119 -26
- package/src/panels/toolbar/ToolDockBar.tsx +329 -80
- package/src/panels/toolbar/ToolFooter.tsx +102 -0
- package/src/panels/toolbar/ViewModeBar.tsx +247 -38
- package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
- package/src/panels/toolbar/useAddRows.tsx +326 -0
- package/src/panels/toolbar/useDismiss.ts +122 -0
- package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
- package/src/panels/versions/versionModel.ts +103 -0
- package/src/panels/virtualWindow.ts +271 -0
- package/src/shotTokens.css +151 -60
- package/src/stage/FrustumGizmo.tsx +504 -84
- package/src/stage/GridPlane.tsx +225 -16
- package/src/stage/NodePreviews.tsx +628 -0
- package/src/stage/PerfHud.tsx +437 -47
- package/src/stage/SplitRenderer.tsx +816 -169
- package/src/stage/StageApp.tsx +4274 -486
- package/src/stage/StageRootBoundary.tsx +114 -0
- package/src/stage/StageTools.tsx +651 -151
- package/src/stage/TransformGizmo.tsx +696 -0
- package/src/stage/adaptivePresentation.ts +145 -0
- package/src/stage/bridgeClient.ts +2522 -41
- package/src/stage/exportWorker.ts +9 -0
- package/src/stage/feed.ts +305 -14
- package/src/stage/fontPreview.ts +176 -0
- package/src/stage/frustumGeometry.ts +319 -1
- package/src/stage/furnitureTokens.ts +33 -0
- package/src/stage/gizmoMath.ts +508 -16
- package/src/stage/gpuTimer.ts +276 -0
- package/src/stage/instanceModules.ts +194 -33
- package/src/stage/interactions/move.ts +24 -5
- package/src/stage/isolation.ts +291 -33
- package/src/stage/jsSelfProfiler.ts +325 -0
- package/src/stage/main.tsx +116 -16
- package/src/stage/modalState.ts +222 -23
- package/src/stage/moduleEpoch.ts +60 -0
- package/src/stage/motionPathStage.ts +279 -0
- package/src/stage/motionPreview.ts +74 -0
- package/src/stage/overlays/Overlays.tsx +1112 -159
- package/src/stage/overlays/Rulers.tsx +495 -0
- package/src/stage/panes.ts +159 -10
- package/src/stage/project.ts +68 -3
- package/src/stage/renderScaleController.ts +730 -0
- package/src/stage/rulers.ts +129 -0
- package/src/stage/sceneExtent.ts +75 -0
- package/src/stage/shading.ts +20 -0
- package/src/stage/splineStage.ts +632 -0
- package/src/stage/stagePerformanceTelemetry.ts +717 -0
- package/src/stage/stageTheme.ts +36 -0
- package/src/stage/stageWarmup.ts +11 -0
- package/src/stage/textAutoSize.ts +124 -0
- package/src/stage/tier1Export.ts +641 -0
- package/src/stage/tokenColor.ts +14 -9
- package/src/stage/view.ts +56 -9
- package/src/stage/workingView.ts +277 -33
- package/src/state/accountPrefs.ts +261 -0
- package/src/state/agentActions.ts +173 -15
- package/src/state/agentActivity.ts +198 -0
- package/src/state/agentQuestion.ts +239 -0
- package/src/state/bootOpen.ts +42 -0
- package/src/state/cameraVerbs.ts +139 -0
- package/src/state/clientId.ts +6 -1
- package/src/state/comments.ts +1099 -0
- package/src/state/context.tsx +19 -1
- package/src/state/editorPrefs.ts +220 -0
- package/src/state/errorReports.ts +121 -0
- package/src/state/fieldWrite.ts +161 -0
- package/src/state/fontRecents.ts +70 -0
- package/src/state/fonts.ts +656 -0
- package/src/state/graphClipboard.ts +414 -0
- package/src/state/imageThumbs.ts +216 -0
- package/src/state/insert.ts +444 -67
- package/src/state/isolationTrail.ts +92 -0
- package/src/state/keyMoves.ts +134 -0
- package/src/state/keyframeClipboard.ts +177 -0
- package/src/state/keymap.ts +1153 -117
- package/src/state/layoutPrefs.ts +272 -0
- package/src/state/layouts.ts +205 -0
- package/src/state/measureMedia.ts +167 -0
- package/src/state/menu.ts +2341 -28
- package/src/state/motionStamp.ts +7 -0
- package/src/state/panelSize.ts +375 -5
- package/src/state/pendingChanges.ts +119 -0
- package/src/state/playHold.ts +78 -0
- package/src/state/playbackPreparation.ts +562 -0
- package/src/state/posterCapture.ts +242 -0
- package/src/state/presence.ts +254 -0
- package/src/state/projectComponents.ts +160 -0
- package/src/state/renderEvents.ts +298 -18
- package/src/state/runtimeErrors.ts +46 -0
- package/src/state/selection.ts +12 -0
- package/src/state/shortcuts.ts +1606 -0
- package/src/state/sketchGuide.ts +51 -0
- package/src/state/splineRefs.ts +87 -0
- package/src/state/stageHealth.ts +259 -0
- package/src/state/stageWatchdog.ts +47 -0
- package/src/state/stillStage.ts +330 -0
- package/src/state/stillThumbs.ts +474 -0
- package/src/state/store.ts +23591 -2982
- package/src/state/storyboardModel.ts +528 -0
- package/src/state/sync.ts +1257 -0
- package/src/state/syncCache.ts +159 -0
- package/src/state/triangles.ts +13 -0
- package/src/state/types.ts +1698 -55
- package/src/state/unsavedGuard.ts +49 -0
- package/src/state/viewMode.ts +200 -0
- package/src/state/webmcp.ts +1128 -0
- package/src/state/workspace.ts +1147 -0
- package/src/styles/assets-tab.css +304 -0
- package/src/styles/canvas.css +545 -0
- package/src/styles/comments.css +1435 -0
- package/src/styles/controls.css +162 -0
- package/src/styles/dialogs.css +390 -0
- package/src/styles/insert-drawer.css +586 -0
- package/src/styles/inspector-board.css +207 -0
- package/src/styles/inspector-object.css +486 -0
- package/src/styles/inspector-shot.css +252 -0
- package/src/styles/inspector.css +360 -0
- package/src/styles/left-column.css +1628 -0
- package/src/styles/library-preview.css +575 -0
- package/src/styles/library.css +512 -0
- package/src/styles/modes/code.css +569 -0
- package/src/styles/modes/component.css +1561 -0
- package/src/styles/modes/material.css +1201 -0
- package/src/styles/modes/storyboard.css +518 -0
- package/src/styles/share-component.css +49 -0
- package/src/styles/shell.css +653 -0
- package/src/styles/shot-brief.css +360 -0
- package/src/styles/states.css +76 -0
- package/src/styles/sync.css +380 -0
- package/src/styles/timeline-graph.css +384 -0
- package/src/styles/timeline-meters.css +89 -0
- package/src/styles/timeline-rows.css +1959 -0
- package/src/styles/timeline-sound.css +1003 -0
- package/src/styles/timeline.css +754 -0
- package/src/styles/tool-footer.css +525 -0
- package/src/styles/topbar.css +886 -0
- package/src/styles/versions.css +262 -0
- package/src/styles.css +72 -2921
- package/src/tools.ts +108 -23
- package/dist/assets/index-B7notge7.css +0 -1
- package/dist/assets/index-BBE6Ta9L.js +0 -52
- package/src/panels/files/icons.tsx +0 -118
- package/src/panels/header/DocSwitcher.tsx +0 -85
- package/src/panels/header/TransportBar.tsx +0 -86
- package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
- package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
- package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
- package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
- package/src/panels/inspector/animate/useBlocks.ts +0 -43
- package/src/panels/material/MaterialPicker.tsx +0 -172
- package/src/panels/timeline/SceneStrip.tsx +0 -145
- package/src/panels/toolbar/AddMenu.tsx +0 -230
- package/src/stage/MoveGizmo.tsx +0 -411
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
// THIS USE (C4): one place that uses a component, and only what it changed.
|
|
2
|
+
//
|
|
3
|
+
// A use is named by its key (`cardUseKey`, `layerUseKey`), so every surface
|
|
4
|
+
// that shows one passes the same key to the same store verbs:
|
|
5
|
+
//
|
|
6
|
+
// ThisUsePanel the whole panel: the head, then every prop of the master
|
|
7
|
+
// with a blue dot on the ones this use changed. The
|
|
8
|
+
// Components right panel shows it for the use picked in Every
|
|
9
|
+
// use, and the board's card sheet shows it for a card.
|
|
10
|
+
// ThisUseBlock the head alone, over the Studio inspector's own prop rows
|
|
11
|
+
// for a selected component or instance layer.
|
|
12
|
+
// ComponentOriginPanel
|
|
13
|
+
// the Components right panel when a Shot door opened the
|
|
14
|
+
// component (C7): this use's panel, then where it sits in
|
|
15
|
+
// that Shot and the master's other uses.
|
|
16
|
+
// InTheStudioBlock
|
|
17
|
+
// the Studio inspector's way into Components for a selected
|
|
18
|
+
// component or instance layer.
|
|
19
|
+
//
|
|
20
|
+
// Writes go through `setUseProp` (one undo step, equal-to-master stores
|
|
21
|
+
// nothing), `resetComponentUse` (Reset all to master) and
|
|
22
|
+
// `detachComponentUse`. A code component's contract is loaded here, since its
|
|
23
|
+
// props and their defaults come from it.
|
|
24
|
+
//
|
|
25
|
+
// THE ROW IS `UsePropRow`, and the Studio inspector's override rows for a
|
|
26
|
+
// placed Studio-made component (ComponentSection) are this same row: one use's
|
|
27
|
+
// prop is one control wherever it is shown, written by one rule
|
|
28
|
+
// (`writeUseValue`).
|
|
29
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
30
|
+
import type { ReactNode } from "react";
|
|
31
|
+
import { PropRow, useLocked } from "@dailies-studio/ui";
|
|
32
|
+
import type { PropControlAsset, ScrubHandlers } from "@dailies-studio/ui";
|
|
33
|
+
import {
|
|
34
|
+
appliedOverride,
|
|
35
|
+
defDurationFrames,
|
|
36
|
+
homeOf,
|
|
37
|
+
instanceExportOf,
|
|
38
|
+
isDefId,
|
|
39
|
+
type ComponentDef3D,
|
|
40
|
+
type ComponentUse,
|
|
41
|
+
type ExposedProp3D,
|
|
42
|
+
} from "@dailies-studio/shot/doc";
|
|
43
|
+
import { controlLabel, orderSpecs, type ControlSpec } from "@dailies-studio/contract";
|
|
44
|
+
import { framesToSeconds, type Value } from "@dailies-studio/engine";
|
|
45
|
+
import { COMPONENT_ICON } from "../../icons.js";
|
|
46
|
+
import { useShotEditor, useStore } from "../../state/context.js";
|
|
47
|
+
import type { ComponentUpdateRemoved, ComponentsOrigin, ComponentsSelection } from "../../state/types.js";
|
|
48
|
+
import {
|
|
49
|
+
BUILTIN_NO_MASTER,
|
|
50
|
+
changeLabel,
|
|
51
|
+
contractOfUse,
|
|
52
|
+
copyUpdateOf,
|
|
53
|
+
detachRefusal,
|
|
54
|
+
isBuiltinComponent,
|
|
55
|
+
layerUseKey,
|
|
56
|
+
masterValueOf,
|
|
57
|
+
propLabelOf,
|
|
58
|
+
sameUseValue,
|
|
59
|
+
shotLabel,
|
|
60
|
+
useByKey,
|
|
61
|
+
useKeyOf,
|
|
62
|
+
usePropRefusal,
|
|
63
|
+
useRowText,
|
|
64
|
+
usesOfSubject,
|
|
65
|
+
useTitle,
|
|
66
|
+
workspaceRowOf,
|
|
67
|
+
writeUseValue,
|
|
68
|
+
} from "../../state/workspace.js";
|
|
69
|
+
import { clock, formatDuration, lifespanOf } from "../timeline/model.js";
|
|
70
|
+
import { useScrub } from "../inspector/useDocWrite.js";
|
|
71
|
+
import { exposedRowOf, masterRowValue, outsideRangeOf, projectAssetsOf, propEditOf, shownPropValue } from "../inspector/propValue.js";
|
|
72
|
+
import type { ExposedRow } from "../inspector/propValue.js";
|
|
73
|
+
|
|
74
|
+
/** The master a use links to, as Components selects it. */
|
|
75
|
+
function masterOf(use: ComponentUse): ComponentsSelection | null {
|
|
76
|
+
if (use.def !== undefined) return { kind: "studio", def: use.def };
|
|
77
|
+
return use.component === undefined ? null : { kind: "code", module: use.component };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The use a key names in the open document, live. */
|
|
81
|
+
function useUse(useKey: string): ComponentUse | null {
|
|
82
|
+
const doc = useShotEditor((s) => s.doc);
|
|
83
|
+
const contracts = useShotEditor((s) => s.contracts);
|
|
84
|
+
return useMemo(() => (doc === null ? null : useByKey(doc, useKey, contracts)), [doc, useKey, contracts]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** A code use's contract, loaded once per module. */
|
|
88
|
+
function useContractOf(use: ComponentUse | null): void {
|
|
89
|
+
const store = useStore();
|
|
90
|
+
const module = use?.component ?? null;
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (module !== null) void store.loadContract(module);
|
|
93
|
+
}, [store, module]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** "Phone 3D" and the master's version this use follows: the copy's own
|
|
97
|
+
* version for a copied definition, else the workspace's latest. */
|
|
98
|
+
function useMasterFacts(use: ComponentUse | null): { name: string; version: number | null } {
|
|
99
|
+
const doc = useShotEditor((s) => s.doc);
|
|
100
|
+
const library = useShotEditor((s) => s.library);
|
|
101
|
+
const list = useShotEditor((s) => s.workspaceComponents);
|
|
102
|
+
if (use === null || doc === null) return { name: "", version: null };
|
|
103
|
+
const sel = masterOf(use);
|
|
104
|
+
const row = workspaceRowOf(list, doc.id, sel);
|
|
105
|
+
if (use.def !== undefined) {
|
|
106
|
+
const def = doc.components?.[use.def];
|
|
107
|
+
return { name: def?.name ?? "Component", version: def?.origin?.version ?? row?.version ?? null };
|
|
108
|
+
}
|
|
109
|
+
const id = use.component ?? "";
|
|
110
|
+
return { name: library.find((r) => r.id === id)?.name ?? instanceExportOf(id), version: row?.version ?? null };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The head: "This use", where it is, what it links to, Edit master and
|
|
115
|
+
* Detach, and Update when the copy's source has a newer version.
|
|
116
|
+
*/
|
|
117
|
+
export function ThisUseBlock(props: { useKey: string; resetAll?: boolean; note?: string }) {
|
|
118
|
+
const store = useStore();
|
|
119
|
+
const doc = useShotEditor((s) => s.doc);
|
|
120
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
121
|
+
const use = useUse(props.useKey);
|
|
122
|
+
const facts = useMasterFacts(use);
|
|
123
|
+
// A built-in ships inside a package: nothing to open, so no Edit master.
|
|
124
|
+
const builtin = useShotEditor((s) => isBuiltinComponent(s.library, use?.component));
|
|
125
|
+
useContractOf(use);
|
|
126
|
+
if (doc === null || use === null) return null;
|
|
127
|
+
const sel = masterOf(use);
|
|
128
|
+
// A code component and a board card cannot be detached. The button says so
|
|
129
|
+
// before it is pressed (the house refusal: dimmed, still pressable, its
|
|
130
|
+
// title and its press give the reason), in the store's own words.
|
|
131
|
+
const refused = detachRefusal(use, props.useKey);
|
|
132
|
+
return (
|
|
133
|
+
<div className="this-use-head" data-testid="this-use-head">
|
|
134
|
+
<div className="this-use-titles">
|
|
135
|
+
<span className="this-use-caps">This use</span>
|
|
136
|
+
<span className="this-use-title" data-testid="this-use-title">
|
|
137
|
+
{useTitle(doc, use)}
|
|
138
|
+
</span>
|
|
139
|
+
<span className="this-use-linked" data-testid="this-use-linked">
|
|
140
|
+
Linked to {facts.name} master{facts.version === null ? "" : ` v${facts.version}`}
|
|
141
|
+
</span>
|
|
142
|
+
</div>
|
|
143
|
+
{props.note === undefined ? null : (
|
|
144
|
+
<p className="this-use-help" data-testid="this-use-note">
|
|
145
|
+
{props.note}
|
|
146
|
+
</p>
|
|
147
|
+
)}
|
|
148
|
+
{/* The house row of buttons (`.insp-buttons`): 28px house buttons that
|
|
149
|
+
share the row by their words, as every verb row in the inspector. */}
|
|
150
|
+
<div className="insp-buttons">
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
className="btn"
|
|
154
|
+
data-testid="this-use-edit-master"
|
|
155
|
+
disabled={sel === null || builtin}
|
|
156
|
+
title={builtin ? BUILTIN_NO_MASTER : "Edit the master. Props without a dot follow the change."}
|
|
157
|
+
onClick={() => {
|
|
158
|
+
if (sel !== null) void store.editComponentMaster(sel);
|
|
159
|
+
}}
|
|
160
|
+
>
|
|
161
|
+
Edit master
|
|
162
|
+
</button>
|
|
163
|
+
<button
|
|
164
|
+
type="button"
|
|
165
|
+
className="btn"
|
|
166
|
+
data-testid="this-use-detach"
|
|
167
|
+
disabled={readOnly}
|
|
168
|
+
{...(refused !== null ? { "aria-disabled": true } : {})}
|
|
169
|
+
title={refused ?? "Make this use its own copy. It stops following the master."}
|
|
170
|
+
onClick={() => store.detachComponentUse(props.useKey)}
|
|
171
|
+
>
|
|
172
|
+
Detach
|
|
173
|
+
</button>
|
|
174
|
+
</div>
|
|
175
|
+
{props.resetAll === true ? (
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
className="this-use-reset-all is-inline"
|
|
179
|
+
data-testid="this-use-reset-all"
|
|
180
|
+
disabled={readOnly || use.overrides.length === 0}
|
|
181
|
+
onClick={() => store.resetComponentUse(props.useKey)}
|
|
182
|
+
>
|
|
183
|
+
Reset all to master
|
|
184
|
+
</button>
|
|
185
|
+
) : null}
|
|
186
|
+
{use.def === undefined ? null : <UpdateAvailable defId={use.def} />}
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* "Update available · vN" for a copied definition whose source moved on: the
|
|
193
|
+
* workspace's latest for a `cpt_` copy, the Community listing's for a `cml-`
|
|
194
|
+
* one. A code component never has one (it is live everywhere). Before an
|
|
195
|
+
* update that drops props a use changed, the list of them, then Update
|
|
196
|
+
* anyway or Cancel. A Community update always asks first, with the same
|
|
197
|
+
* list read from the listing: the server writes it, so after it comes the
|
|
198
|
+
* list again with Revert update until the next change.
|
|
199
|
+
*/
|
|
200
|
+
export function UpdateAvailable(props: { defId: string }) {
|
|
201
|
+
const store = useStore();
|
|
202
|
+
const def = useShotEditor((s) => s.doc?.components?.[props.defId]);
|
|
203
|
+
const list = useShotEditor((s) => s.workspaceComponents);
|
|
204
|
+
const listings = useShotEditor((s) => s.componentListingUpdates);
|
|
205
|
+
const pending = useShotEditor((s) => (s.componentUpdate?.defId === props.defId ? s.componentUpdate : null));
|
|
206
|
+
const applied = useShotEditor((s) => (s.componentUpdated?.defId === props.defId ? s.componentUpdated : null));
|
|
207
|
+
const canRevert = useShotEditor((s) => s.componentUpdated !== null && s.doc === s.componentUpdated.after && !s.readOnly);
|
|
208
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
209
|
+
const source = def?.origin?.source ?? null;
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (source === null) return;
|
|
212
|
+
if (store.getState().workspaceComponents === null) void store.refreshWorkspaceComponents();
|
|
213
|
+
void store.refreshListingUpdates();
|
|
214
|
+
}, [store, source]);
|
|
215
|
+
const update = copyUpdateOf(def, list, listings);
|
|
216
|
+
if (update === null && applied === null) return null;
|
|
217
|
+
return (
|
|
218
|
+
<div className="this-use-update" data-testid="this-use-update">
|
|
219
|
+
{update === null ? null : (
|
|
220
|
+
<div className="this-use-update-row">
|
|
221
|
+
<span className="use-chip" data-testid="this-use-update-chip">
|
|
222
|
+
Update available · v{update.version}
|
|
223
|
+
</span>
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
className="use-update-button"
|
|
227
|
+
data-testid="this-use-update-apply"
|
|
228
|
+
disabled={readOnly || pending !== null}
|
|
229
|
+
onClick={() => void store.updateComponentCopy(props.defId)}
|
|
230
|
+
>
|
|
231
|
+
Update
|
|
232
|
+
</button>
|
|
233
|
+
</div>
|
|
234
|
+
)}
|
|
235
|
+
{pending === null ? null : (
|
|
236
|
+
<div className="this-use-update-confirm" data-testid="this-use-update-confirm">
|
|
237
|
+
{pending.community ? (
|
|
238
|
+
<p className="this-use-help" data-testid="this-use-update-note">
|
|
239
|
+
The server writes v{pending.version} into this Project, so Undo may not take it back. Revert update can,
|
|
240
|
+
until your next change.
|
|
241
|
+
{pending.removed === null
|
|
242
|
+
? ` Changes with no prop in v${pending.version} are kept aside and listed after.`
|
|
243
|
+
: pending.removed.length === 0
|
|
244
|
+
? ""
|
|
245
|
+
: ` These changes have no prop in v${pending.version} and are kept aside, not applied:`}
|
|
246
|
+
</p>
|
|
247
|
+
) : (
|
|
248
|
+
<p className="this-use-help" data-testid="this-use-update-note">
|
|
249
|
+
v{pending.version} has no prop for some changes these uses made. They are kept aside, not applied:
|
|
250
|
+
</p>
|
|
251
|
+
)}
|
|
252
|
+
{pending.removed === null || pending.removed.length === 0 ? null : <RemovedList removed={pending.removed} />}
|
|
253
|
+
<div className="insp-buttons">
|
|
254
|
+
<button
|
|
255
|
+
type="button"
|
|
256
|
+
className="use-update-button"
|
|
257
|
+
data-testid="this-use-update-confirm-apply"
|
|
258
|
+
onClick={() => void store.updateComponentCopy(props.defId, true)}
|
|
259
|
+
>
|
|
260
|
+
{pending.removed === null || pending.removed.length === 0 ? "Update" : "Update anyway"}
|
|
261
|
+
</button>
|
|
262
|
+
<button
|
|
263
|
+
type="button"
|
|
264
|
+
className="btn"
|
|
265
|
+
data-testid="this-use-update-cancel"
|
|
266
|
+
onClick={() => store.cancelComponentUpdate()}
|
|
267
|
+
>
|
|
268
|
+
Cancel
|
|
269
|
+
</button>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
)}
|
|
273
|
+
{applied === null ? null : (
|
|
274
|
+
<div className="this-use-update-confirm" data-testid="this-use-updated">
|
|
275
|
+
<p className="this-use-help" data-testid="this-use-updated-note">
|
|
276
|
+
Updated to v{applied.version}.
|
|
277
|
+
{applied.removed.length === 0 ? "" : " These changes have no prop in it and are kept aside, not applied:"}
|
|
278
|
+
</p>
|
|
279
|
+
{applied.removed.length === 0 ? null : <RemovedList removed={applied.removed} />}
|
|
280
|
+
<div className="insp-buttons">
|
|
281
|
+
{canRevert ? (
|
|
282
|
+
<button
|
|
283
|
+
type="button"
|
|
284
|
+
className="use-update-button"
|
|
285
|
+
data-testid="this-use-update-revert"
|
|
286
|
+
onClick={() => store.revertComponentUpdate()}
|
|
287
|
+
>
|
|
288
|
+
Revert update
|
|
289
|
+
</button>
|
|
290
|
+
) : null}
|
|
291
|
+
<button
|
|
292
|
+
type="button"
|
|
293
|
+
className="btn"
|
|
294
|
+
data-testid="this-use-updated-done"
|
|
295
|
+
onClick={() => store.cancelComponentUpdate()}
|
|
296
|
+
>
|
|
297
|
+
Done
|
|
298
|
+
</button>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function RemovedList(props: { removed: readonly ComponentUpdateRemoved[] }) {
|
|
307
|
+
return (
|
|
308
|
+
<ul className="this-use-removed">
|
|
309
|
+
{props.removed.map((r) => (
|
|
310
|
+
<li key={r.where} data-testid="this-use-removed">
|
|
311
|
+
<span className="this-use-removed-where">{r.where}</span>
|
|
312
|
+
<span className="this-use-removed-keys">{r.keys.join(", ")}</span>
|
|
313
|
+
</li>
|
|
314
|
+
))}
|
|
315
|
+
</ul>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** One prop of a master, as a use's row draws it. A definition's carries the
|
|
320
|
+
* exposed record and the definition, which a stored override is read
|
|
321
|
+
* against (`appliedOverride`: its `renamedFrom` keys, its target). */
|
|
322
|
+
interface MasterProp extends ExposedRow {
|
|
323
|
+
exposed?: { prop: ExposedProp3D; def: ComponentDef3D };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** The master's props, as rows: a definition's exposed props, each from what
|
|
327
|
+
* it drives (`exposedRowOf`), or a code component's contract keys in its own
|
|
328
|
+
* order (the live contract, else a placed layer's snapshot), every kind
|
|
329
|
+
* listed (a slot or an event reads "set in code", as it does in the Studio).
|
|
330
|
+
* Null while a code component's contract is not in reach. */
|
|
331
|
+
function useMasterProps(use: ComponentUse | null): MasterProp[] | null {
|
|
332
|
+
const doc = useShotEditor((s) => s.doc);
|
|
333
|
+
const contracts = useShotEditor((s) => s.contracts);
|
|
334
|
+
return useMemo(() => {
|
|
335
|
+
if (use === null || doc === null) return [];
|
|
336
|
+
if (use.def !== undefined) {
|
|
337
|
+
const def = doc.components?.[use.def];
|
|
338
|
+
if (def === undefined) return [];
|
|
339
|
+
return def.exposed.map((prop) => ({ ...exposedRowOf(prop, def, doc.materials, contracts), exposed: { prop, def } }));
|
|
340
|
+
}
|
|
341
|
+
const contract = contractOfUse(doc, contracts, use);
|
|
342
|
+
if (contract === null) return null;
|
|
343
|
+
return orderSpecs(contract).map((spec) => ({ spec, opaqueColor: false, undescribed: false }));
|
|
344
|
+
}, [use, doc, contracts]);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** What one use stores for one prop that reaches the screen: a definition's
|
|
348
|
+
* override as the renderer writes it (`appliedOverride`: under a
|
|
349
|
+
* `renamedFrom` key too, and nothing for a value it quarantines, whose row
|
|
350
|
+
* follows the master as the usage index counts it), or a code use's prop. */
|
|
351
|
+
function storedOf(use: ComponentUse, prop: MasterProp): Value | undefined {
|
|
352
|
+
return prop.exposed !== undefined
|
|
353
|
+
? appliedOverride(prop.exposed.def, prop.exposed.prop, use.values)?.value
|
|
354
|
+
: use.values[prop.spec.key];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* THE WHOLE PANEL: the head, then every prop of the master. A prop this use
|
|
359
|
+
* changed wears the blue dot and its own Reset; the rest follow the master.
|
|
360
|
+
*/
|
|
361
|
+
export function ThisUsePanel(props: { useKey: string; note?: string; propsLabel?: string; children?: ReactNode }) {
|
|
362
|
+
const store = useStore();
|
|
363
|
+
const doc = useShotEditor((s) => s.doc);
|
|
364
|
+
const contracts = useShotEditor((s) => s.contracts);
|
|
365
|
+
const readOnly = useShotEditor((s) => s.readOnly);
|
|
366
|
+
const use = useUse(props.useKey);
|
|
367
|
+
const masterProps = useMasterProps(use);
|
|
368
|
+
const assetTable = doc?.assets;
|
|
369
|
+
const assets = useMemo(() => projectAssetsOf(assetTable), [assetTable]);
|
|
370
|
+
// A contract never arrives for a component the registry no longer has: once
|
|
371
|
+
// the registry has answered without it, the panel says so rather than
|
|
372
|
+
// reading for ever.
|
|
373
|
+
const unlisted = useShotEditor(
|
|
374
|
+
(s) => s.libraryLoaded && use?.component !== undefined && !s.library.some((r) => r.id === use.component),
|
|
375
|
+
);
|
|
376
|
+
if (use === null || doc === null) {
|
|
377
|
+
return (
|
|
378
|
+
<section className="this-use" data-testid="this-use">
|
|
379
|
+
<p className="insp-empty" data-testid="this-use-gone">
|
|
380
|
+
This use is gone. It was deleted or detached.
|
|
381
|
+
</p>
|
|
382
|
+
</section>
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
return (
|
|
386
|
+
<section className="this-use" data-testid="this-use" aria-label="This use">
|
|
387
|
+
<ThisUseBlock useKey={props.useKey} {...(props.note === undefined ? {} : { note: props.note })} />
|
|
388
|
+
<div className="this-use-props">
|
|
389
|
+
<div className="this-use-props-head">
|
|
390
|
+
<span className="this-use-caps">{props.propsLabel ?? "Props"}</span>
|
|
391
|
+
<button
|
|
392
|
+
type="button"
|
|
393
|
+
className="this-use-reset-all"
|
|
394
|
+
data-testid="this-use-reset-all"
|
|
395
|
+
disabled={readOnly || use.overrides.length === 0}
|
|
396
|
+
onClick={() => store.resetComponentUse(props.useKey)}
|
|
397
|
+
>
|
|
398
|
+
Reset all to master
|
|
399
|
+
</button>
|
|
400
|
+
</div>
|
|
401
|
+
{masterProps === null ? (
|
|
402
|
+
<p className="insp-empty" data-testid="this-use-props-unread">
|
|
403
|
+
{unlisted
|
|
404
|
+
? "This component is not in the project's registry, so its props cannot be read."
|
|
405
|
+
: "Reading its props…"}
|
|
406
|
+
</p>
|
|
407
|
+
) : masterProps.length === 0 ? (
|
|
408
|
+
<p className="insp-empty">This component has no props.</p>
|
|
409
|
+
) : (
|
|
410
|
+
masterProps.map((prop) => (
|
|
411
|
+
<UsePropRow
|
|
412
|
+
key={prop.spec.key}
|
|
413
|
+
useKey={props.useKey}
|
|
414
|
+
row={prop}
|
|
415
|
+
stored={storedOf(use, prop)}
|
|
416
|
+
master={masterValueOf(doc, contracts, use, prop.spec.key)}
|
|
417
|
+
assets={assets}
|
|
418
|
+
/>
|
|
419
|
+
))
|
|
420
|
+
)}
|
|
421
|
+
<p className="this-use-help">Blue dot: changed here only. Props without a dot follow the master when you edit it.</p>
|
|
422
|
+
</div>
|
|
423
|
+
{props.children}
|
|
424
|
+
</section>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* C7: the right panel while a Shot door's component is on Preview. This use
|
|
430
|
+
* first (its props change this Shot only), then where the layer sits in the
|
|
431
|
+
* Shot, read-only (moving and timing it is the Studio's job), then the
|
|
432
|
+
* master's other uses.
|
|
433
|
+
*/
|
|
434
|
+
export function ComponentOriginPanel(props: { origin: ComponentsOrigin }) {
|
|
435
|
+
const { origin } = props;
|
|
436
|
+
return (
|
|
437
|
+
<ThisUsePanel useKey={origin.useKey} note="Changes here apply to this Shot only." propsLabel="Props · this use">
|
|
438
|
+
<InTheShot useKey={origin.useKey} />
|
|
439
|
+
<OtherUses origin={origin} />
|
|
440
|
+
</ThisUsePanel>
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/** "Placed at" and "On screen" for the layer a use names. */
|
|
445
|
+
function InTheShot(props: { useKey: string }) {
|
|
446
|
+
const doc = useShotEditor((s) => s.doc);
|
|
447
|
+
const use = useUse(props.useKey);
|
|
448
|
+
if (doc === null || use === null || use.layerId === undefined) return null;
|
|
449
|
+
const container = use.sceneId ?? use.inDef ?? null;
|
|
450
|
+
const layer = container === null ? undefined : homeOf(doc, container)?.layersById[use.layerId];
|
|
451
|
+
if (container === null || layer === undefined) return null;
|
|
452
|
+
const def = isDefId(container) ? doc.components?.[container] : undefined;
|
|
453
|
+
const length = def !== undefined ? defDurationFrames(def) : (doc.scenesById[container]?.durationFrames ?? 1);
|
|
454
|
+
const life = lifespanOf(layer, length);
|
|
455
|
+
const [x, y, z] = layer.transform.position;
|
|
456
|
+
const round = (n: number): number => Math.round(n);
|
|
457
|
+
return (
|
|
458
|
+
<div className="this-use-props" data-testid="origin-in-the-shot">
|
|
459
|
+
<div className="this-use-props-head">
|
|
460
|
+
<span className="this-use-caps">In the Shot</span>
|
|
461
|
+
</div>
|
|
462
|
+
<dl className="origin-facts">
|
|
463
|
+
<dt>Placed at</dt>
|
|
464
|
+
<dd data-testid="origin-placed-at">
|
|
465
|
+
{round(x)}, {round(y)}, {round(z)}
|
|
466
|
+
</dd>
|
|
467
|
+
<dt>On screen</dt>
|
|
468
|
+
<dd data-testid="origin-on-screen">
|
|
469
|
+
{clock(life.in, doc.fps)} to {clock(life.out, doc.fps)} ·{" "}
|
|
470
|
+
{formatDuration(framesToSeconds(life.out - life.in, doc.fps))}
|
|
471
|
+
</dd>
|
|
472
|
+
</dl>
|
|
473
|
+
<p className="this-use-help">Move and time it in the Studio after Back to Shot.</p>
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** The master's other uses in this document, with what each changed. */
|
|
479
|
+
function OtherUses(props: { origin: ComponentsOrigin }) {
|
|
480
|
+
const doc = useShotEditor((s) => s.doc);
|
|
481
|
+
const contracts = useShotEditor((s) => s.contracts);
|
|
482
|
+
const { sel, useKey } = props.origin;
|
|
483
|
+
const others = useMemo(
|
|
484
|
+
() => (doc === null ? [] : usesOfSubject(doc, sel, contracts).filter((u) => useKeyOf(u) !== useKey)),
|
|
485
|
+
[doc, sel, contracts, useKey],
|
|
486
|
+
);
|
|
487
|
+
if (doc === null) return null;
|
|
488
|
+
const master: Pick<ComponentUse, "def" | "component"> = sel.kind === "studio" ? { def: sel.def } : { component: sel.module };
|
|
489
|
+
const labelOf = (key: string): string => propLabelOf(doc, contracts, master, key);
|
|
490
|
+
return (
|
|
491
|
+
<div className="this-use-props" data-testid="origin-other-uses">
|
|
492
|
+
<div className="this-use-props-head">
|
|
493
|
+
<span className="this-use-caps">Other uses</span>
|
|
494
|
+
</div>
|
|
495
|
+
{others.length === 0 ? (
|
|
496
|
+
<p className="insp-empty">Only used here.</p>
|
|
497
|
+
) : (
|
|
498
|
+
<ul className="origin-uses">
|
|
499
|
+
{others.map((u) => {
|
|
500
|
+
const text = useRowText(doc, u);
|
|
501
|
+
return (
|
|
502
|
+
<li key={useKeyOf(u)} className="origin-use" data-testid="origin-other-use">
|
|
503
|
+
<span className="origin-use-title">{text.title}</span>
|
|
504
|
+
<span className="origin-use-changes">{changeLabel(u, labelOf)}</span>
|
|
505
|
+
</li>
|
|
506
|
+
);
|
|
507
|
+
})}
|
|
508
|
+
</ul>
|
|
509
|
+
)}
|
|
510
|
+
</div>
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* THE STUDIO'S WAY INTO COMPONENTS for one selected component or instance
|
|
516
|
+
* layer: it opens that component standalone, on Preview, with Back to Shot
|
|
517
|
+
* (`openComponentContext`, the double-click's verb).
|
|
518
|
+
*/
|
|
519
|
+
export function InTheStudioBlock(props: { sceneId: string; layerId: string }) {
|
|
520
|
+
const store = useStore();
|
|
521
|
+
const doc = useShotEditor((s) => s.doc);
|
|
522
|
+
const use = useUse(layerUseKey(props.sceneId, props.layerId));
|
|
523
|
+
const facts = useMasterFacts(use);
|
|
524
|
+
const builtin = useShotEditor((s) => isBuiltinComponent(s.library, use?.component));
|
|
525
|
+
if (doc === null || use === null) return null;
|
|
526
|
+
return (
|
|
527
|
+
<div className="in-the-studio" data-testid="in-the-studio">
|
|
528
|
+
<span className="this-use-caps">In the Studio · {shotLabel(doc, props.sceneId)}</span>
|
|
529
|
+
<div className="in-the-studio-row">
|
|
530
|
+
<span className="in-the-studio-icon" aria-hidden="true">
|
|
531
|
+
{COMPONENT_ICON}
|
|
532
|
+
</span>
|
|
533
|
+
<span className="in-the-studio-name" data-testid="in-the-studio-name">
|
|
534
|
+
{facts.name}
|
|
535
|
+
</span>
|
|
536
|
+
</div>
|
|
537
|
+
<button
|
|
538
|
+
type="button"
|
|
539
|
+
className="in-the-studio-open"
|
|
540
|
+
data-testid="open-in-components"
|
|
541
|
+
disabled={builtin}
|
|
542
|
+
title={builtin ? BUILTIN_NO_MASTER : "See it alone in Components"}
|
|
543
|
+
onClick={() => void store.openComponentContext(props.layerId)}
|
|
544
|
+
>
|
|
545
|
+
Open in Components →
|
|
546
|
+
</button>
|
|
547
|
+
<p className="this-use-help">Or double-click it on the stage. Both land here.</p>
|
|
548
|
+
</div>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** What an animated prop's row says, read-only. */
|
|
553
|
+
const ANIMATED_HERE = "Animated in the Shot: edit it there";
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* A use's DRAG, through the same rule as its commit (`writeUseValue`), inside
|
|
557
|
+
* the store's scrub bracket, so the whole gesture is one undo step. A refusal
|
|
558
|
+
* (a locked layer, a value the prop cannot hold) writes nothing and is said
|
|
559
|
+
* ONCE, at the release, rather than per pointer event or not at all: a thumb
|
|
560
|
+
* that moved while the document did not, with no reason given, read as a
|
|
561
|
+
* broken control.
|
|
562
|
+
*/
|
|
563
|
+
function useUseScrub(useKey: string, spec: ControlSpec, fallback: unknown): ScrubHandlers {
|
|
564
|
+
const store = useStore();
|
|
565
|
+
const refusal = useRef<string | null>(null);
|
|
566
|
+
const scrub = useScrub((doc, raw) => {
|
|
567
|
+
const edit = propEditOf(spec, raw, fallback);
|
|
568
|
+
if (edit.kind === "refused") {
|
|
569
|
+
refusal.current = edit.reason;
|
|
570
|
+
return doc;
|
|
571
|
+
}
|
|
572
|
+
const out = writeUseValue(doc, store.getState().contracts, useKey, spec.key, edit.kind === "set" ? edit.value : null);
|
|
573
|
+
refusal.current = out.refusal;
|
|
574
|
+
return out.doc;
|
|
575
|
+
});
|
|
576
|
+
return {
|
|
577
|
+
...scrub,
|
|
578
|
+
end: (commit) => {
|
|
579
|
+
scrub.end(commit);
|
|
580
|
+
if (commit && refusal.current !== null) store.reportError(refusal.current);
|
|
581
|
+
refusal.current = null;
|
|
582
|
+
},
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* ONE PROP OF ONE USE: the master's value until this use changes it, then the
|
|
588
|
+
* blue dot and its own Reset. The board's component sheet, Components' THIS
|
|
589
|
+
* USE and the Studio inspector's override rows for a placed Studio-made
|
|
590
|
+
* component (ComponentSection) all draw this row.
|
|
591
|
+
*
|
|
592
|
+
* READ-ONLY, with the reason, for a prop the use cannot change here: an
|
|
593
|
+
* animated instance prop (only its keyframes change it, in the Shot), and a
|
|
594
|
+
* prop nothing in reach can describe (`ExposedRow.undescribed`).
|
|
595
|
+
*/
|
|
596
|
+
export function UsePropRow(props: {
|
|
597
|
+
useKey: string;
|
|
598
|
+
row: ExposedRow;
|
|
599
|
+
/** What the use stores for the prop that reaches the screen (`storedOf`:
|
|
600
|
+
* read through `renamedFrom`, a quarantined value read as none). */
|
|
601
|
+
stored: Value | undefined;
|
|
602
|
+
/** The master's value (`masterValueOf`): what the use follows while it
|
|
603
|
+
* stores nothing, and what a value equal to it is stored as. */
|
|
604
|
+
master: Value | undefined;
|
|
605
|
+
assets: readonly PropControlAsset[];
|
|
606
|
+
}) {
|
|
607
|
+
const { useKey, row, stored, master } = props;
|
|
608
|
+
const { spec } = row;
|
|
609
|
+
const store = useStore();
|
|
610
|
+
const locked = useLocked();
|
|
611
|
+
const label = controlLabel(spec);
|
|
612
|
+
const animated = useShotEditor((s) => (s.doc === null ? null : usePropRefusal(s.doc, useKey, spec.key, label)));
|
|
613
|
+
// What the row shows while the use stores nothing: the master's value, what
|
|
614
|
+
// this use draws then (`masterRowValue`), so an inherited row reads what is
|
|
615
|
+
// on screen even after the master's field was edited on its own layer.
|
|
616
|
+
const fallback = masterRowValue(spec, master);
|
|
617
|
+
const changed = stored !== undefined && !(master !== undefined && sameUseValue(stored, master, spec.kind));
|
|
618
|
+
const scrub = useUseScrub(useKey, spec, fallback);
|
|
619
|
+
const commit = (raw: unknown): void => {
|
|
620
|
+
const edit = propEditOf(spec, raw, fallback);
|
|
621
|
+
if (edit.kind === "refused") store.reportError(edit.reason);
|
|
622
|
+
else store.setUseProp(useKey, spec.key, edit.kind === "set" ? edit.value : null);
|
|
623
|
+
};
|
|
624
|
+
const readOnly = animated !== null || row.undescribed;
|
|
625
|
+
// A stored value outside a range the component narrowed (or a hand edit
|
|
626
|
+
// put there), said under the row with the verb that brings it inside.
|
|
627
|
+
// Not while the row is read-only: an animated prop's keyframes are its
|
|
628
|
+
// value, and an undescribed one has no range to speak of.
|
|
629
|
+
const outside = readOnly ? null : outsideRangeOf(spec, stored);
|
|
630
|
+
return (
|
|
631
|
+
<PropRow
|
|
632
|
+
spec={spec}
|
|
633
|
+
value={shownPropValue(spec, stored ?? fallback)}
|
|
634
|
+
commit={commit}
|
|
635
|
+
scrub={scrub}
|
|
636
|
+
changed={changed}
|
|
637
|
+
inherited={stored === undefined}
|
|
638
|
+
// A stored value is an opinion even when it matches the master, and
|
|
639
|
+
// only a clear makes the use follow the master's next edit. An animated
|
|
640
|
+
// prop's clear is refused by the write itself, so it offers none.
|
|
641
|
+
{...(stored !== undefined && animated === null
|
|
642
|
+
? {
|
|
643
|
+
reset: {
|
|
644
|
+
onReset: () => store.setUseProp(useKey, spec.key, null),
|
|
645
|
+
title: "Follow the master again",
|
|
646
|
+
props: { "data-testid": `this-use-reset-${spec.key}` },
|
|
647
|
+
},
|
|
648
|
+
}
|
|
649
|
+
: {})}
|
|
650
|
+
{...(readOnly ? { readOnly: true } : {})}
|
|
651
|
+
{...(animated !== null ? { keyed: true } : {})}
|
|
652
|
+
{...(row.opaqueColor ? { opaqueColor: true } : {})}
|
|
653
|
+
notice={
|
|
654
|
+
outside === null ? undefined : (
|
|
655
|
+
<>
|
|
656
|
+
<span>{outside.words}</span>
|
|
657
|
+
<div className="insp-buttons">
|
|
658
|
+
<button
|
|
659
|
+
type="button"
|
|
660
|
+
className="btn"
|
|
661
|
+
disabled={locked}
|
|
662
|
+
data-testid={`this-use-inside-${spec.key}`}
|
|
663
|
+
title={outside.title}
|
|
664
|
+
onClick={() => store.setUseProp(useKey, spec.key, outside.inside)}
|
|
665
|
+
>
|
|
666
|
+
Bring inside
|
|
667
|
+
</button>
|
|
668
|
+
</div>
|
|
669
|
+
</>
|
|
670
|
+
)
|
|
671
|
+
}
|
|
672
|
+
assets={props.assets}
|
|
673
|
+
rowProps={{
|
|
674
|
+
"data-testid": `this-use-prop-${spec.key}`,
|
|
675
|
+
title: animated !== null ? ANIMATED_HERE : changed ? "Changed here only" : "Follows the master",
|
|
676
|
+
}}
|
|
677
|
+
/>
|
|
678
|
+
);
|
|
679
|
+
}
|