remotion 4.0.532 → 4.0.533

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.
@@ -77,6 +77,12 @@ export type TSequence = {
77
77
  from: number;
78
78
  trimBefore: number | null;
79
79
  duration: number;
80
+ /** Infer the timeline display duration from children without changing playback. */
81
+ readonly autoDuration?: boolean | null;
82
+ /** Whether the wrapper can restore its duration from its scenes. */
83
+ readonly canInferDuration?: boolean | null;
84
+ /** Full scene duration in the parent clock, before container clipping. */
85
+ readonly unclippedDuration?: number | null;
80
86
  id: string;
81
87
  displayName: string;
82
88
  documentationLink: string | null;
@@ -72,6 +72,7 @@ export type HtmlInCanvasOnPaintParams = {
72
72
  readonly pixelDensity: number;
73
73
  };
74
74
  export declare const isHtmlInCanvasSupported: () => boolean;
75
+ export declare const isHtmlInCanvasNestingSupported: () => boolean;
75
76
  /** Generic fallback for consumers that cannot inspect the current browser. */
76
77
  export declare const HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = "HTML in Canvas requires Chrome 149 or newer with Canvas Draw Element enabled at chrome://flags/#canvas-draw-element.";
77
78
  export declare const getHtmlInCanvasUnsupportedMessage: () => string;
@@ -319,4 +320,5 @@ export declare const HtmlInCanvas: React.ForwardRefExoticComponent<Omit<Interact
319
320
  readonly _remotionInternalCanvasSiblings?: React.ReactNode;
320
321
  } & React.RefAttributes<HTMLCanvasElement>> & {
321
322
  readonly isSupported: () => boolean;
323
+ readonly isNestingSupported: () => boolean;
322
324
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HtmlInCanvas = exports.htmlInCanvasSchema = exports.getHtmlInCanvasUnsupportedMessage = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.isHtmlInCanvasSupported = void 0;
3
+ exports.HtmlInCanvas = exports.htmlInCanvasSchema = exports.getHtmlInCanvasUnsupportedMessage = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.isHtmlInCanvasNestingSupported = exports.isHtmlInCanvasSupported = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const run_effect_chain_js_1 = require("./effects/run-effect-chain.js");
@@ -54,6 +54,17 @@ const isHtmlInCanvasSupported = () => {
54
54
  return cachedSupport;
55
55
  };
56
56
  exports.isHtmlInCanvasSupported = isHtmlInCanvasSupported;
57
+ const MINIMUM_CHROME_VERSION_FOR_NESTED_HTML_IN_CANVAS = 157;
58
+ const isHtmlInCanvasNestingSupported = () => {
59
+ var _a;
60
+ if (!(0, exports.isHtmlInCanvasSupported)() || typeof navigator === 'undefined') {
61
+ return false;
62
+ }
63
+ const chromeVersion = (_a = navigator.userAgent.match(/(?:Chrome|Chromium)\/(\d+)/)) === null || _a === void 0 ? void 0 : _a[1];
64
+ return (chromeVersion !== undefined &&
65
+ Number(chromeVersion) >= MINIMUM_CHROME_VERSION_FOR_NESTED_HTML_IN_CANVAS);
66
+ };
67
+ exports.isHtmlInCanvasNestingSupported = isHtmlInCanvasNestingSupported;
57
68
  /** Generic fallback for consumers that cannot inspect the current browser. */
58
69
  exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = 'HTML in Canvas requires Chrome 149 or newer with Canvas Draw Element enabled at chrome://flags/#canvas-draw-element.';
59
70
  const getHtmlInCanvasUnsupportedMessage = () => {
@@ -139,8 +150,8 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
139
150
  var _a;
140
151
  const isInsideAncestorHtmlInCanvas = (0, react_1.useContext)(HtmlInCanvasAncestorContext);
141
152
  assertHtmlInCanvasDimensions(width, height);
142
- if (isInsideAncestorHtmlInCanvas) {
143
- throw new Error('<HtmlInCanvas> components cannot be nested. Chrome does not reliably render nested HTML-in-canvas subtrees. Consider merging the effects into one <HtmlInCanvas> if you can.');
153
+ if (isInsideAncestorHtmlInCanvas && !(0, exports.isHtmlInCanvasNestingSupported)()) {
154
+ throw new Error(`Nested <HtmlInCanvas> components require Chrome ${MINIMUM_CHROME_VERSION_FOR_NESTED_HTML_IN_CANVAS} or newer with HTML-in-canvas enabled.`);
144
155
  }
145
156
  const resolvedPixelDensity = resolveHtmlInCanvasPixelDensity(pixelDensity);
146
157
  const canvasWidth = Math.ceil(width * resolvedPixelDensity);
@@ -471,6 +482,7 @@ const HtmlInCanvasWrapped = (0, with_interactivity_schema_js_1.withInteractivity
471
482
  });
472
483
  exports.HtmlInCanvas = Object.assign(HtmlInCanvasWrapped, {
473
484
  isSupported: exports.isHtmlInCanvasSupported,
485
+ isNestingSupported: exports.isHtmlInCanvasNestingSupported,
474
486
  });
475
487
  exports.HtmlInCanvas.displayName = 'HtmlInCanvas';
476
488
  (0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(exports.HtmlInCanvas);
@@ -24,6 +24,7 @@ const use_sequence_registration_js_1 = require("./use-sequence-registration.js")
24
24
  const use_video_config_js_1 = require("./use-video-config.js");
25
25
  const v5_flag_js_1 = require("./v5-flag.js");
26
26
  const with_interactivity_schema_js_1 = require("./with-interactivity-schema.js");
27
+ const SeriesContentVisibilityContext = (0, react_1.createContext)(true);
27
28
  const EMPTY_EFFECTS = [];
28
29
  const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playbackRate = 1, loop = false, freeze, durationInFrames, children, name, height, width, showInTimeline = true, hidden = false, controls, _remotionInternalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalDocumentationLink: documentationLink, _remotionInternalSingleChildComponent: singleChildComponent, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, outlineRef: passedRefForOutline, cropLeft, cropRight, cropTop, cropBottom, ...other }, ref) => {
29
30
  var _a, _b, _c, _d, _e;
@@ -283,6 +284,23 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
283
284
  const controlsComponentIdentity = controls === null || controls === void 0 ? void 0 : controls.componentIdentity;
284
285
  const controlsComponentName = controls === null || controls === void 0 ? void 0 : controls.componentName;
285
286
  const controlsVideoConfigValues = controls === null || controls === void 0 ? void 0 : controls.videoConfigValues;
287
+ const isInsideNonPremountFreeze = (0, freeze_js_1.useIsInsideNonPremountFreeze)();
288
+ const canInferDuration = (controlsComponentIdentity === 'dev.remotion.remotion.Series' ||
289
+ controlsComponentIdentity ===
290
+ 'dev.remotion.transitions.TransitionSeries') &&
291
+ !loop &&
292
+ registeredFrozenFrame === null &&
293
+ !isInsideNonPremountFreeze &&
294
+ !hidden;
295
+ const autoDuration = canInferDuration && durationInFrames === undefined;
296
+ const isSeriesChild = controlsComponentIdentity === 'dev.remotion.remotion.Series.Sequence' ||
297
+ controlsComponentIdentity ===
298
+ 'dev.remotion.transitions.TransitionSeries.Sequence' ||
299
+ controlsComponentIdentity ===
300
+ 'dev.remotion.transitions.TransitionSeries.Transition' ||
301
+ controlsComponentIdentity ===
302
+ 'dev.remotion.transitions.TransitionSeries.Overlay';
303
+ const seriesContentVisible = (0, react_1.useContext)(SeriesContentVisibilityContext);
286
304
  const effectRuntimeValues = (0, react_1.useMemo)(() => {
287
305
  var _a;
288
306
  return (_a = _remotionInternalEffects === null || _remotionInternalEffects === void 0 ? void 0 : _remotionInternalEffects.runtimeValues) !== null && _a !== void 0 ? _a : null;
@@ -383,6 +401,9 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
383
401
  sequencePlaybackRate: playbackRate,
384
402
  trimBefore: registeredTrimBefore,
385
403
  duration: actualDurationInFrames,
404
+ ...(autoDuration ? { autoDuration: true } : {}),
405
+ ...(canInferDuration ? { canInferDuration: true } : {}),
406
+ ...(isSeriesChild ? { unclippedDuration: effectiveDurationInFrames } : {}),
386
407
  id,
387
408
  displayName: timelineClipName,
388
409
  documentationLink: resolvedDocumentationLink,
@@ -408,6 +429,10 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
408
429
  playbackRate,
409
430
  parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id,
410
431
  actualDurationInFrames,
432
+ autoDuration,
433
+ canInferDuration,
434
+ isSeriesChild,
435
+ effectiveDurationInFrames,
411
436
  from,
412
437
  registeredTrimBefore,
413
438
  showInTimeline,
@@ -442,7 +467,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
442
467
  parentPlaybackRate,
443
468
  durationInFrames: effectiveDurationInFrames,
444
469
  });
445
- const content = frameInParent - from < -boundaryTolerance
470
+ const content = !seriesContentVisible || frameInParent - from < -boundaryTolerance
446
471
  ? null
447
472
  : frameInParent - endThreshold >= -boundaryTolerance
448
473
  ? null
@@ -485,7 +510,11 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
485
510
  if (hidden) {
486
511
  return shouldDiscoverOutline ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, outlineChildrenRef: automaticOutlineRef, children: null })) : null;
487
512
  }
488
- const sequence = (jsx_runtime_1.jsx(SequenceContext_js_1.SequenceContext.Provider, { value: contextValue, children: loopedContent === null ? null : other.layout === 'none' ? (loopedContent) : (jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: sequenceRef, style: defaultStyle, className: other.className, children: loopedContent })) }));
513
+ // Retain resolved scene registrations so Studio can recover the natural end
514
+ // even when seeking past an explicit wrapper trim. Scene contents stay hidden.
515
+ const retainSeriesRegistration = env.isStudio && canInferDuration;
516
+ const sequenceContent = loopedContent === null ? (retainSeriesRegistration ? (children) : null) : other.layout === 'none' ? (loopedContent) : (jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: sequenceRef, style: defaultStyle, className: other.className, children: loopedContent }));
517
+ const sequence = (jsx_runtime_1.jsx(SequenceContext_js_1.SequenceContext.Provider, { value: contextValue, children: retainSeriesRegistration ? (jsx_runtime_1.jsx(SeriesContentVisibilityContext.Provider, { value: content !== null, children: sequenceContent })) : (sequenceContent) }));
489
518
  return shouldDiscoverOutline ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, outlineChildrenRef: automaticOutlineRef, children: sequence })) : (sequence);
490
519
  };
491
520
  const RegularSequence = (0, react_1.forwardRef)(RegularSequenceRefForwardingFunction);
@@ -12,7 +12,10 @@ export type SequenceManagerRef = {
12
12
  current: TSequence[];
13
13
  };
14
14
  export type SequenceNodePath = Array<string | number>;
15
+ type SequenceManagerActions = Pick<SequenceManagerContext, 'registerSequence' | 'updateSequence' | 'unregisterSequence'>;
16
+ export declare const SequenceManagerActionsContext: React.Context<SequenceManagerActions>;
15
17
  export declare const SequenceManager: React.Context<SequenceManagerContext>;
18
+ export declare const useSequenceManagerSequences: () => TSequence[];
16
19
  export declare const SequenceManagerRefContext: React.Context<SequenceManagerRef>;
17
20
  export declare const SequenceRegistrationContext: React.Context<boolean>;
18
21
  export declare const DisableSequenceRegistrationContext: React.Context<boolean>;
@@ -29,6 +32,14 @@ export type VisualModeDragOverrides = {
29
32
  getDragOverrides: GetDragOverrides;
30
33
  getEffectDragOverrides: GetEffectDragOverrides;
31
34
  };
35
+ type DragOverridesSubscription = {
36
+ manager: SequenceManagerActions;
37
+ subscribe: (key: string | null, listener: () => void) => () => void;
38
+ getSnapshot: (key: string | null) => Record<string, DragOverrideValue>;
39
+ subscribeEffects: (key: string | null, listener: () => void) => () => void;
40
+ getEffectSnapshot: (key: string | null) => Record<string, Record<string, DragOverrideValue>>;
41
+ };
42
+ export declare const VisualModeDragOverridesSubscriptionContext: React.Context<DragOverridesSubscription | null>;
32
43
  export type SequencePropsStatusRemapping = {
33
44
  previousNodePath: SequencePropsSubscriptionKey;
34
45
  nodePath: SequencePropsSubscriptionKey | null;
@@ -42,6 +53,19 @@ export type VisualModeSetters = {
42
53
  setPropStatuses: (nodePath: SequencePropsSubscriptionKey, values: (prev: CanUpdateSequencePropsResponse) => CanUpdateSequencePropsResponse) => void;
43
54
  remapPropStatuses: (remappings: readonly SequencePropsStatusRemapping[]) => void;
44
55
  };
56
+ export type VisualModeBatchSetters = {
57
+ setDragOverridesBatch: (overrides: readonly {
58
+ readonly nodePath: SequencePropsSubscriptionKey;
59
+ readonly key: string;
60
+ readonly value: DragOverrideValue;
61
+ }[]) => void;
62
+ setEffectDragOverridesBatch: (overrides: readonly {
63
+ readonly nodePath: SequencePropsSubscriptionKey;
64
+ readonly effectIndex: number;
65
+ readonly key: string;
66
+ readonly value: DragOverrideValue;
67
+ }[]) => void;
68
+ };
45
69
  export type CanUpdateEffectPropsResponseTrue = {
46
70
  canUpdate: true;
47
71
  callee: string;
@@ -71,7 +95,11 @@ export declare const makeSequencePropsSubscriptionKey: (key: SequencePropsSubscr
71
95
  export declare const VisualModePropStatusesContext: React.Context<VisualModePropStatuses>;
72
96
  export declare const VisualModePropStatusesRefContext: React.Context<VisualModePropStatusesRef>;
73
97
  export declare const VisualModeDragOverridesContext: React.Context<VisualModeDragOverrides>;
98
+ export declare const useDragOverridesForNodePath: (nodePath: SequencePropsSubscriptionKey | null) => Record<string, DragOverrideValue>;
99
+ export declare const useActiveFromDragOverrideKeys: () => ReadonlySet<string>;
100
+ export declare const useEffectDragOverridesForNodePath: (nodePath: SequencePropsSubscriptionKey | null, effectCount: number) => Record<string, Record<string, DragOverrideValue>>;
74
101
  export declare const VisualModeSettersContext: React.Context<VisualModeSetters>;
102
+ export declare const VisualModeBatchSettersContext: React.Context<VisualModeBatchSetters | null>;
75
103
  export type SequencePropsSubscriptionKey = {
76
104
  absolutePath: string;
77
105
  nodePath: SequenceNodePath;
@@ -33,13 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SequenceManagerProvider = exports.VisualModeSettersContext = exports.VisualModeDragOverridesContext = exports.VisualModePropStatusesRefContext = exports.VisualModePropStatusesContext = exports.makeSequencePropsSubscriptionKey = exports.DisableSequenceRegistrationProvider = exports.DisableSequenceRegistrationContext = exports.SequenceRegistrationContext = exports.SequenceManagerRefContext = exports.SequenceManager = void 0;
36
+ exports.SequenceManagerProvider = exports.VisualModeBatchSettersContext = exports.VisualModeSettersContext = exports.useEffectDragOverridesForNodePath = exports.useActiveFromDragOverrideKeys = exports.useDragOverridesForNodePath = exports.VisualModeDragOverridesContext = exports.VisualModePropStatusesRefContext = exports.VisualModePropStatusesContext = exports.makeSequencePropsSubscriptionKey = exports.VisualModeDragOverridesSubscriptionContext = exports.DisableSequenceRegistrationProvider = exports.DisableSequenceRegistrationContext = exports.SequenceRegistrationContext = exports.SequenceManagerRefContext = exports.useSequenceManagerSequences = exports.SequenceManager = exports.SequenceManagerActionsContext = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = __importStar(require("react"));
39
39
  const sequence_order_marker_js_1 = require("./sequence-order-marker.js");
40
40
  const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
41
+ const use_sync_external_store_js_1 = require("./use-sync-external-store.js");
41
42
  const useIsomorphicLayoutEffect = typeof window === 'undefined' ? react_1.default.useEffect : react_1.default.useLayoutEffect;
42
- exports.SequenceManager = react_1.default.createContext({
43
+ const defaultSequenceManager = {
43
44
  registerSequence: () => {
44
45
  throw new Error('SequenceManagerContext not initialized');
45
46
  },
@@ -48,7 +49,31 @@ exports.SequenceManager = react_1.default.createContext({
48
49
  throw new Error('SequenceManagerContext not initialized');
49
50
  },
50
51
  sequences: [],
52
+ };
53
+ exports.SequenceManagerActionsContext = react_1.default.createContext({
54
+ registerSequence: defaultSequenceManager.registerSequence,
55
+ updateSequence: defaultSequenceManager.updateSequence,
56
+ unregisterSequence: defaultSequenceManager.unregisterSequence,
57
+ });
58
+ exports.SequenceManager = react_1.default.createContext(defaultSequenceManager);
59
+ const NativeSequenceManagerProvider = exports.SequenceManager.Provider;
60
+ const SequenceManagerProviderWithActions = ({ value, children }) => {
61
+ const actions = (0, react_1.useMemo)(() => ({
62
+ registerSequence: value.registerSequence,
63
+ updateSequence: value.updateSequence,
64
+ unregisterSequence: value.unregisterSequence,
65
+ }), [value.registerSequence, value.updateSequence, value.unregisterSequence]);
66
+ return (jsx_runtime_1.jsx(exports.SequenceManagerActionsContext.Provider, { value: actions, children: jsx_runtime_1.jsx(NativeSequenceManagerProvider, { value: value, children: children }) }));
67
+ };
68
+ // Keep custom SequenceManager.Provider trees in sync with the stable actions
69
+ // context while preserving the legacy reactive sequence-list context.
70
+ Object.defineProperty(exports.SequenceManager, 'Provider', {
71
+ value: SequenceManagerProviderWithActions,
51
72
  });
73
+ const useSequenceManagerSequences = () => {
74
+ return (0, react_1.useContext)(exports.SequenceManager).sequences;
75
+ };
76
+ exports.useSequenceManagerSequences = useSequenceManagerSequences;
52
77
  exports.SequenceManagerRefContext = react_1.default.createContext({
53
78
  current: [],
54
79
  });
@@ -58,6 +83,17 @@ const DisableSequenceRegistrationProvider = ({ children }) => {
58
83
  return react_1.default.createElement(exports.DisableSequenceRegistrationContext.Provider, { value: true }, children);
59
84
  };
60
85
  exports.DisableSequenceRegistrationProvider = DisableSequenceRegistrationProvider;
86
+ exports.VisualModeDragOverridesSubscriptionContext = react_1.default.createContext(null);
87
+ const ActiveFromDragOverrideKeysContext = react_1.default.createContext(null);
88
+ const SequenceManagerScopeProviders = ({ children, dragOverridesSubscription, fromKeys }) => {
89
+ const manager = (0, react_1.useContext)(exports.SequenceManagerActionsContext);
90
+ const scopedDragOverridesSubscription = (0, react_1.useMemo)(() => ({ ...dragOverridesSubscription, manager }), [dragOverridesSubscription, manager]);
91
+ const activeFromDragOverrideKeys = (0, react_1.useMemo)(() => ({ manager, keys: fromKeys }), [fromKeys, manager]);
92
+ return (jsx_runtime_1.jsx(ActiveFromDragOverrideKeysContext.Provider, { value: activeFromDragOverrideKeys, children: jsx_runtime_1.jsx(exports.VisualModeDragOverridesSubscriptionContext.Provider, { value: scopedDragOverridesSubscription, children: children }) }));
93
+ };
94
+ const emptyDragOverrides = {};
95
+ const emptyFromOverrideKeys = new Set();
96
+ const emptyEffectDragOverrides = {};
61
97
  const makeSequencePropsSubscriptionKey = (key) => {
62
98
  return `${key.absolutePath}\0${key.nodePath.join('.')}\0${key.sequenceKeys.join('.')}\0${key.effectKeys.map((keys) => keys.join('.')).join('.')}`;
63
99
  };
@@ -76,6 +112,67 @@ exports.VisualModeDragOverridesContext = react_1.default.createContext({
76
112
  throw new Error('VisualModeDragOverridesContext not initialized');
77
113
  },
78
114
  });
115
+ /* eslint-disable react-hooks/rules-of-hooks */
116
+ const useDragOverridesForNodePath = (nodePath) => {
117
+ const subscription = (0, react_1.useContext)(exports.VisualModeDragOverridesSubscriptionContext);
118
+ const manager = (0, react_1.useContext)(exports.SequenceManagerActionsContext);
119
+ const scopedSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.manager) === manager ? subscription : null;
120
+ // Legacy providers only supply VisualModeDragOverridesContext. Its presence is
121
+ // fixed for the lifetime of a mounted tree.
122
+ const legacy = scopedSubscription === null
123
+ ? (0, react_1.useContext)(exports.VisualModeDragOverridesContext)
124
+ : null;
125
+ const key = nodePath === null ? null : (0, exports.makeSequencePropsSubscriptionKey)(nodePath);
126
+ const subscribe = (0, react_1.useCallback)((listener) => {
127
+ var _a;
128
+ return (_a = scopedSubscription === null || scopedSubscription === void 0 ? void 0 : scopedSubscription.subscribe(key, listener)) !== null && _a !== void 0 ? _a : (() => undefined);
129
+ }, [key, scopedSubscription]);
130
+ const getSnapshot = (0, react_1.useCallback)(() => {
131
+ var _a;
132
+ return (_a = scopedSubscription === null || scopedSubscription === void 0 ? void 0 : scopedSubscription.getSnapshot(key)) !== null && _a !== void 0 ? _a : emptyDragOverrides;
133
+ }, [key, scopedSubscription]);
134
+ const overrides = (0, use_sync_external_store_js_1.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
135
+ return legacy !== null && nodePath !== null
136
+ ? legacy.getDragOverrides(nodePath)
137
+ : overrides;
138
+ };
139
+ exports.useDragOverridesForNodePath = useDragOverridesForNodePath;
140
+ const useActiveFromDragOverrideKeys = () => {
141
+ const snapshot = (0, react_1.useContext)(ActiveFromDragOverrideKeysContext);
142
+ const manager = (0, react_1.useContext)(exports.SequenceManagerActionsContext);
143
+ return (snapshot === null || snapshot === void 0 ? void 0 : snapshot.manager) === manager ? snapshot.keys : emptyFromOverrideKeys;
144
+ };
145
+ exports.useActiveFromDragOverrideKeys = useActiveFromDragOverrideKeys;
146
+ const useEffectDragOverridesForNodePath = (nodePath, effectCount) => {
147
+ const subscription = (0, react_1.useContext)(exports.VisualModeDragOverridesSubscriptionContext);
148
+ const manager = (0, react_1.useContext)(exports.SequenceManagerActionsContext);
149
+ const scopedSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.manager) === manager ? subscription : null;
150
+ // Legacy providers only supply VisualModeDragOverridesContext. Its presence is
151
+ // fixed for the lifetime of a mounted tree.
152
+ const legacy = scopedSubscription === null
153
+ ? (0, react_1.useContext)(exports.VisualModeDragOverridesContext)
154
+ : null;
155
+ const key = nodePath === null ? null : (0, exports.makeSequencePropsSubscriptionKey)(nodePath);
156
+ const subscribe = (0, react_1.useCallback)((listener) => {
157
+ var _a;
158
+ return (_a = scopedSubscription === null || scopedSubscription === void 0 ? void 0 : scopedSubscription.subscribeEffects(key, listener)) !== null && _a !== void 0 ? _a : (() => undefined);
159
+ }, [key, scopedSubscription]);
160
+ const getSnapshot = (0, react_1.useCallback)(() => {
161
+ var _a;
162
+ return (_a = scopedSubscription === null || scopedSubscription === void 0 ? void 0 : scopedSubscription.getEffectSnapshot(key)) !== null && _a !== void 0 ? _a : emptyEffectDragOverrides;
163
+ }, [key, scopedSubscription]);
164
+ const overrides = (0, use_sync_external_store_js_1.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
165
+ if (legacy !== null && nodePath !== null) {
166
+ const legacyOverrides = {};
167
+ for (let index = 0; index < effectCount; index++) {
168
+ legacyOverrides[index] = legacy.getEffectDragOverrides(nodePath, index);
169
+ }
170
+ return legacyOverrides;
171
+ }
172
+ return overrides;
173
+ };
174
+ exports.useEffectDragOverridesForNodePath = useEffectDragOverridesForNodePath;
175
+ /* eslint-enable react-hooks/rules-of-hooks */
79
176
  exports.VisualModeSettersContext = react_1.default.createContext({
80
177
  setDragOverrides: () => {
81
178
  throw new Error('VisualModeSettersContext not initialized');
@@ -96,6 +193,7 @@ exports.VisualModeSettersContext = react_1.default.createContext({
96
193
  throw new Error('VisualModeSettersContext not initialized');
97
194
  },
98
195
  });
196
+ exports.VisualModeBatchSettersContext = react_1.default.createContext(null);
99
197
  const effectDragOverridesKey = (nodePath, effectIndex) => `${(0, exports.makeSequencePropsSubscriptionKey)(nodePath)}.effects.${effectIndex}`;
100
198
  const SequenceManagerProvider = ({ children }) => {
101
199
  const { isStudio } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
@@ -105,45 +203,202 @@ const SequenceManagerProvider = ({ children }) => {
105
203
  const [sequences, setSequences] = (0, react_1.useState)([]);
106
204
  const sequencesRef = (0, react_1.useRef)(sequences);
107
205
  sequencesRef.current = sequences;
108
- const [dragOverrides, setControlOverrides] = (0, react_1.useState)({});
109
- const controlOverridesRef = (0, react_1.useRef)(dragOverrides);
110
- controlOverridesRef.current = dragOverrides;
206
+ const [dragOverrideState, setDragOverrideState] = (0, react_1.useState)(() => ({
207
+ overrides: {},
208
+ fromKeys: new Set(),
209
+ }));
210
+ const dragOverrides = dragOverrideState.overrides;
211
+ const dragOverridesStore = (0, react_1.useRef)({
212
+ snapshot: dragOverrides,
213
+ listeners: new Map(),
214
+ });
111
215
  const [effectDragOverridesState, setEffectDragOverridesState] = (0, react_1.useState)({});
216
+ const effectDragOverridesStore = (0, react_1.useRef)({
217
+ snapshot: effectDragOverridesState,
218
+ byNode: new Map(),
219
+ listeners: new Map(),
220
+ });
112
221
  const [propStatuses, setPropStatusesMapState] = (0, react_1.useState)({});
113
222
  const propStatusesRef = (0, react_1.useRef)(propStatuses);
114
223
  propStatusesRef.current = propStatuses;
115
- const setDragOverrides = (0, react_1.useCallback)((nodePath, key, value) => {
116
- setControlOverrides((prev) => ({
117
- ...prev,
118
- [(0, exports.makeSequencePropsSubscriptionKey)(nodePath)]: {
119
- ...prev[(0, exports.makeSequencePropsSubscriptionKey)(nodePath)],
120
- [key]: value,
121
- },
122
- }));
224
+ const setDragOverridesBatch = (0, react_1.useCallback)((overrides) => {
225
+ setDragOverrideState((prevState) => {
226
+ var _a;
227
+ const prev = prevState.overrides;
228
+ let next = null;
229
+ let nextFromKeys = prevState.fromKeys;
230
+ for (const { nodePath, key, value } of overrides) {
231
+ const mapKey = (0, exports.makeSequencePropsSubscriptionKey)(nodePath);
232
+ const existing = (_a = (next !== null && next !== void 0 ? next : prev)[mapKey]) === null || _a === void 0 ? void 0 : _a[key];
233
+ if (existing === value ||
234
+ ((existing === null || existing === void 0 ? void 0 : existing.type) === 'static' &&
235
+ value.type === 'static' &&
236
+ Object.is(existing.value, value.value))) {
237
+ continue;
238
+ }
239
+ if (next === null) {
240
+ next = { ...prev };
241
+ }
242
+ if (next[mapKey] === prev[mapKey]) {
243
+ next[mapKey] = { ...prev[mapKey] };
244
+ }
245
+ next[mapKey][key] = value;
246
+ if (key === 'from' && !nextFromKeys.has(mapKey)) {
247
+ nextFromKeys = new Set(nextFromKeys);
248
+ nextFromKeys.add(mapKey);
249
+ }
250
+ }
251
+ return next === null
252
+ ? prevState
253
+ : { overrides: next, fromKeys: nextFromKeys };
254
+ });
123
255
  }, []);
256
+ const setDragOverrides = (0, react_1.useCallback)((nodePath, key, value) => setDragOverridesBatch([{ nodePath, key, value }]), [setDragOverridesBatch]);
257
+ const subscribeDragOverrides = (0, react_1.useCallback)((key, listener) => {
258
+ if (key === null) {
259
+ return () => undefined;
260
+ }
261
+ let listeners = dragOverridesStore.current.listeners.get(key);
262
+ if (!listeners) {
263
+ listeners = new Set();
264
+ dragOverridesStore.current.listeners.set(key, listeners);
265
+ }
266
+ listeners.add(listener);
267
+ return () => {
268
+ listeners.delete(listener);
269
+ if (listeners.size === 0) {
270
+ dragOverridesStore.current.listeners.delete(key);
271
+ }
272
+ };
273
+ }, []);
274
+ const getDragOverridesSnapshot = (0, react_1.useCallback)((key) => {
275
+ var _a;
276
+ return key === null
277
+ ? emptyDragOverrides
278
+ : ((_a = dragOverridesStore.current.snapshot[key]) !== null && _a !== void 0 ? _a : emptyDragOverrides);
279
+ }, []);
280
+ useIsomorphicLayoutEffect(() => {
281
+ var _a;
282
+ const previous = dragOverridesStore.current.snapshot;
283
+ dragOverridesStore.current.snapshot = dragOverrides;
284
+ for (const key of new Set([
285
+ ...Object.keys(previous),
286
+ ...Object.keys(dragOverrides),
287
+ ])) {
288
+ if (previous[key] !== dragOverrides[key]) {
289
+ for (const listener of (_a = dragOverridesStore.current.listeners.get(key)) !== null && _a !== void 0 ? _a : []) {
290
+ listener();
291
+ }
292
+ }
293
+ }
294
+ }, [dragOverrides]);
295
+ const subscribeEffectDragOverrides = (0, react_1.useCallback)((key, listener) => {
296
+ if (key === null) {
297
+ return () => undefined;
298
+ }
299
+ let listeners = effectDragOverridesStore.current.listeners.get(key);
300
+ if (!listeners) {
301
+ listeners = new Set();
302
+ effectDragOverridesStore.current.listeners.set(key, listeners);
303
+ }
304
+ listeners.add(listener);
305
+ return () => {
306
+ listeners.delete(listener);
307
+ if (listeners.size === 0) {
308
+ effectDragOverridesStore.current.listeners.delete(key);
309
+ }
310
+ };
311
+ }, []);
312
+ const getEffectDragOverridesSnapshot = (0, react_1.useCallback)((key) => {
313
+ var _a;
314
+ return key === null
315
+ ? emptyEffectDragOverrides
316
+ : ((_a = effectDragOverridesStore.current.byNode.get(key)) !== null && _a !== void 0 ? _a : emptyEffectDragOverrides);
317
+ }, []);
318
+ useIsomorphicLayoutEffect(() => {
319
+ var _a;
320
+ const previous = effectDragOverridesStore.current.snapshot;
321
+ const byNode = new Map(effectDragOverridesStore.current.byNode);
322
+ const changedNodes = new Set();
323
+ for (const flatKey of new Set([
324
+ ...Object.keys(previous),
325
+ ...Object.keys(effectDragOverridesState),
326
+ ])) {
327
+ if (previous[flatKey] === effectDragOverridesState[flatKey]) {
328
+ continue;
329
+ }
330
+ const separator = flatKey.lastIndexOf('.effects.');
331
+ if (separator === -1) {
332
+ throw new Error('Invalid effect drag override key');
333
+ }
334
+ const nodeKey = flatKey.slice(0, separator);
335
+ const effectIndex = flatKey.slice(separator + '.effects.'.length);
336
+ if (!changedNodes.has(nodeKey)) {
337
+ byNode.set(nodeKey, { ...byNode.get(nodeKey) });
338
+ changedNodes.add(nodeKey);
339
+ }
340
+ const next = byNode.get(nodeKey);
341
+ if (effectDragOverridesState[flatKey] === undefined) {
342
+ delete next[effectIndex];
343
+ }
344
+ else {
345
+ next[effectIndex] = effectDragOverridesState[flatKey];
346
+ }
347
+ }
348
+ for (const nodeKey of changedNodes) {
349
+ if (Object.keys(byNode.get(nodeKey)).length === 0) {
350
+ byNode.delete(nodeKey);
351
+ }
352
+ }
353
+ effectDragOverridesStore.current.snapshot = effectDragOverridesState;
354
+ effectDragOverridesStore.current.byNode = byNode;
355
+ for (const nodeKey of changedNodes) {
356
+ for (const listener of (_a = effectDragOverridesStore.current.listeners.get(nodeKey)) !== null && _a !== void 0 ? _a : []) {
357
+ listener();
358
+ }
359
+ }
360
+ }, [effectDragOverridesState]);
124
361
  const clearDragOverrides = (0, react_1.useCallback)((nodePath) => {
125
- setControlOverrides((prev) => {
362
+ setDragOverrideState((prevState) => {
363
+ const prev = prevState.overrides;
126
364
  const key = (0, exports.makeSequencePropsSubscriptionKey)(nodePath);
127
365
  if (!prev[key]) {
128
- return prev;
366
+ return prevState;
129
367
  }
130
368
  const next = { ...prev };
131
369
  delete next[key];
132
- return next;
370
+ const nextFromKeys = prevState.fromKeys.has(key)
371
+ ? new Set(prevState.fromKeys)
372
+ : prevState.fromKeys;
373
+ nextFromKeys.delete(key);
374
+ return { overrides: next, fromKeys: nextFromKeys };
133
375
  });
134
376
  }, []);
135
- const setEffectDragOverrides = (0, react_1.useCallback)((nodePath, effectIndex, key, value) => {
377
+ const setEffectDragOverridesBatch = (0, react_1.useCallback)((overrides) => {
136
378
  setEffectDragOverridesState((prev) => {
137
- const mapKey = effectDragOverridesKey(nodePath, effectIndex);
138
- return {
139
- ...prev,
140
- [mapKey]: {
141
- ...prev[mapKey],
142
- [key]: value,
143
- },
144
- };
379
+ var _a;
380
+ let next = null;
381
+ for (const { nodePath, effectIndex, key, value } of overrides) {
382
+ const mapKey = effectDragOverridesKey(nodePath, effectIndex);
383
+ const existing = (_a = (next !== null && next !== void 0 ? next : prev)[mapKey]) === null || _a === void 0 ? void 0 : _a[key];
384
+ if (existing === value ||
385
+ ((existing === null || existing === void 0 ? void 0 : existing.type) === 'static' &&
386
+ value.type === 'static' &&
387
+ Object.is(existing.value, value.value))) {
388
+ continue;
389
+ }
390
+ if (next === null) {
391
+ next = { ...prev };
392
+ }
393
+ if (next[mapKey] === prev[mapKey]) {
394
+ next[mapKey] = { ...prev[mapKey] };
395
+ }
396
+ next[mapKey][key] = value;
397
+ }
398
+ return next !== null && next !== void 0 ? next : prev;
145
399
  });
146
400
  }, []);
401
+ const setEffectDragOverrides = (0, react_1.useCallback)((nodePath, effectIndex, key, value) => setEffectDragOverridesBatch([{ nodePath, effectIndex, key, value }]), [setEffectDragOverridesBatch]);
147
402
  const clearEffectDragOverrides = (0, react_1.useCallback)((nodePath, effectIndex) => {
148
403
  setEffectDragOverridesState((prev) => {
149
404
  const mapKey = effectDragOverridesKey(nodePath, effectIndex);
@@ -269,6 +524,17 @@ const SequenceManagerProvider = ({ children }) => {
269
524
  unregisterSequence,
270
525
  };
271
526
  }, [registerSequence, sequences, unregisterSequence, updateSequence]);
527
+ const dragOverridesSubscription = (0, react_1.useMemo)(() => ({
528
+ subscribe: subscribeDragOverrides,
529
+ getSnapshot: getDragOverridesSnapshot,
530
+ subscribeEffects: subscribeEffectDragOverrides,
531
+ getEffectSnapshot: getEffectDragOverridesSnapshot,
532
+ }), [
533
+ getDragOverridesSnapshot,
534
+ getEffectDragOverridesSnapshot,
535
+ subscribeDragOverrides,
536
+ subscribeEffectDragOverrides,
537
+ ]);
272
538
  const getDragOverrides = (0, react_1.useCallback)((nodePath) => {
273
539
  var _a;
274
540
  return (_a = dragOverrides[(0, exports.makeSequencePropsSubscriptionKey)(nodePath)]) !== null && _a !== void 0 ? _a : {};
@@ -305,7 +571,8 @@ const SequenceManagerProvider = ({ children }) => {
305
571
  setPropStatuses,
306
572
  remapPropStatuses,
307
573
  ]);
308
- const providers = (jsx_runtime_1.jsx(exports.SequenceManagerRefContext.Provider, { value: sequencesRef, children: jsx_runtime_1.jsx(exports.SequenceManager.Provider, { value: sequenceContext, children: jsx_runtime_1.jsx(exports.VisualModePropStatusesRefContext.Provider, { value: propStatusesRef, children: jsx_runtime_1.jsx(exports.VisualModePropStatusesContext.Provider, { value: propStatusesContext, children: jsx_runtime_1.jsx(exports.VisualModeDragOverridesContext.Provider, { value: dragOverridesContext, children: jsx_runtime_1.jsx(exports.VisualModeSettersContext.Provider, { value: settersContext, children: children }) }) }) }) }) }));
574
+ const batchSettersContext = (0, react_1.useMemo)(() => ({ setDragOverridesBatch, setEffectDragOverridesBatch }), [setDragOverridesBatch, setEffectDragOverridesBatch]);
575
+ const providers = (jsx_runtime_1.jsx(exports.SequenceManagerRefContext.Provider, { value: sequencesRef, children: jsx_runtime_1.jsx(exports.SequenceManager.Provider, { value: sequenceContext, children: jsx_runtime_1.jsx(exports.VisualModePropStatusesRefContext.Provider, { value: propStatusesRef, children: jsx_runtime_1.jsx(exports.VisualModePropStatusesContext.Provider, { value: propStatusesContext, children: jsx_runtime_1.jsx(SequenceManagerScopeProviders, { dragOverridesSubscription: dragOverridesSubscription, fromKeys: dragOverrideState.fromKeys, children: jsx_runtime_1.jsx(exports.VisualModeDragOverridesContext.Provider, { value: dragOverridesContext, children: jsx_runtime_1.jsx(exports.VisualModeSettersContext.Provider, { value: settersContext, children: jsx_runtime_1.jsx(exports.VisualModeBatchSettersContext.Provider, { value: batchSettersContext, children: children }) }) }) }) }) }) }) }));
309
576
  return isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceManagerOrderMarker, { managerId: sequenceManagerId, children: providers })) : (providers);
310
577
  };
311
578
  exports.SequenceManagerProvider = SequenceManagerProvider;
@@ -8,6 +8,7 @@ const runtime_value_store_js_1 = require("../runtime-value-store.js");
8
8
  const sequence_node_path_js_1 = require("../sequence-node-path.js");
9
9
  const SequenceManager_js_1 = require("../SequenceManager.js");
10
10
  const use_current_frame_js_1 = require("../use-current-frame.js");
11
+ const emptyDragOverrides = {};
11
12
  const mergeOverrides = ({ descriptor, propStatusOverrides, dragOverrides, frame, }) => {
12
13
  if (!propStatusOverrides && !dragOverrides) {
13
14
  return { params: descriptor.params, effectKey: descriptor.effectKey };
@@ -123,14 +124,15 @@ const useMemoizedEffects = ({ effects, overrideId, }) => {
123
124
  var _a;
124
125
  const previousRef = (0, react_1.useRef)(null);
125
126
  const { propStatuses } = (0, react_1.useContext)(SequenceManager_js_1.VisualModePropStatusesContext);
126
- const { getEffectDragOverrides } = (0, react_1.useContext)(SequenceManager_js_1.VisualModeDragOverridesContext);
127
127
  const frame = (0, use_current_frame_js_1.useCurrentFrame)();
128
128
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(sequence_node_path_js_1.OverrideIdsToNodePathsGettersContext);
129
129
  const previous = previousRef.current;
130
130
  const nodePath = overrideId
131
131
  ? ((_a = overrideIdToNodePathMappings[overrideId]) !== null && _a !== void 0 ? _a : null)
132
132
  : null;
133
+ const effectDragOverrides = (0, SequenceManager_js_1.useEffectDragOverridesForNodePath)(nodePath, effects.length);
133
134
  const resolved = effects.map((descriptor, index) => {
135
+ var _a;
134
136
  if (nodePath === null) {
135
137
  return {
136
138
  descriptor,
@@ -146,7 +148,7 @@ const useMemoizedEffects = ({ effects, overrideId, }) => {
146
148
  const propStatusOverrides = effectStatus.type === 'can-update-effect'
147
149
  ? resolvePropStatusOverrides(effectStatus.props, frame)
148
150
  : null;
149
- const dragOverridesMap = getEffectDragOverrides(nodePath, index);
151
+ const dragOverridesMap = (_a = effectDragOverrides[index]) !== null && _a !== void 0 ? _a : emptyDragOverrides;
150
152
  const dragOverrides = Object.keys(dragOverridesMap).length === 0 ? null : dragOverridesMap;
151
153
  const { params, effectKey } = mergeOverrides({
152
154
  descriptor,