@remotion/studio 4.0.457 → 4.0.459
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/components/FramePersistor.js +1 -1
- package/dist/components/PlaybackRatePersistor.js +1 -1
- package/dist/components/PreviewToolbar.js +1 -1
- package/dist/components/Timeline/Padder.d.ts +4 -0
- package/dist/components/Timeline/Padder.js +14 -0
- package/dist/components/Timeline/Timeline.js +10 -3
- package/dist/components/Timeline/TimelineEnumField.d.ts +11 -0
- package/dist/components/Timeline/TimelineEnumField.js +34 -0
- package/dist/components/Timeline/TimelineExpandArrowButton.d.ts +0 -1
- package/dist/components/Timeline/TimelineExpandArrowButton.js +3 -4
- package/dist/components/Timeline/TimelineExpandedRow.d.ts +16 -0
- package/dist/components/Timeline/TimelineExpandedRow.js +49 -0
- package/dist/components/Timeline/TimelineExpandedSection.d.ts +2 -2
- package/dist/components/Timeline/TimelineExpandedSection.js +11 -63
- package/dist/components/Timeline/TimelineFieldRow.d.ts +3 -1
- package/dist/components/Timeline/TimelineFieldRow.js +13 -12
- package/dist/components/Timeline/TimelineListItem.d.ts +1 -1
- package/dist/components/Timeline/TimelineListItem.js +6 -15
- package/dist/components/Timeline/TimelinePlayCursorSyncer.js +5 -5
- package/dist/components/Timeline/TimelineSchemaField.js +4 -0
- package/dist/components/Timeline/TimelineSequence.d.ts +1 -1
- package/dist/components/Timeline/TimelineSequence.js +93 -51
- package/dist/components/Timeline/TimelineStack/index.js +1 -1
- package/dist/components/Timeline/TimelineTimeIndicators.js +10 -3
- package/dist/components/Timeline/TimelineTracks.js +5 -4
- package/dist/components/Timeline/sequence-props-subscription-store.d.ts +19 -0
- package/dist/components/Timeline/sequence-props-subscription-store.js +151 -0
- package/dist/components/Timeline/use-sequence-props-subscription.js +35 -112
- package/dist/components/draw-peaks.js +7 -0
- package/dist/esm/audio-waveform-worker.mjs +3 -0
- package/dist/esm/{chunk-0y1jhm8s.js → chunk-0njpenna.js} +2171 -1959
- package/dist/esm/internals.mjs +2171 -1959
- package/dist/esm/previewEntry.mjs +2179 -1967
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/timeline-layout.d.ts +15 -17
- package/dist/helpers/timeline-layout.js +32 -52
- package/package.json +9 -9
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.TimelineSequence = void 0;
|
|
4
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
-
const react_1 = require("react");
|
|
38
|
+
const react_1 = __importStar(require("react"));
|
|
6
39
|
const remotion_1 = require("remotion");
|
|
7
40
|
const colors_1 = require("../../helpers/colors");
|
|
8
41
|
const get_timeline_sequence_layout_1 = require("../../helpers/get-timeline-sequence-layout");
|
|
@@ -17,40 +50,81 @@ const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
|
|
|
17
50
|
const AUDIO_GRADIENT = 'linear-gradient(rgb(16 171 58), rgb(43 165 63) 60%)';
|
|
18
51
|
const VIDEO_GRADIENT = 'linear-gradient(to top, #8e44ad, #9b59b6)';
|
|
19
52
|
const IMAGE_GRADIENT = 'linear-gradient(to top, #2980b9, #3498db)';
|
|
20
|
-
const
|
|
53
|
+
const TimelineSequenceFn = ({ s }) => {
|
|
21
54
|
const windowWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
|
|
22
55
|
if (windowWidth === null) {
|
|
23
56
|
return null;
|
|
24
57
|
}
|
|
25
58
|
return jsx_runtime_1.jsx(Inner, { windowWidth: windowWidth, s: s });
|
|
26
59
|
};
|
|
27
|
-
|
|
60
|
+
const TimelineSequenceCurrentFrame = ({ s, displayDurationInFrames, premountWidth, postmountWidth, style, children, }) => {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
const frame = (0, remotion_1.useCurrentFrame)();
|
|
63
|
+
const relativeFrame = frame - s.from;
|
|
64
|
+
const relativeFrameWithPremount = relativeFrame + ((_a = s.premountDisplay) !== null && _a !== void 0 ? _a : 0);
|
|
65
|
+
const relativeFrameWithPostmount = relativeFrame - displayDurationInFrames;
|
|
66
|
+
const roundedFrame = Math.round(relativeFrame * 100) / 100;
|
|
67
|
+
const isInRange = relativeFrame >= 0 && relativeFrame < displayDurationInFrames;
|
|
68
|
+
const isPremounting = relativeFrameWithPremount >= 0 &&
|
|
69
|
+
relativeFrameWithPremount < displayDurationInFrames &&
|
|
70
|
+
!isInRange;
|
|
71
|
+
const isPostmounting = relativeFrameWithPostmount >= 0 &&
|
|
72
|
+
relativeFrameWithPostmount < ((_b = s.postmountDisplay) !== null && _b !== void 0 ? _b : 0) &&
|
|
73
|
+
!isInRange;
|
|
74
|
+
const actualStyle = (0, react_1.useMemo)(() => {
|
|
75
|
+
return {
|
|
76
|
+
...style,
|
|
77
|
+
opacity: isInRange ? 1 : 0.5,
|
|
78
|
+
};
|
|
79
|
+
}, [isInRange, style]);
|
|
80
|
+
return (jsx_runtime_1.jsxs("div", { style: actualStyle, title: s.displayName, children: [premountWidth ? (jsx_runtime_1.jsx("div", { style: {
|
|
81
|
+
width: premountWidth,
|
|
82
|
+
height: '100%',
|
|
83
|
+
background: `repeating-linear-gradient(
|
|
84
|
+
-45deg,
|
|
85
|
+
transparent,
|
|
86
|
+
transparent 2px,
|
|
87
|
+
rgba(255, 255, 255, ${isPremounting ? 0.5 : 0.2}) 2px,
|
|
88
|
+
rgba(255, 255, 255, ${isPremounting ? 0.5 : 0.2}) 4px
|
|
89
|
+
)`,
|
|
90
|
+
position: 'absolute',
|
|
91
|
+
} })) : null, postmountWidth ? (jsx_runtime_1.jsx("div", { style: {
|
|
92
|
+
width: postmountWidth,
|
|
93
|
+
height: '100%',
|
|
94
|
+
background: `repeating-linear-gradient(
|
|
95
|
+
-45deg,
|
|
96
|
+
transparent,
|
|
97
|
+
transparent 2px,
|
|
98
|
+
rgba(255, 255, 255, ${isPostmounting ? 0.5 : 0.2}) 2px,
|
|
99
|
+
rgba(255, 255, 255, ${isPostmounting ? 0.5 : 0.2}) 4px
|
|
100
|
+
)`,
|
|
101
|
+
position: 'absolute',
|
|
102
|
+
right: 0,
|
|
103
|
+
} })) : null, children, s.type !== 'audio' &&
|
|
104
|
+
s.type !== 'video' &&
|
|
105
|
+
s.type !== 'image' &&
|
|
106
|
+
s.loopDisplay === undefined &&
|
|
107
|
+
(isInRange || isPremounting || isPostmounting) ? (jsx_runtime_1.jsx("div", { style: {
|
|
108
|
+
paddingLeft: 5 + (premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0),
|
|
109
|
+
height: '100%',
|
|
110
|
+
display: 'flex',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
}, children: jsx_runtime_1.jsx(TimelineSequenceFrame_1.TimelineSequenceFrame, { premounted: isPremounting, postmounted: isPostmounting ? s.duration - 1 : null, roundedFrame: roundedFrame }) })) : null] }));
|
|
113
|
+
};
|
|
28
114
|
const Inner = ({ s, windowWidth }) => {
|
|
29
115
|
// If a duration is 1, it is essentially a still and it should have width 0
|
|
30
116
|
// Some compositions may not be longer than their media duration,
|
|
31
117
|
// if that is the case, it needs to be asynchronously determined
|
|
32
|
-
var _a
|
|
118
|
+
var _a;
|
|
33
119
|
const video = remotion_1.Internals.useVideo();
|
|
34
120
|
const maxMediaDuration = (0, use_max_media_duration_1.useMaxMediaDuration)(s, (_a = video === null || video === void 0 ? void 0 : video.fps) !== null && _a !== void 0 ? _a : 30);
|
|
35
121
|
const effectiveMaxMediaDuration = s.loopDisplay ? null : maxMediaDuration;
|
|
36
122
|
if (!video) {
|
|
37
123
|
throw new TypeError('Expected video config');
|
|
38
124
|
}
|
|
39
|
-
const frame = (0, remotion_1.useCurrentFrame)();
|
|
40
|
-
const relativeFrame = frame - s.from;
|
|
41
125
|
const displayDurationInFrames = s.loopDisplay
|
|
42
126
|
? s.loopDisplay.durationInFrames * s.loopDisplay.numberOfTimes
|
|
43
127
|
: s.duration;
|
|
44
|
-
const relativeFrameWithPremount = relativeFrame + ((_b = s.premountDisplay) !== null && _b !== void 0 ? _b : 0);
|
|
45
|
-
const relativeFrameWithPostmount = relativeFrame - displayDurationInFrames;
|
|
46
|
-
const roundedFrame = Math.round(relativeFrame * 100) / 100;
|
|
47
|
-
const isInRange = relativeFrame >= 0 && relativeFrame < displayDurationInFrames;
|
|
48
|
-
const isPremounting = relativeFrameWithPremount >= 0 &&
|
|
49
|
-
relativeFrameWithPremount < displayDurationInFrames &&
|
|
50
|
-
!isInRange;
|
|
51
|
-
const isPostmounting = relativeFrameWithPostmount >= 0 &&
|
|
52
|
-
relativeFrameWithPostmount < ((_c = s.postmountDisplay) !== null && _c !== void 0 ? _c : 0) &&
|
|
53
|
-
!isInRange;
|
|
54
128
|
const { marginLeft, width, naturalWidth, premountWidth, postmountWidth } = (0, react_1.useMemo)(() => {
|
|
55
129
|
return (0, get_timeline_sequence_layout_1.getTimelineSequenceLayout)({
|
|
56
130
|
durationInFrames: displayDurationInFrames,
|
|
@@ -86,43 +160,11 @@ const Inner = ({ s, windowWidth }) => {
|
|
|
86
160
|
width,
|
|
87
161
|
color: 'white',
|
|
88
162
|
overflow: 'hidden',
|
|
89
|
-
opacity: isInRange ? 1 : 0.5,
|
|
90
163
|
};
|
|
91
|
-
}, [
|
|
164
|
+
}, [marginLeft, s.type, width]);
|
|
92
165
|
if (maxMediaDuration === null && !s.loopDisplay) {
|
|
93
166
|
return null;
|
|
94
167
|
}
|
|
95
|
-
return (jsx_runtime_1.jsxs(
|
|
96
|
-
width: premountWidth,
|
|
97
|
-
height: '100%',
|
|
98
|
-
background: `repeating-linear-gradient(
|
|
99
|
-
-45deg,
|
|
100
|
-
transparent,
|
|
101
|
-
transparent 2px,
|
|
102
|
-
rgba(255, 255, 255, ${isPremounting ? 0.5 : 0.2}) 2px,
|
|
103
|
-
rgba(255, 255, 255, ${isPremounting ? 0.5 : 0.2}) 4px
|
|
104
|
-
)`,
|
|
105
|
-
position: 'absolute',
|
|
106
|
-
} })) : null, postmountWidth ? (jsx_runtime_1.jsx("div", { style: {
|
|
107
|
-
width: postmountWidth,
|
|
108
|
-
height: '100%',
|
|
109
|
-
background: `repeating-linear-gradient(
|
|
110
|
-
-45deg,
|
|
111
|
-
transparent,
|
|
112
|
-
transparent 2px,
|
|
113
|
-
rgba(255, 255, 255, ${isPostmounting ? 0.5 : 0.2}) 2px,
|
|
114
|
-
rgba(255, 255, 255, ${isPostmounting ? 0.5 : 0.2}) 4px
|
|
115
|
-
)`,
|
|
116
|
-
position: 'absolute',
|
|
117
|
-
right: 0,
|
|
118
|
-
} })) : null, s.type === 'audio' ? (jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, doesVolumeChange: s.doesVolumeChange, visualizationWidth: width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate, loopDisplay: s.loopDisplay })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, trimBefore: s.startMediaFrom, durationInFrames: s.duration, playbackRate: s.playbackRate, volume: s.volume, doesVolumeChange: s.doesVolumeChange, premountWidth: premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0, postmountWidth: postmountWidth !== null && postmountWidth !== void 0 ? postmountWidth : 0, loopDisplay: s.loopDisplay })) : null, s.type === 'image' ? (jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: width })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), s.type !== 'audio' &&
|
|
119
|
-
s.type !== 'video' &&
|
|
120
|
-
s.type !== 'image' &&
|
|
121
|
-
s.loopDisplay === undefined &&
|
|
122
|
-
(isInRange || isPremounting || isPostmounting) ? (jsx_runtime_1.jsx("div", { style: {
|
|
123
|
-
paddingLeft: 5 + (premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0),
|
|
124
|
-
height: '100%',
|
|
125
|
-
display: 'flex',
|
|
126
|
-
alignItems: 'center',
|
|
127
|
-
}, children: jsx_runtime_1.jsx(TimelineSequenceFrame_1.TimelineSequenceFrame, { premounted: isPremounting, postmounted: isPostmounting ? s.duration - 1 : null, roundedFrame: roundedFrame }) })) : null] }, s.id));
|
|
168
|
+
return (jsx_runtime_1.jsxs(TimelineSequenceCurrentFrame, { s: s, displayDurationInFrames: displayDurationInFrames, premountWidth: premountWidth, postmountWidth: postmountWidth, style: style, children: [s.type === 'audio' ? (jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, doesVolumeChange: s.doesVolumeChange, visualizationWidth: width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate, loopDisplay: s.loopDisplay })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, trimBefore: s.startMediaFrom, durationInFrames: s.duration, playbackRate: s.playbackRate, volume: s.volume, doesVolumeChange: s.doesVolumeChange, premountWidth: premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0, postmountWidth: postmountWidth !== null && postmountWidth !== void 0 ? postmountWidth : 0, loopDisplay: s.loopDisplay })) : null, s.type === 'image' ? (jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: width })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes }))] }));
|
|
128
169
|
};
|
|
170
|
+
exports.TimelineSequence = react_1.default.memo(TimelineSequenceFn);
|
|
@@ -127,7 +127,7 @@ const TimelineStack = ({ isCompact, sequence, originalLocation }) => {
|
|
|
127
127
|
: stackHovered && stackHoverable
|
|
128
128
|
? colors_1.LIGHT_TEXT
|
|
129
129
|
: colors_1.VERY_LIGHT_TEXT,
|
|
130
|
-
marginLeft:
|
|
130
|
+
marginLeft: 5,
|
|
131
131
|
cursor: stackHoverable ? 'pointer' : undefined,
|
|
132
132
|
display: 'flex',
|
|
133
133
|
flexDirection: 'row',
|
|
@@ -30,9 +30,12 @@ const secondTick = {
|
|
|
30
30
|
...tick,
|
|
31
31
|
height: 15,
|
|
32
32
|
};
|
|
33
|
+
const TICK_LABEL_FONT_SIZE = 12;
|
|
34
|
+
const TICK_LABEL_MARGIN_LEFT = 8;
|
|
35
|
+
const TICK_LABEL_MIN_GAP = 16;
|
|
33
36
|
const tickLabel = {
|
|
34
|
-
fontSize:
|
|
35
|
-
marginLeft:
|
|
37
|
+
fontSize: TICK_LABEL_FONT_SIZE,
|
|
38
|
+
marginLeft: TICK_LABEL_MARGIN_LEFT,
|
|
36
39
|
marginTop: 7,
|
|
37
40
|
color: colors_1.LIGHT_TEXT,
|
|
38
41
|
};
|
|
@@ -101,8 +104,12 @@ const Inner = ({ windowWidth, durationInFrames, fps }) => {
|
|
|
101
104
|
const ticks = (0, react_1.useMemo)(() => {
|
|
102
105
|
const frameInterval = (0, timeline_scroll_logic_1.getFrameIncrementFromWidth)(durationInFrames, windowWidth);
|
|
103
106
|
const MIN_SPACING_BETWEEN_TICKS_PX = 5;
|
|
107
|
+
const maxTickLabelWidth = (0, render_frame_1.renderFrame)(durationInFrames - 1, fps).length *
|
|
108
|
+
TICK_LABEL_FONT_SIZE *
|
|
109
|
+
0.6;
|
|
110
|
+
const minSpacingBetweenTickLabelsPx = TICK_LABEL_MARGIN_LEFT + maxTickLabelWidth + TICK_LABEL_MIN_GAP;
|
|
104
111
|
const seconds = Math.floor(durationInFrames / fps);
|
|
105
|
-
const secondMarkerEveryNth = Math.ceil(
|
|
112
|
+
const secondMarkerEveryNth = Math.ceil(minSpacingBetweenTickLabelsPx / (frameInterval * fps));
|
|
106
113
|
const frameMarkerEveryNth = Math.ceil(MIN_SPACING_BETWEEN_TICKS_PX / frameInterval);
|
|
107
114
|
// Big ticks showing for every second
|
|
108
115
|
const secondTicks = new Array(seconds)
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TimelineTracks = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
|
+
const remotion_1 = require("remotion");
|
|
6
7
|
const client_id_1 = require("../../helpers/client-id");
|
|
7
8
|
const timeline_layout_1 = require("../../helpers/timeline-layout");
|
|
8
9
|
const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
|
|
@@ -18,13 +19,13 @@ const content = {
|
|
|
18
19
|
const timelineContent = {
|
|
19
20
|
minHeight: '100%',
|
|
20
21
|
};
|
|
21
|
-
const getExpandedPlaceholderStyle = (sequence, expandedTracks) => ({
|
|
22
|
-
height: (0, timeline_layout_1.getExpandedTrackHeight)(sequence, expandedTracks) +
|
|
23
|
-
timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
|
|
22
|
+
const getExpandedPlaceholderStyle = (sequence, expandedTracks, dragOverrides, codeValues) => ({
|
|
23
|
+
height: (0, timeline_layout_1.getExpandedTrackHeight)(sequence, expandedTracks, dragOverrides, codeValues) + timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
|
|
24
24
|
});
|
|
25
25
|
const TimelineTracks = ({ timeline, hasBeenCut }) => {
|
|
26
26
|
const { expandedTracks } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksContext);
|
|
27
27
|
const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
28
|
+
const { dragOverrides, codeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeOverridesContext);
|
|
28
29
|
const visualModeEnabled = Boolean(process.env.EXPERIMENTAL_VISUAL_MODE_ENABLED) &&
|
|
29
30
|
previewServerState.type === 'connected';
|
|
30
31
|
const timelineStyle = (0, react_1.useMemo)(() => {
|
|
@@ -45,7 +46,7 @@ const TimelineTracks = ({ timeline, hasBeenCut }) => {
|
|
|
45
46
|
jsx_runtime_1.jsx("div", { style: {
|
|
46
47
|
height: (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type),
|
|
47
48
|
marginBottom: timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
|
|
48
|
-
}, children: jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence }) }), visualModeEnabled && isExpanded ? (jsx_runtime_1.jsx("div", { style: getExpandedPlaceholderStyle(track.sequence, expandedTracks) })) : null] }, track.sequence.id));
|
|
49
|
+
}, children: jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence }) }), visualModeEnabled && isExpanded ? (jsx_runtime_1.jsx("div", { style: getExpandedPlaceholderStyle(track.sequence, expandedTracks, dragOverrides, codeValues) })) : null] }, track.sequence.id));
|
|
49
50
|
})] }), hasBeenCut ? jsx_runtime_1.jsx(MaxTimelineTracks_1.MaxTimelineTracksReached, {}) : null] }));
|
|
50
51
|
};
|
|
51
52
|
exports.TimelineTracks = TimelineTracks;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EventSourceEvent, SequenceNodePath } from '@remotion/studio-shared';
|
|
2
|
+
import { type CanUpdateSequencePropStatus } from 'remotion';
|
|
3
|
+
import type { SequenceSchema } from 'remotion';
|
|
4
|
+
export type SequencePropsSnapshot = {
|
|
5
|
+
nodePath: SequenceNodePath | null;
|
|
6
|
+
jsxInMapCallback: boolean;
|
|
7
|
+
props: Record<string, CanUpdateSequencePropStatus> | null;
|
|
8
|
+
};
|
|
9
|
+
type SubscribeToEvent = (type: EventSourceEvent['type'], listener: (event: EventSourceEvent) => void) => () => void;
|
|
10
|
+
export declare const acquireSequencePropsSubscription: ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }: {
|
|
11
|
+
clientId: string;
|
|
12
|
+
fileName: string;
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
schema: SequenceSchema;
|
|
16
|
+
subscribeToEvent: SubscribeToEvent;
|
|
17
|
+
onChange: (snapshot: SequencePropsSnapshot) => void;
|
|
18
|
+
}) => () => void;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.acquireSequencePropsSubscription = void 0;
|
|
4
|
+
const remotion_1 = require("remotion");
|
|
5
|
+
const call_api_1 = require("../call-api");
|
|
6
|
+
const INITIAL_SNAPSHOT = {
|
|
7
|
+
nodePath: null,
|
|
8
|
+
jsxInMapCallback: false,
|
|
9
|
+
props: null,
|
|
10
|
+
};
|
|
11
|
+
const entries = new Map();
|
|
12
|
+
let globalUnsubscribe = null;
|
|
13
|
+
const makeKey = (fileName, line, column) => `${fileName}|${line}|${column}`;
|
|
14
|
+
const nodePathsEqual = (a, b) => {
|
|
15
|
+
if (!a || !b) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
19
|
+
};
|
|
20
|
+
const notify = (entry) => {
|
|
21
|
+
for (const listener of entry.listeners) {
|
|
22
|
+
listener(entry.snapshot);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const handleEvent = (event) => {
|
|
26
|
+
if (event.type !== 'sequence-props-updated') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const entry of entries.values()) {
|
|
30
|
+
if (entry.fileName !== event.fileName) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (!nodePathsEqual(entry.snapshot.nodePath, event.nodePath)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (event.result.canUpdate) {
|
|
37
|
+
entry.snapshot = {
|
|
38
|
+
nodePath: entry.snapshot.nodePath,
|
|
39
|
+
jsxInMapCallback: event.result.jsxInMapCallback,
|
|
40
|
+
props: event.result.props,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
entry.snapshot = {
|
|
45
|
+
nodePath: entry.snapshot.nodePath,
|
|
46
|
+
jsxInMapCallback: false,
|
|
47
|
+
props: null,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
notify(entry);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const ensureGlobalListener = (subscribeToEvent) => {
|
|
54
|
+
if (globalUnsubscribe) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
globalUnsubscribe = subscribeToEvent('sequence-props-updated', handleEvent);
|
|
58
|
+
};
|
|
59
|
+
const teardownGlobalListenerIfEmpty = () => {
|
|
60
|
+
if (entries.size > 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (globalUnsubscribe) {
|
|
64
|
+
globalUnsubscribe();
|
|
65
|
+
globalUnsubscribe = null;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const fireUnsubscribe = (fileName, nodePath, clientId) => {
|
|
69
|
+
(0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
70
|
+
fileName,
|
|
71
|
+
nodePath,
|
|
72
|
+
clientId,
|
|
73
|
+
}).catch(() => {
|
|
74
|
+
// Ignore unsubscribe errors
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const acquireSequencePropsSubscription = ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }) => {
|
|
78
|
+
const key = makeKey(fileName, line, column);
|
|
79
|
+
let entry = entries.get(key);
|
|
80
|
+
if (!entry) {
|
|
81
|
+
const newEntry = {
|
|
82
|
+
clientId,
|
|
83
|
+
fileName,
|
|
84
|
+
refCount: 0,
|
|
85
|
+
snapshot: INITIAL_SNAPSHOT,
|
|
86
|
+
listeners: new Set(),
|
|
87
|
+
tornDown: false,
|
|
88
|
+
};
|
|
89
|
+
entries.set(key, newEntry);
|
|
90
|
+
ensureGlobalListener(subscribeToEvent);
|
|
91
|
+
(0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
92
|
+
fileName,
|
|
93
|
+
line,
|
|
94
|
+
column,
|
|
95
|
+
schema,
|
|
96
|
+
clientId,
|
|
97
|
+
})
|
|
98
|
+
.then((result) => {
|
|
99
|
+
if (newEntry.tornDown) {
|
|
100
|
+
if (result.canUpdate) {
|
|
101
|
+
fireUnsubscribe(fileName, result.nodePath, clientId);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (result.canUpdate) {
|
|
106
|
+
newEntry.snapshot = {
|
|
107
|
+
nodePath: result.nodePath,
|
|
108
|
+
jsxInMapCallback: result.jsxInMapCallback,
|
|
109
|
+
props: result.props,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
114
|
+
}
|
|
115
|
+
notify(newEntry);
|
|
116
|
+
})
|
|
117
|
+
.catch((err) => {
|
|
118
|
+
if (newEntry.tornDown) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
remotion_1.Internals.Log.error(err);
|
|
122
|
+
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
123
|
+
notify(newEntry);
|
|
124
|
+
});
|
|
125
|
+
entry = newEntry;
|
|
126
|
+
}
|
|
127
|
+
entry.refCount += 1;
|
|
128
|
+
entry.listeners.add(onChange);
|
|
129
|
+
onChange(entry.snapshot);
|
|
130
|
+
let released = false;
|
|
131
|
+
return () => {
|
|
132
|
+
if (released) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
released = true;
|
|
136
|
+
const e = entry;
|
|
137
|
+
e.listeners.delete(onChange);
|
|
138
|
+
e.refCount -= 1;
|
|
139
|
+
if (e.refCount > 0) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
e.tornDown = true;
|
|
143
|
+
const resolvedNodePath = e.snapshot.nodePath;
|
|
144
|
+
entries.delete(key);
|
|
145
|
+
if (resolvedNodePath) {
|
|
146
|
+
fireUnsubscribe(e.fileName, resolvedNodePath, e.clientId);
|
|
147
|
+
}
|
|
148
|
+
teardownGlobalListenerIfEmpty();
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
exports.acquireSequencePropsSubscription = acquireSequencePropsSubscription;
|
|
@@ -4,13 +4,16 @@ exports.useSequencePropsSubscription = void 0;
|
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const remotion_1 = require("remotion");
|
|
6
6
|
const client_id_1 = require("../../helpers/client-id");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
7
|
+
const sequence_props_subscription_store_1 = require("./sequence-props-subscription-store");
|
|
8
|
+
const EMPTY_STATE = {
|
|
9
|
+
nodePath: null,
|
|
10
|
+
jsxInMapCallback: false,
|
|
11
|
+
};
|
|
9
12
|
const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnabled) => {
|
|
10
|
-
var _a;
|
|
11
|
-
var
|
|
13
|
+
var _a, _b;
|
|
14
|
+
var _c, _d, _e, _f;
|
|
12
15
|
const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeOverridesContext);
|
|
13
|
-
const overrideId = (
|
|
16
|
+
const overrideId = (_c = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.overrideId) !== null && _c !== void 0 ? _c : null;
|
|
14
17
|
const setPropStatusesForSequence = (0, react_1.useCallback)((statuses) => {
|
|
15
18
|
if (!overrideId) {
|
|
16
19
|
return;
|
|
@@ -19,8 +22,6 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
|
|
|
19
22
|
}, [overrideId, setCodeValues]);
|
|
20
23
|
const { previewServerState: state, subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
21
24
|
const clientId = state.type === 'connected' ? state.clientId : undefined;
|
|
22
|
-
const schemaFields = (0, react_1.useMemo)(() => (0, timeline_layout_1.getSchemaFields)(sequence.controls), [sequence.controls]);
|
|
23
|
-
const schemaKeysString = (0, react_1.useMemo)(() => (schemaFields ? schemaFields.map((f) => f.key).join(',') : null), [schemaFields]);
|
|
24
25
|
const validatedLocation = (0, react_1.useMemo)(() => {
|
|
25
26
|
var _a;
|
|
26
27
|
if (!originalLocation ||
|
|
@@ -34,145 +35,67 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
|
|
|
34
35
|
column: (_a = originalLocation.column) !== null && _a !== void 0 ? _a : 0,
|
|
35
36
|
};
|
|
36
37
|
}, [originalLocation]);
|
|
37
|
-
const
|
|
38
|
-
const locationLine = (_d = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.line) !== null && _d !== void 0 ? _d : null;
|
|
39
|
-
const locationColumn = (_e = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.column) !== null && _e !== void 0 ? _e : null;
|
|
40
|
-
const currentLocationSource = (0, react_1.useRef)(locationSource);
|
|
41
|
-
currentLocationSource.current = locationSource;
|
|
42
|
-
const currentLocationLine = (0, react_1.useRef)(locationLine);
|
|
43
|
-
currentLocationLine.current = locationLine;
|
|
44
|
-
const currentLocationColumn = (0, react_1.useRef)(locationColumn);
|
|
45
|
-
currentLocationColumn.current = locationColumn;
|
|
46
|
-
const nodePathRef = (0, react_1.useRef)(null);
|
|
47
|
-
const [nodePath, setNodePath] = (0, react_1.useState)(null);
|
|
48
|
-
const [jsxInMapCallback, setJsxInMapCallback] = (0, react_1.useState)(false);
|
|
38
|
+
const [subscriptionState, setSubscriptionState] = (0, react_1.useState)(EMPTY_STATE);
|
|
49
39
|
const isMountedRef = (0, react_1.useRef)(true);
|
|
50
|
-
const setNodePathBoth = (0, react_1.useCallback)((next) => {
|
|
51
|
-
nodePathRef.current = next;
|
|
52
|
-
setNodePath(next);
|
|
53
|
-
}, []);
|
|
54
40
|
(0, react_1.useEffect)(() => {
|
|
55
41
|
isMountedRef.current = true;
|
|
56
42
|
return () => {
|
|
57
43
|
isMountedRef.current = false;
|
|
58
44
|
};
|
|
59
45
|
}, []);
|
|
46
|
+
const schema = (_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.schema;
|
|
47
|
+
const locationSource = (_d = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _d !== void 0 ? _d : null;
|
|
48
|
+
const locationLine = (_e = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.line) !== null && _e !== void 0 ? _e : null;
|
|
49
|
+
const locationColumn = (_f = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.column) !== null && _f !== void 0 ? _f : null;
|
|
60
50
|
(0, react_1.useEffect)(() => {
|
|
61
51
|
if (!visualModeEnabled) {
|
|
62
52
|
setPropStatusesForSequence(null);
|
|
63
|
-
|
|
64
|
-
setJsxInMapCallback(false);
|
|
53
|
+
setSubscriptionState(EMPTY_STATE);
|
|
65
54
|
return;
|
|
66
55
|
}
|
|
67
56
|
if (!clientId ||
|
|
68
57
|
!locationSource ||
|
|
69
58
|
!locationLine ||
|
|
70
59
|
locationColumn === null ||
|
|
71
|
-
!
|
|
60
|
+
!schema) {
|
|
72
61
|
setPropStatusesForSequence(null);
|
|
73
|
-
|
|
74
|
-
setJsxInMapCallback(false);
|
|
62
|
+
setSubscriptionState(EMPTY_STATE);
|
|
75
63
|
return;
|
|
76
64
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
65
|
+
const onChange = (snapshot) => {
|
|
66
|
+
setSubscriptionState({
|
|
67
|
+
nodePath: snapshot.nodePath,
|
|
68
|
+
jsxInMapCallback: snapshot.jsxInMapCallback,
|
|
69
|
+
});
|
|
70
|
+
setPropStatusesForSequence(snapshot.props);
|
|
71
|
+
};
|
|
72
|
+
const release = (0, sequence_props_subscription_store_1.acquireSequencePropsSubscription)({
|
|
73
|
+
clientId,
|
|
79
74
|
fileName: locationSource,
|
|
80
75
|
line: locationLine,
|
|
81
76
|
column: locationColumn,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.then((result) => {
|
|
86
|
-
if (currentLocationSource.current !== locationSource ||
|
|
87
|
-
currentLocationLine.current !== locationLine ||
|
|
88
|
-
currentLocationColumn.current !== locationColumn) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (result.canUpdate) {
|
|
92
|
-
setNodePathBoth(result.nodePath);
|
|
93
|
-
setPropStatusesForSequence(result.props);
|
|
94
|
-
setJsxInMapCallback(result.jsxInMapCallback);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
setNodePathBoth(null);
|
|
98
|
-
setPropStatusesForSequence(null);
|
|
99
|
-
setJsxInMapCallback(false);
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
.catch((err) => {
|
|
103
|
-
setNodePathBoth(null);
|
|
104
|
-
setJsxInMapCallback(false);
|
|
105
|
-
remotion_1.Internals.Log.error(err);
|
|
106
|
-
setPropStatusesForSequence(null);
|
|
77
|
+
schema,
|
|
78
|
+
subscribeToEvent,
|
|
79
|
+
onChange,
|
|
107
80
|
});
|
|
108
81
|
return () => {
|
|
109
|
-
|
|
82
|
+
release();
|
|
110
83
|
// Only clear props on true unmount, not on re-subscribe due to
|
|
111
|
-
//
|
|
84
|
+
// location changes — avoids flicker while re-subscribing.
|
|
112
85
|
if (!isMountedRef.current) {
|
|
113
86
|
setPropStatusesForSequence(null);
|
|
114
87
|
}
|
|
115
|
-
setNodePathBoth(null);
|
|
116
|
-
setJsxInMapCallback(false);
|
|
117
|
-
if (currentNodePath) {
|
|
118
|
-
(0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
119
|
-
fileName: locationSource,
|
|
120
|
-
nodePath: currentNodePath,
|
|
121
|
-
clientId,
|
|
122
|
-
}).catch(() => {
|
|
123
|
-
// Ignore unsubscribe errors
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
88
|
};
|
|
127
89
|
}, [
|
|
128
|
-
visualModeEnabled,
|
|
129
90
|
clientId,
|
|
130
|
-
locationSource,
|
|
131
|
-
locationLine,
|
|
132
91
|
locationColumn,
|
|
133
|
-
schemaKeysString,
|
|
134
|
-
setPropStatusesForSequence,
|
|
135
|
-
setNodePathBoth,
|
|
136
|
-
]);
|
|
137
|
-
(0, react_1.useEffect)(() => {
|
|
138
|
-
if (!visualModeEnabled) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (!locationSource || !locationLine || locationColumn === null) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const listener = (event) => {
|
|
145
|
-
if (event.type !== 'sequence-props-updated') {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (event.fileName !== currentLocationSource.current ||
|
|
149
|
-
!nodePathRef.current ||
|
|
150
|
-
JSON.stringify(event.nodePath) !== JSON.stringify(nodePathRef.current)) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (event.result.canUpdate) {
|
|
154
|
-
setPropStatusesForSequence(event.result.props);
|
|
155
|
-
setJsxInMapCallback(event.result.jsxInMapCallback);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
setPropStatusesForSequence(null);
|
|
159
|
-
setNodePathBoth(null);
|
|
160
|
-
setJsxInMapCallback(false);
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
const unsub = subscribeToEvent('sequence-props-updated', listener);
|
|
164
|
-
return () => {
|
|
165
|
-
unsub();
|
|
166
|
-
};
|
|
167
|
-
}, [
|
|
168
|
-
visualModeEnabled,
|
|
169
|
-
locationSource,
|
|
170
92
|
locationLine,
|
|
171
|
-
|
|
172
|
-
|
|
93
|
+
locationSource,
|
|
94
|
+
schema,
|
|
173
95
|
setPropStatusesForSequence,
|
|
174
|
-
|
|
96
|
+
subscribeToEvent,
|
|
97
|
+
visualModeEnabled,
|
|
175
98
|
]);
|
|
176
|
-
return
|
|
99
|
+
return subscriptionState;
|
|
177
100
|
};
|
|
178
101
|
exports.useSequencePropsSubscription = useSequencePropsSubscription;
|
|
@@ -10,6 +10,13 @@ const drawBars = (canvas, peaks, color, volume, width) => {
|
|
|
10
10
|
}
|
|
11
11
|
const { height } = canvas;
|
|
12
12
|
const w = canvas.width;
|
|
13
|
+
// Skip drawing when the target canvas has not been laid out yet.
|
|
14
|
+
// `createImageData(0, h)` / `(w, 0)` throws a DOMException, which
|
|
15
|
+
// surfaces in Studio's console for compositions with many audio
|
|
16
|
+
// sequences — some segments are 0 px wide at certain zoom levels.
|
|
17
|
+
if (w === 0 || height === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
13
20
|
ctx.clearRect(0, 0, w, height);
|
|
14
21
|
if (volume === 0)
|
|
15
22
|
return;
|