@remotion/studio 4.0.470 → 4.0.471

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.
Files changed (35) hide show
  1. package/dist/components/ContextMenu.d.ts +7 -2
  2. package/dist/components/ContextMenu.js +50 -10
  3. package/dist/components/Preview.js +2 -1
  4. package/dist/components/SelectedOutlineOverlay.d.ts +31 -0
  5. package/dist/components/SelectedOutlineOverlay.js +100 -35
  6. package/dist/components/Timeline/Timeline.js +76 -1
  7. package/dist/components/Timeline/TimelineDeleteKeybindings.js +15 -0
  8. package/dist/components/Timeline/TimelineDragHandler.js +1 -0
  9. package/dist/components/Timeline/TimelineEffectItem.js +157 -4
  10. package/dist/components/Timeline/TimelineKeyframeControls.js +16 -11
  11. package/dist/components/Timeline/TimelineRowChrome.d.ts +3 -0
  12. package/dist/components/Timeline/TimelineRowChrome.js +3 -3
  13. package/dist/components/Timeline/TimelineSequenceItem.js +91 -1
  14. package/dist/components/Timeline/call-delete-keyframe.d.ts +16 -0
  15. package/dist/components/Timeline/call-delete-keyframe.js +86 -14
  16. package/dist/components/Timeline/delete-selected-keyframe.d.ts +10 -0
  17. package/dist/components/Timeline/delete-selected-keyframe.js +48 -7
  18. package/dist/components/Timeline/delete-selected-timeline-item.js +6 -11
  19. package/dist/components/Timeline/reset-selected-timeline-props.d.ts +38 -0
  20. package/dist/components/Timeline/reset-selected-timeline-props.js +143 -0
  21. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +3 -2
  22. package/dist/components/Timeline/sequence-props-subscription-store.js +2 -1
  23. package/dist/components/Timeline/timeline-scroll-logic.js +3 -3
  24. package/dist/components/Timeline/use-sequence-props-subscription.js +2 -1
  25. package/dist/esm/{chunk-dny42qnq.js → chunk-z0z9d4r0.js} +1704 -962
  26. package/dist/esm/internals.mjs +1704 -962
  27. package/dist/esm/previewEntry.mjs +1711 -967
  28. package/dist/esm/renderEntry.mjs +1 -1
  29. package/dist/helpers/get-left-of-timeline-slider.js +1 -1
  30. package/dist/helpers/get-timeline-sequence-layout.js +10 -11
  31. package/dist/helpers/open-in-editor.d.ts +19 -1
  32. package/dist/helpers/open-in-editor.js +42 -4
  33. package/dist/helpers/use-menu-structure.js +0 -1
  34. package/dist/state/z-index.js +5 -2
  35. package/package.json +10 -10
@@ -1,7 +1,12 @@
1
1
  import React from 'react';
2
2
  import type { ComboboxValue } from './NewComposition/ComboBox';
3
- export declare const ContextMenu: React.FC<{
3
+ type ContextMenuProps = {
4
4
  readonly children: React.ReactNode;
5
5
  readonly values: ComboboxValue[];
6
6
  readonly onOpen: (() => void) | null;
7
- }>;
7
+ readonly style?: React.CSSProperties;
8
+ readonly className?: string;
9
+ readonly onPointerDown?: React.PointerEventHandler<HTMLDivElement>;
10
+ };
11
+ export declare const ContextMenu: React.ForwardRefExoticComponent<ContextMenuProps & React.RefAttributes<HTMLDivElement>>;
12
+ export {};
@@ -1,4 +1,37 @@
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
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -6,7 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.ContextMenu = void 0;
7
40
  const jsx_runtime_1 = require("react/jsx-runtime");
8
41
  const player_1 = require("@remotion/player");
9
- const react_1 = require("react");
42
+ const react_1 = __importStar(require("react"));
10
43
  const react_dom_1 = __importDefault(require("react-dom"));
11
44
  const mobile_layout_1 = require("../helpers/mobile-layout");
12
45
  const noop_1 = require("../helpers/noop");
@@ -14,13 +47,20 @@ const z_index_1 = require("../state/z-index");
14
47
  const portals_1 = require("./Menu/portals");
15
48
  const styles_1 = require("./Menu/styles");
16
49
  const MenuContent_1 = require("./NewComposition/MenuContent");
17
- const ContextMenu = ({ children, values, onOpen }) => {
50
+ exports.ContextMenu = react_1.default.forwardRef(({ children, values, onOpen, style = undefined, className = undefined, onPointerDown = undefined, }, forwardedRef) => {
18
51
  const ref = (0, react_1.useRef)(null);
19
52
  const [opened, setOpened] = (0, react_1.useState)({ type: 'not-open' });
20
53
  const { currentZIndex } = (0, z_index_1.useZIndex)();
21
- const style = (0, react_1.useMemo)(() => {
22
- return {};
23
- }, []);
54
+ const setRef = (0, react_1.useCallback)((node) => {
55
+ ref.current = node;
56
+ if (typeof forwardedRef === 'function') {
57
+ forwardedRef(node);
58
+ return;
59
+ }
60
+ if (forwardedRef) {
61
+ forwardedRef.current = node;
62
+ }
63
+ }, [forwardedRef]);
24
64
  const size = player_1.PlayerInternals.useElementSize(ref, {
25
65
  triggerOnWindowResize: true,
26
66
  shouldApplyCssTransforms: true,
@@ -93,12 +133,12 @@ const ContextMenu = ({ children, values, onOpen }) => {
93
133
  setOpened({ type: 'not-open' });
94
134
  }, []);
95
135
  // Prevent deselection of a selected item
96
- const onPointerDown = (0, react_1.useCallback)((e) => {
136
+ const onMenuPointerDown = (0, react_1.useCallback)((e) => {
97
137
  e.stopPropagation();
98
138
  }, []);
99
139
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
100
- jsx_runtime_1.jsx("div", { ref: ref, onContextMenu: () => false, style: style, children: children }), portalStyle
101
- ? react_dom_1.default.createPortal(jsx_runtime_1.jsx("div", { style: styles_1.fullScreenOverlay, children: jsx_runtime_1.jsx("div", { style: styles_1.outerPortal, className: "css-reset", children: jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, children: jsx_runtime_1.jsx("div", { style: portalStyle, onPointerDown: onPointerDown, children: jsx_runtime_1.jsx(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: noop_1.noop, values: values, onHide: onHide, leaveLeftSpace: true, preselectIndex: false, topItemCanBeUnselected: false, fixedHeight: null }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
140
+ jsx_runtime_1.jsx("div", { ref: setRef, onContextMenu: () => false, style: style, className: className, onPointerDown: onPointerDown, children: children }), portalStyle
141
+ ? react_dom_1.default.createPortal(jsx_runtime_1.jsx("div", { style: styles_1.fullScreenOverlay, children: jsx_runtime_1.jsx("div", { style: styles_1.outerPortal, className: "css-reset", children: jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, children: jsx_runtime_1.jsx("div", { style: portalStyle, onPointerDown: onMenuPointerDown, children: jsx_runtime_1.jsx(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: noop_1.noop, values: values, onHide: onHide, leaveLeftSpace: true, preselectIndex: false, topItemCanBeUnselected: false, fixedHeight: null }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
102
142
  : null] }));
103
- };
104
- exports.ContextMenu = ContextMenu;
143
+ });
144
+ exports.ContextMenu.displayName = 'ContextMenu';
@@ -72,6 +72,7 @@ const containerStyle = (options) => {
72
72
  width: options.width,
73
73
  height: options.height,
74
74
  display: 'flex',
75
+ overflow: 'hidden',
75
76
  position: 'absolute',
76
77
  backgroundColor: (0, checkerboard_background_1.checkerboardBackgroundColor)(options.checkerboard),
77
78
  backgroundImage: (0, checkerboard_background_1.checkerboardBackgroundImage)(options.checkerboard),
@@ -122,7 +123,7 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
122
123
  position: 'absolute',
123
124
  left: centerX - previewSize.translation.x,
124
125
  top: centerY - previewSize.translation.y,
125
- overflow: 'hidden',
126
+ overflow: canvasContent.type === 'composition' ? 'visible' : 'hidden',
126
127
  justifyContent: canvasContent.type === 'asset' ? 'center' : 'flex-start',
127
128
  alignItems: canvasContent.type === 'asset' &&
128
129
  (0, exports.getPreviewFileType)(canvasContent.asset) === 'audio'
@@ -1,10 +1,25 @@
1
1
  import React from 'react';
2
+ import type { CanUpdateSequencePropStatusTrue, SequencePropsSubscriptionKey, SequenceSchema } from 'remotion';
2
3
  import { type TimelineSelection } from './Timeline/TimelineSelection';
3
4
  type OutlinePoint = {
4
5
  readonly x: number;
5
6
  readonly y: number;
6
7
  };
7
8
  type UvCoordinate = readonly [number, number];
9
+ type SelectedOutlineDragTarget = {
10
+ readonly codeValue: CanUpdateSequencePropStatusTrue;
11
+ readonly clientId: string;
12
+ readonly fieldDefault: string | undefined;
13
+ readonly nodePath: SequencePropsSubscriptionKey;
14
+ readonly schema: SequenceSchema;
15
+ };
16
+ export type SelectedOutlineDragState = {
17
+ readonly defaultValue: string | null;
18
+ readonly key: string;
19
+ readonly startX: number;
20
+ readonly startY: number;
21
+ readonly target: SelectedOutlineDragTarget;
22
+ };
8
23
  export declare const getUvHandlePosition: (points: readonly [OutlinePoint, OutlinePoint, OutlinePoint, OutlinePoint], uv: UvCoordinate) => OutlinePoint;
9
24
  export declare const getUvCoordinateForPoint: (points: readonly [OutlinePoint, OutlinePoint, OutlinePoint, OutlinePoint], point: OutlinePoint) => UvCoordinate;
10
25
  type SelectedEffectFields = {
@@ -12,6 +27,22 @@ type SelectedEffectFields = {
12
27
  fieldKeys: Set<string>;
13
28
  };
14
29
  export declare const getSelectedEffectFieldsBySequenceKey: (selectedItems: readonly TimelineSelection[]) => Map<string, Map<number, SelectedEffectFields>>;
30
+ export declare const getSelectedOutlineDragValues: ({ dragStates, deltaX, deltaY, }: {
31
+ readonly dragStates: readonly SelectedOutlineDragState[];
32
+ readonly deltaX: number;
33
+ readonly deltaY: number;
34
+ }) => Map<string, string>;
35
+ export declare const getSelectedOutlineDragChanges: ({ dragStates, lastValues, }: {
36
+ readonly dragStates: readonly SelectedOutlineDragState[];
37
+ readonly lastValues: ReadonlyMap<string, string>;
38
+ }) => {
39
+ fileName: string;
40
+ nodePath: SequencePropsSubscriptionKey;
41
+ fieldKey: string;
42
+ value: string;
43
+ defaultValue: string | null;
44
+ schema: SequenceSchema;
45
+ }[];
15
46
  export declare const SelectedOutlineOverlay: React.FC<{
16
47
  readonly scale: number;
17
48
  }>;
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SelectedOutlineOverlay = exports.getSelectedEffectFieldsBySequenceKey = exports.getUvCoordinateForPoint = exports.getUvHandlePosition = void 0;
36
+ exports.SelectedOutlineOverlay = exports.getSelectedOutlineDragChanges = exports.getSelectedOutlineDragValues = exports.getSelectedEffectFieldsBySequenceKey = exports.getUvCoordinateForPoint = exports.getUvHandlePosition = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = __importStar(require("react"));
39
39
  const remotion_1 = require("remotion");
@@ -41,6 +41,7 @@ const calculate_timeline_1 = require("../helpers/calculate-timeline");
41
41
  const client_id_1 = require("../helpers/client-id");
42
42
  const colors_1 = require("../helpers/colors");
43
43
  const get_box_quads_ponyfill_1 = require("../helpers/get-box-quads-ponyfill");
44
+ const NotificationCenter_1 = require("./Notifications/NotificationCenter");
44
45
  const save_effect_prop_1 = require("./Timeline/save-effect-prop");
45
46
  const save_sequence_prop_1 = require("./Timeline/save-sequence-prop");
46
47
  const timeline_field_utils_1 = require("./Timeline/timeline-field-utils");
@@ -394,14 +395,73 @@ const outlinesAreEqual = (a, b) => {
394
395
  }
395
396
  return true;
396
397
  };
397
- const SelectedOutlinePolygon = ({ outline, scale, target }) => {
398
+ const getSelectedOutlineDragStates = ({ dragTargets, getDragOverrides, }) => {
399
+ return dragTargets.map((target) => {
400
+ var _a;
401
+ const dragOverrideValue = ((_a = getDragOverrides(target.nodePath)) !== null && _a !== void 0 ? _a : {})[translateFieldKey];
402
+ const effectiveValue = remotion_1.Internals.getEffectiveVisualModeValue({
403
+ codeValue: target.codeValue,
404
+ dragOverrideValue,
405
+ defaultValue: target.fieldDefault,
406
+ shouldResortToDefaultValueIfUndefined: true,
407
+ });
408
+ const [startX, startY] = (0, timeline_translate_utils_1.parseTranslate)(String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '0px 0px'));
409
+ return {
410
+ defaultValue: target.fieldDefault !== undefined
411
+ ? JSON.stringify(target.fieldDefault)
412
+ : null,
413
+ key: remotion_1.Internals.makeSequencePropsSubscriptionKey(target.nodePath),
414
+ startX,
415
+ startY,
416
+ target,
417
+ };
418
+ });
419
+ };
420
+ const getSelectedOutlineDragValues = ({ dragStates, deltaX, deltaY, }) => {
421
+ return new Map(dragStates.map((dragState) => [
422
+ dragState.key,
423
+ (0, timeline_translate_utils_1.serializeTranslate)(dragState.startX + deltaX, dragState.startY + deltaY),
424
+ ]));
425
+ };
426
+ exports.getSelectedOutlineDragValues = getSelectedOutlineDragValues;
427
+ const getSelectedOutlineDragChanges = ({ dragStates, lastValues, }) => {
428
+ return dragStates.flatMap((dragState) => {
429
+ const value = lastValues.get(dragState.key);
430
+ if (value === undefined) {
431
+ return [];
432
+ }
433
+ const stringifiedValue = JSON.stringify(value);
434
+ const shouldSave = value !== dragState.target.codeValue.codeValue &&
435
+ !(dragState.defaultValue === stringifiedValue &&
436
+ dragState.target.codeValue.codeValue === undefined);
437
+ if (!shouldSave) {
438
+ return [];
439
+ }
440
+ return [
441
+ {
442
+ fileName: dragState.target.nodePath.absolutePath,
443
+ nodePath: dragState.target.nodePath,
444
+ fieldKey: translateFieldKey,
445
+ value,
446
+ defaultValue: dragState.defaultValue,
447
+ schema: dragState.target.schema,
448
+ },
449
+ ];
450
+ });
451
+ };
452
+ exports.getSelectedOutlineDragChanges = getSelectedOutlineDragChanges;
453
+ const clearSelectedOutlineDragOverrides = ({ clearDragOverrides, dragStates, }) => {
454
+ for (const dragState of dragStates) {
455
+ clearDragOverrides(dragState.target.nodePath);
456
+ }
457
+ };
458
+ const SelectedOutlinePolygon = ({ allDragTargets, outline, scale, target }) => {
398
459
  var _a;
399
460
  const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
400
461
  const { setCodeValues, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
401
462
  const points = (0, react_1.useMemo)(() => outline.points.map(pointToString).join(' '), [outline.points]);
402
463
  const drag = (_a = target === null || target === void 0 ? void 0 : target.drag) !== null && _a !== void 0 ? _a : null;
403
464
  const onPointerDown = react_1.default.useCallback((event) => {
404
- var _a;
405
465
  if (event.button !== 0 || drag === null) {
406
466
  return;
407
467
  }
@@ -409,55 +469,57 @@ const SelectedOutlinePolygon = ({ outline, scale, target }) => {
409
469
  event.stopPropagation();
410
470
  const startPointerX = event.clientX;
411
471
  const startPointerY = event.clientY;
412
- const dragOverrideValue = ((_a = getDragOverrides(drag.nodePath)) !== null && _a !== void 0 ? _a : {})[translateFieldKey];
413
- const effectiveValue = remotion_1.Internals.getEffectiveVisualModeValue({
414
- codeValue: drag.codeValue,
415
- dragOverrideValue,
416
- defaultValue: drag.fieldDefault,
417
- shouldResortToDefaultValueIfUndefined: true,
472
+ const dragStates = getSelectedOutlineDragStates({
473
+ dragTargets: allDragTargets,
474
+ getDragOverrides,
418
475
  });
419
- const [startX, startY] = (0, timeline_translate_utils_1.parseTranslate)(String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '0px 0px'));
420
- const defaultValue = drag.fieldDefault !== undefined
421
- ? JSON.stringify(drag.fieldDefault)
422
- : null;
423
- let lastValue = null;
476
+ let lastValues = new Map();
424
477
  const onPointerMove = (moveEvent) => {
425
478
  moveEvent.preventDefault();
426
- const nextX = startX + (moveEvent.clientX - startPointerX) / scale;
427
- const nextY = startY + (moveEvent.clientY - startPointerY) / scale;
428
- lastValue = (0, timeline_translate_utils_1.serializeTranslate)(nextX, nextY);
429
- setDragOverrides(drag.nodePath, translateFieldKey, lastValue);
479
+ lastValues = (0, exports.getSelectedOutlineDragValues)({
480
+ dragStates,
481
+ deltaX: (moveEvent.clientX - startPointerX) / scale,
482
+ deltaY: (moveEvent.clientY - startPointerY) / scale,
483
+ });
484
+ for (const dragState of dragStates) {
485
+ const value = lastValues.get(dragState.key);
486
+ if (value === undefined) {
487
+ throw new Error('Expected drag value to be available');
488
+ }
489
+ setDragOverrides(dragState.target.nodePath, translateFieldKey, value);
490
+ }
430
491
  };
431
492
  const onPointerUp = () => {
432
493
  window.removeEventListener('pointermove', onPointerMove);
433
494
  window.removeEventListener('pointerup', onPointerUp);
434
495
  window.removeEventListener('pointercancel', onPointerUp);
435
- const stringifiedValue = lastValue === null ? null : JSON.stringify(lastValue);
436
- const shouldSave = lastValue !== null &&
437
- lastValue !== drag.codeValue.codeValue &&
438
- !(defaultValue === stringifiedValue &&
439
- drag.codeValue.codeValue === undefined);
440
- if (!shouldSave) {
441
- clearDragOverrides(drag.nodePath);
496
+ const changes = (0, exports.getSelectedOutlineDragChanges)({
497
+ dragStates,
498
+ lastValues,
499
+ });
500
+ if (changes.length === 0) {
501
+ clearSelectedOutlineDragOverrides({ clearDragOverrides, dragStates });
442
502
  return;
443
503
  }
444
- (0, save_sequence_prop_1.saveSequenceProp)({
445
- fileName: drag.nodePath.absolutePath,
446
- nodePath: drag.nodePath,
447
- fieldKey: translateFieldKey,
448
- value: lastValue,
449
- defaultValue,
450
- schema: drag.schema,
504
+ (0, save_sequence_prop_1.saveSequenceProps)({
505
+ changes,
451
506
  setCodeValues,
452
507
  clientId: drag.clientId,
453
- }).finally(() => {
454
- clearDragOverrides(drag.nodePath);
508
+ undoLabel: changes.length > 1 ? 'Move selected sequences' : null,
509
+ redoLabel: changes.length > 1 ? 'Move selected sequences back' : null,
510
+ })
511
+ .catch((err) => {
512
+ (0, NotificationCenter_1.showNotification)(`Could not save sequence props: ${err instanceof Error ? err.message : String(err)}`, 4000);
513
+ })
514
+ .finally(() => {
515
+ clearSelectedOutlineDragOverrides({ clearDragOverrides, dragStates });
455
516
  });
456
517
  };
457
518
  window.addEventListener('pointermove', onPointerMove);
458
519
  window.addEventListener('pointerup', onPointerUp);
459
520
  window.addEventListener('pointercancel', onPointerUp);
460
521
  }, [
522
+ allDragTargets,
461
523
  clearDragOverrides,
462
524
  drag,
463
525
  getDragOverrides,
@@ -611,6 +673,9 @@ const SelectedOutlineOverlay = ({ scale }) => {
611
673
  const targetsByKey = (0, react_1.useMemo)(() => {
612
674
  return new Map(selectedOutlineTargets.map((target) => [target.key, target]));
613
675
  }, [selectedOutlineTargets]);
676
+ const allDragTargets = (0, react_1.useMemo)(() => {
677
+ return selectedOutlineTargets.flatMap((target) => target.drag === null ? [] : [target.drag]);
678
+ }, [selectedOutlineTargets]);
614
679
  (0, react_1.useEffect)(() => {
615
680
  if (selectedOutlineTargets.length === 0) {
616
681
  setOutlines((prevOutlines) => prevOutlines.length === 0 ? prevOutlines : []);
@@ -639,7 +704,7 @@ const SelectedOutlineOverlay = ({ scale }) => {
639
704
  return (jsx_runtime_1.jsx("svg", { ref: overlayRef, style: outlineContainer, width: "100%", height: "100%", "aria-hidden": "true", children: outlines.map((outline) => {
640
705
  var _a;
641
706
  return (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [
642
- jsx_runtime_1.jsx(SelectedOutlinePolygon, { outline: outline, scale: scale, target: targetsByKey.get(outline.key) }), (_a = targetsByKey.get(outline.key)) === null || _a === void 0 ? void 0 : _a.uvHandles.map((handle) => (jsx_runtime_1.jsx(SelectedUvHandleCircle, { handle: handle, outline: outline }, `${handle.effectIndex}-${handle.fieldKey}`)))] }, outline.key));
707
+ jsx_runtime_1.jsx(SelectedOutlinePolygon, { allDragTargets: allDragTargets, outline: outline, scale: scale, target: targetsByKey.get(outline.key) }), (_a = targetsByKey.get(outline.key)) === null || _a === void 0 ? void 0 : _a.uvHandles.map((handle) => (jsx_runtime_1.jsx(SelectedUvHandleCircle, { handle: handle, outline: outline }, `${handle.effectIndex}-${handle.fieldKey}`)))] }, outline.key));
643
708
  }) }));
644
709
  };
645
710
  exports.SelectedOutlineOverlay = SelectedOutlineOverlay;
@@ -41,7 +41,11 @@ const calculate_timeline_1 = require("../../helpers/calculate-timeline");
41
41
  const client_id_1 = require("../../helpers/client-id");
42
42
  const colors_1 = require("../../helpers/colors");
43
43
  const is_current_selected_still_1 = require("../../helpers/is-current-selected-still");
44
+ const open_in_editor_1 = require("../../helpers/open-in-editor");
45
+ const call_api_1 = require("../call-api");
46
+ const ContextMenu_1 = require("../ContextMenu");
44
47
  const is_menu_item_1 = require("../Menu/is-menu-item");
48
+ const NotificationCenter_1 = require("../Notifications/NotificationCenter");
45
49
  const SplitterContainer_1 = require("../Splitter/SplitterContainer");
46
50
  const SplitterElement_1 = require("../Splitter/SplitterElement");
47
51
  const SplitterHandle_1 = require("../Splitter/SplitterHandle");
@@ -63,6 +67,7 @@ const TimelineSlider_1 = require("./TimelineSlider");
63
67
  const TimelineTimeIndicators_1 = require("./TimelineTimeIndicators");
64
68
  const TimelineTracks_1 = require("./TimelineTracks");
65
69
  const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
70
+ const use_resolved_stack_1 = require("./use-resolved-stack");
66
71
  const container = {
67
72
  minHeight: '100%',
68
73
  flex: 1,
@@ -73,7 +78,25 @@ const container = {
73
78
  };
74
79
  const noop = () => undefined;
75
80
  const TimelineClearSelectionArea = ({ children }) => {
81
+ var _a, _b;
76
82
  const { clearSelection } = (0, TimelineSelection_1.useTimelineSelection)();
83
+ const { compositions, canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
84
+ const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
85
+ const [isAddingSolid, setIsAddingSolid] = (0, react_1.useState)(false);
86
+ const currentCompositionId = (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition' ? canvasContent.compositionId : null;
87
+ const currentComposition = (0, react_1.useMemo)(() => {
88
+ var _a;
89
+ if (currentCompositionId === null) {
90
+ return null;
91
+ }
92
+ return ((_a = compositions.find((composition) => composition.id === currentCompositionId)) !== null && _a !== void 0 ? _a : null);
93
+ }, [compositions, currentCompositionId]);
94
+ const resolvedCompositionLocation = (0, use_resolved_stack_1.useResolvedStack)((_a = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _a !== void 0 ? _a : null);
95
+ const compositionFile = (_b = resolvedCompositionLocation === null || resolvedCompositionLocation === void 0 ? void 0 : resolvedCompositionLocation.source) !== null && _b !== void 0 ? _b : null;
96
+ const compositionComponentInfo = (0, open_in_editor_1.useCachedCompositionComponentInfo)({
97
+ compositionFile,
98
+ compositionId: currentCompositionId,
99
+ });
77
100
  // Selection-triggering click handlers in children call e.stopPropagation(),
78
101
  // so any pointerdown that bubbles up here is by definition on empty space
79
102
  // and should clear the current selection.
@@ -83,7 +106,59 @@ const TimelineClearSelectionArea = ({ children }) => {
83
106
  }
84
107
  clearSelection();
85
108
  }, [clearSelection]);
86
- return (jsx_runtime_1.jsx("div", { ref: timeline_refs_1.timelineVerticalScroll, style: container, className: 'css-reset ' + is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, onPointerDown: onPointerDown, children: children }));
109
+ const canInsertSolid = (compositionComponentInfo === null || compositionComponentInfo === void 0 ? void 0 : compositionComponentInfo.canAddSequence) === true &&
110
+ currentCompositionId !== null &&
111
+ compositionFile !== null &&
112
+ videoConfig !== null &&
113
+ !isAddingSolid;
114
+ const insertSolid = (0, react_1.useCallback)(async () => {
115
+ if (!canInsertSolid ||
116
+ currentCompositionId === null ||
117
+ compositionFile === null ||
118
+ videoConfig === null) {
119
+ return;
120
+ }
121
+ setIsAddingSolid(true);
122
+ try {
123
+ const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
124
+ compositionFile,
125
+ compositionId: currentCompositionId,
126
+ element: {
127
+ type: 'solid',
128
+ width: videoConfig.width,
129
+ height: videoConfig.height,
130
+ },
131
+ });
132
+ if (result.success) {
133
+ (0, NotificationCenter_1.showNotification)('Added <Solid> to source file', 2000);
134
+ return;
135
+ }
136
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
137
+ }
138
+ catch (err) {
139
+ (0, NotificationCenter_1.showNotification)(err.message, 4000);
140
+ }
141
+ finally {
142
+ setIsAddingSolid(false);
143
+ }
144
+ }, [canInsertSolid, compositionFile, currentCompositionId, videoConfig]);
145
+ const contextMenuItems = (0, react_1.useMemo)(() => {
146
+ return [
147
+ {
148
+ type: 'item',
149
+ id: 'insert-solid',
150
+ label: 'Add <Solid>',
151
+ value: 'insert-solid',
152
+ onClick: insertSolid,
153
+ keyHint: null,
154
+ leftItem: null,
155
+ subMenu: null,
156
+ quickSwitcherLabel: null,
157
+ disabled: !canInsertSolid,
158
+ },
159
+ ];
160
+ }, [insertSolid, canInsertSolid]);
161
+ return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { ref: timeline_refs_1.timelineVerticalScroll, values: contextMenuItems, onOpen: null, style: container, className: 'css-reset ' + is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, onPointerDown: onPointerDown, children: children }));
87
162
  };
88
163
  const TimelineInner = () => {
89
164
  var _a;
@@ -7,12 +7,14 @@ const client_id_1 = require("../../helpers/client-id");
7
7
  const use_keybinding_1 = require("../../helpers/use-keybinding");
8
8
  const delete_selected_timeline_item_1 = require("./delete-selected-timeline-item");
9
9
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
10
+ const reset_selected_timeline_props_1 = require("./reset-selected-timeline-props");
10
11
  const TimelineSelection_1 = require("./TimelineSelection");
11
12
  const TimelineDeleteKeybindings = () => {
12
13
  const keybindings = (0, use_keybinding_1.useKeybinding)();
13
14
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
14
15
  const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
15
16
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
17
+ const { codeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeCodeValuesContext);
16
18
  const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
17
19
  const { canSelect } = (0, TimelineSelection_1.useTimelineSelection)();
18
20
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
@@ -29,6 +31,18 @@ const TimelineDeleteKeybindings = () => {
29
31
  if (selectedItems.length === 0) {
30
32
  return;
31
33
  }
34
+ const resetPromise = (0, reset_selected_timeline_props_1.resetSelectedTimelineProps)({
35
+ selections: selectedItems,
36
+ sequences,
37
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
38
+ codeValues,
39
+ setCodeValues,
40
+ clientId,
41
+ });
42
+ if (resetPromise !== null) {
43
+ resetPromise.catch(() => undefined);
44
+ return;
45
+ }
32
46
  const deletePromise = (0, delete_selected_timeline_item_1.deleteSelectedTimelineItems)({
33
47
  selections: selectedItems,
34
48
  sequences,
@@ -74,6 +88,7 @@ const TimelineDeleteKeybindings = () => {
74
88
  };
75
89
  }, [
76
90
  canSelect,
91
+ codeValues,
77
92
  currentSelection,
78
93
  keybindings,
79
94
  overrideIdToNodePathMappings,
@@ -125,6 +125,7 @@ const TimelineDragHandlerInner = () => {
125
125
  if (!videoConfig) {
126
126
  return;
127
127
  }
128
+ e.stopPropagation();
128
129
  document.body.style.userSelect = 'none';
129
130
  document.body.style.webkitUserSelect = 'none';
130
131
  const frame = (0, timeline_scroll_logic_1.getFrameFromX)({