@remotion/studio 4.0.474 → 4.0.475

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 (73) hide show
  1. package/dist/components/Canvas.js +6 -0
  2. package/dist/components/ColorPicker/ColorPicker.js +4 -31
  3. package/dist/components/CompositionSelectorItem.js +4 -4
  4. package/dist/components/Editor.js +4 -1
  5. package/dist/components/Modals.js +2 -1
  6. package/dist/components/NewComposition/ComboBox.js +1 -0
  7. package/dist/components/PreviewToolbar.js +2 -2
  8. package/dist/components/SelectedOutlineOverlay.d.ts +58 -32
  9. package/dist/components/SelectedOutlineOverlay.js +766 -315
  10. package/dist/components/SelectedOutlineUvControls.d.ts +17 -0
  11. package/dist/components/SelectedOutlineUvControls.js +167 -0
  12. package/dist/components/StudioCanvasCapture.d.ts +5 -0
  13. package/dist/components/StudioCanvasCapture.js +40 -0
  14. package/dist/components/Timeline/EasingEditorModal.d.ts +11 -0
  15. package/dist/components/Timeline/EasingEditorModal.js +247 -0
  16. package/dist/components/Timeline/KeyframeSettingsModal.js +1 -0
  17. package/dist/components/Timeline/Timeline.js +10 -7
  18. package/dist/components/Timeline/TimelineDeleteKeybindings.js +64 -35
  19. package/dist/components/Timeline/TimelineDragHandler.js +2 -2
  20. package/dist/components/Timeline/TimelineEffectItem.js +1 -2
  21. package/dist/components/Timeline/TimelineEffectPropItem.js +1 -1
  22. package/dist/components/Timeline/TimelineExpandedKeyframeRow.d.ts +1 -0
  23. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +2 -2
  24. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +1 -1
  25. package/dist/components/Timeline/TimelineHeightContainer.js +2 -0
  26. package/dist/components/Timeline/TimelineItemStack.js +3 -56
  27. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +7 -0
  28. package/dist/components/Timeline/TimelineKeyframeControls.js +259 -62
  29. package/dist/components/Timeline/TimelineKeyframeDiamond.js +4 -2
  30. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +128 -3
  31. package/dist/components/Timeline/TimelineKeyframeTracksContext.d.ts +7 -0
  32. package/dist/components/Timeline/TimelineKeyframeTracksContext.js +17 -0
  33. package/dist/components/Timeline/TimelineMediaInfo.js +4 -24
  34. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +4 -0
  35. package/dist/components/Timeline/TimelineRotationField.js +5 -23
  36. package/dist/components/Timeline/TimelineScrollable.js +19 -3
  37. package/dist/components/Timeline/TimelineSelection.d.ts +67 -3
  38. package/dist/components/Timeline/TimelineSelection.js +289 -32
  39. package/dist/components/Timeline/TimelineSequence.js +17 -9
  40. package/dist/components/Timeline/TimelineSequenceItem.js +29 -61
  41. package/dist/components/Timeline/TimelineSequenceName.js +3 -17
  42. package/dist/components/Timeline/TimelineSequencePropItem.js +1 -1
  43. package/dist/components/Timeline/TimelineTimeIndicators.js +4 -2
  44. package/dist/components/Timeline/TimelineTransformOriginField.d.ts +11 -0
  45. package/dist/components/Timeline/TimelineTransformOriginField.js +138 -0
  46. package/dist/components/Timeline/call-add-keyframe.d.ts +17 -0
  47. package/dist/components/Timeline/call-add-keyframe.js +65 -1
  48. package/dist/components/Timeline/delete-selected-timeline-item.js +23 -13
  49. package/dist/components/Timeline/reset-selected-timeline-props.js +13 -5
  50. package/dist/components/Timeline/timeline-rotation-utils.d.ts +2 -0
  51. package/dist/components/Timeline/timeline-rotation-utils.js +32 -0
  52. package/dist/components/Timeline/transform-origin-utils.d.ts +24 -0
  53. package/dist/components/Timeline/transform-origin-utils.js +170 -0
  54. package/dist/components/Timeline/update-selected-easing.d.ts +35 -0
  55. package/dist/components/Timeline/update-selected-easing.js +133 -0
  56. package/dist/components/Timeline/use-expanded-track-keyframe-rows.d.ts +1 -0
  57. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +28 -0
  58. package/dist/components/canvas-capture-enabled.d.ts +1 -0
  59. package/dist/components/canvas-capture-enabled.js +4 -0
  60. package/dist/components/effect-drag-and-drop.d.ts +11 -0
  61. package/dist/components/effect-drag-and-drop.js +73 -0
  62. package/dist/components/selected-outline-geometry.d.ts +20 -0
  63. package/dist/components/selected-outline-geometry.js +18 -0
  64. package/dist/components/selected-outline-uv.d.ts +46 -0
  65. package/dist/components/selected-outline-uv.js +240 -0
  66. package/dist/esm/{chunk-xjvc8qen.js → chunk-qaqqvw4q.js} +7418 -4943
  67. package/dist/esm/internals.mjs +7418 -4943
  68. package/dist/esm/previewEntry.mjs +7426 -4951
  69. package/dist/esm/renderEntry.mjs +1 -1
  70. package/dist/helpers/colors.d.ts +0 -1
  71. package/dist/helpers/colors.js +1 -2
  72. package/dist/state/modals.d.ts +2 -1
  73. package/package.json +11 -10
@@ -2,18 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TimelineSequenceItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const studio_shared_1 = require("@remotion/studio-shared");
6
5
  const react_1 = require("react");
7
6
  const remotion_1 = require("remotion");
8
7
  const no_react_1 = require("remotion/no-react");
9
8
  const client_id_1 = require("../../helpers/client-id");
10
9
  const format_file_location_1 = require("../../helpers/format-file-location");
11
- const install_required_package_1 = require("../../helpers/install-required-package");
12
10
  const timeline_layout_1 = require("../../helpers/timeline-layout");
13
11
  const call_api_1 = require("../call-api");
14
12
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
15
13
  const ContextMenu_1 = require("../ContextMenu");
14
+ const effect_drag_and_drop_1 = require("../effect-drag-and-drop");
16
15
  const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
16
+ const layout_1 = require("../layout");
17
17
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
18
18
  const use_select_asset_1 = require("../use-select-asset");
19
19
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
@@ -34,7 +34,6 @@ const labelContainerStyle = {
34
34
  display: 'flex',
35
35
  flexDirection: 'row',
36
36
  minWidth: 0,
37
- gap: 4,
38
37
  };
39
38
  const effectDropHighlight = {
40
39
  backgroundColor: 'rgba(0, 155, 255, 0.16)',
@@ -103,28 +102,6 @@ const getSequenceReorderDragData = (dataTransfer) => {
103
102
  const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
104
103
  return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
105
104
  };
106
- const hasEffectDragType = (dataTransfer) => {
107
- return Array.from(dataTransfer.types).some((type) => type === studio_shared_1.EFFECT_DRAG_MIME_TYPE ||
108
- type === 'application/json' ||
109
- type === 'text/plain');
110
- };
111
- const getEffectDragData = (dataTransfer) => {
112
- for (const type of [
113
- studio_shared_1.EFFECT_DRAG_MIME_TYPE,
114
- 'application/json',
115
- 'text/plain',
116
- ]) {
117
- const value = dataTransfer.getData(type);
118
- if (!value) {
119
- continue;
120
- }
121
- const parsed = (0, studio_shared_1.parseEffectDragData)(value);
122
- if (parsed) {
123
- return parsed;
124
- }
125
- }
126
- return null;
127
- };
128
105
  const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, trackIndex, }) => {
129
106
  var _a, _b;
130
107
  var _c, _d;
@@ -162,11 +139,10 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
162
139
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
163
140
  const nodePathKey = (0, react_1.useMemo)(() => nodePath ? remotion_1.Internals.makeSequencePropsSubscriptionKey(nodePath) : null, [nodePath]);
164
141
  const parentId = (_d = sequence.parent) !== null && _d !== void 0 ? _d : null;
165
- const canReorderSequence = TimelineSelection_1.SELECTION_ENABLED &&
166
- previewConnected &&
142
+ const canReorderSequence = previewConnected &&
167
143
  Boolean(nodePath && nodePathKey && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) &&
168
144
  (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) === 1;
169
- const canHandleSequenceDrag = TimelineSelection_1.SELECTION_ENABLED && previewConnected;
145
+ const canHandleSequenceDrag = previewConnected;
170
146
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
171
147
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
172
148
  const duplicateDisabled = deleteDisabled;
@@ -519,7 +495,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
519
495
  toggleTrack(nodePathInfo);
520
496
  }, [nodePathInfo, toggleTrack]);
521
497
  const onShowInEditorDoubleClick = (0, react_1.useCallback)((e) => {
522
- if (!TimelineSelection_1.SELECTION_ENABLED || !canOpenInEditor) {
498
+ if (!canOpenInEditor) {
523
499
  return;
524
500
  }
525
501
  if ((0, TimelineSelection_1.isTimelineSelectionModifierEvent)(e)) {
@@ -628,7 +604,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
628
604
  const onEffectDragOver = (0, react_1.useCallback)((e) => {
629
605
  if (!canDropEffect ||
630
606
  isSequenceReorderDrag(e.dataTransfer) ||
631
- !hasEffectDragType(e.dataTransfer)) {
607
+ !(0, effect_drag_and_drop_1.hasEffectDragType)(e.dataTransfer)) {
632
608
  return;
633
609
  }
634
610
  e.preventDefault();
@@ -647,43 +623,35 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
647
623
  nodePath === null ||
648
624
  validatedLocation === null ||
649
625
  isSequenceReorderDrag(e.dataTransfer) ||
650
- !hasEffectDragType(e.dataTransfer)) {
626
+ !(0, effect_drag_and_drop_1.hasEffectDragType)(e.dataTransfer)) {
651
627
  return;
652
628
  }
653
- e.preventDefault();
654
- e.stopPropagation();
655
- setEffectDropHovered(false);
656
- const dragData = getEffectDragData(e.dataTransfer);
629
+ const dragData = (0, effect_drag_and_drop_1.getEffectDragData)(e.dataTransfer);
657
630
  if (!dragData) {
658
- (0, NotificationCenter_1.showNotification)('Could not read effect drag data', 3000);
659
- return;
660
- }
661
- try {
662
- const requiredPackage = (0, studio_shared_1.getRequiredPackageForEffectImportPath)(dragData.effect.importPath);
663
- await (0, install_required_package_1.installRequiredPackages)(requiredPackage ? [requiredPackage] : []);
664
- const result = await (0, call_api_1.callApi)('/api/add-effect', {
665
- fileName: validatedLocation.source,
666
- sequenceNodePath: nodePath,
667
- effectName: dragData.effect.name,
668
- effectImportPath: dragData.effect.importPath,
669
- effectConfig: dragData.effect.config,
670
- clientId: previewServerState.clientId,
671
- });
672
- if (result.success) {
673
- (0, NotificationCenter_1.showNotification)(`Added ${dragData.effect.name}()`, 2000);
631
+ if ((0, effect_drag_and_drop_1.hasExplicitEffectDragType)(e.dataTransfer)) {
632
+ e.preventDefault();
633
+ e.stopPropagation();
634
+ setEffectDropHovered(false);
635
+ (0, NotificationCenter_1.showNotification)('Could not read effect drag data', 3000);
674
636
  }
675
- else {
676
- (0, NotificationCenter_1.showNotification)(result.reason, 4000);
677
- }
678
- }
679
- catch (err) {
680
- (0, NotificationCenter_1.showNotification)(err.message, 4000);
637
+ return;
681
638
  }
639
+ e.preventDefault();
640
+ e.stopPropagation();
641
+ setEffectDropHovered(false);
642
+ await (0, effect_drag_and_drop_1.addEffectFromDragData)({
643
+ dragData,
644
+ fileName: validatedLocation.source,
645
+ nodePath,
646
+ clientId: previewServerState.clientId,
647
+ });
682
648
  }, [canDropEffect, nodePath, previewServerState, validatedLocation]);
683
- const trackRow = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: nestedDepth, eye: canToggleVisibility ? (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEye, { type: sequence.type === 'audio' ? 'speaker' : 'eye', hidden: isItemHidden, onInvoked: onToggleVisibility })) : (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {})), arrow: hasExpandableContent ? (jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowButton, { isExpanded: isExpanded, onClick: onToggleExpand, label: "track properties", disabled: !previewConnected || nodePathInfo === null })) : (jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {})), style: rowStyle, selected: selected, selectable: selectable, onSelect: onSelect, showSelectedBackground: true, containsSelection: containsSelection, outerHeight: outerHeight, onDragLeave: canDropEffect ? onEffectDragLeave : undefined, onDragOver: canDropEffect ? onEffectDragOver : undefined, onDrop: canDropEffect ? onEffectDrop : undefined, onDoubleClick: TimelineSelection_1.SELECTION_ENABLED && canOpenInEditor
684
- ? onShowInEditorDoubleClick
685
- : undefined, children: jsx_runtime_1.jsxs("div", { style: labelContainerStyle, children: [
686
- jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { sequence: sequence, selected: selected, containsSelection: containsSelection }), mediaSrc ? jsx_runtime_1.jsx(TimelineMediaInfo_1.TimelineMediaInfo, { src: mediaSrc }) : null, jsx_runtime_1.jsx(TimelineItemStack_1.TimelineItemStack, { originalLocation: originalLocation })
649
+ const trackRow = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: nestedDepth, eye: canToggleVisibility ? (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEye, { type: sequence.type === 'audio' ? 'speaker' : 'eye', hidden: isItemHidden, onInvoked: onToggleVisibility })) : (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {})), arrow: hasExpandableContent ? (jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowButton, { isExpanded: isExpanded, onClick: onToggleExpand, label: "track properties", disabled: !previewConnected || nodePathInfo === null })) : (jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {})), style: rowStyle, selected: selected, selectable: selectable, onSelect: onSelect, showSelectedBackground: true, containsSelection: containsSelection, outerHeight: outerHeight, onDragLeave: canDropEffect ? onEffectDragLeave : undefined, onDragOver: canDropEffect ? onEffectDragOver : undefined, onDrop: canDropEffect ? onEffectDrop : undefined, onDoubleClick: canOpenInEditor ? onShowInEditorDoubleClick : undefined, children: jsx_runtime_1.jsxs("div", { style: labelContainerStyle, children: [
650
+ jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { sequence: sequence, selected: selected, containsSelection: containsSelection }), mediaSrc ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
651
+ jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }),
652
+ " ",
653
+ jsx_runtime_1.jsx(TimelineMediaInfo_1.TimelineMediaInfo, { src: mediaSrc })
654
+ ] })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(TimelineItemStack_1.TimelineItemStack, { originalLocation: originalLocation })
687
655
  ] }) }));
688
656
  const draggableTrackRow = canHandleSequenceDrag ? (jsx_runtime_1.jsxs("div", { draggable: canReorderSequence, onDragStart: onSequenceDragStart, onDragEnd: onSequenceDragEnd, onDragOver: onSequenceDragOver, onDragLeave: onSequenceDragLeave, onDrop: onSequenceDrop, style: sequenceReorderWrapper, children: [sequenceReorderLineStyle ? (jsx_runtime_1.jsx("div", { style: sequenceReorderLineStyle })) : null, sequenceDropRejection ? (jsx_runtime_1.jsx("div", { style: sequenceReorderRejectionStyle, children: sequenceDropRejection })) : null, trackRow] })) : (trackRow);
689
657
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [previewConnected ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selectable ? onSelect : null, children: draggableTrackRow })) : (draggableTrackRow), previewConnected &&
@@ -12,19 +12,7 @@ const getTruncatedDisplayName = (displayName) => {
12
12
  return displayName;
13
13
  };
14
14
  const TimelineSequenceName = ({ sequence, selected, containsSelection }) => {
15
- const [hovered, setHovered] = (0, react_1.useState)(false);
16
- const { documentationLink } = sequence;
17
- const hoverable = !TimelineSelection_1.SELECTION_ENABLED && documentationLink !== null;
18
- const onClick = (0, react_1.useCallback)(() => {
19
- if (documentationLink === null) {
20
- return;
21
- }
22
- window.open(documentationLink, '_blank', 'noopener,noreferrer');
23
- }, [documentationLink]);
24
- const onPointerEnter = (0, react_1.useCallback)(() => setHovered(true), []);
25
- const onPointerLeave = (0, react_1.useCallback)(() => setHovered(false), []);
26
15
  const style = (0, react_1.useMemo)(() => {
27
- const hoverEffect = hovered && hoverable;
28
16
  return {
29
17
  alignItems: 'center',
30
18
  alignSelf: 'stretch',
@@ -33,18 +21,16 @@ const TimelineSequenceName = ({ sequence, selected, containsSelection }) => {
33
21
  fontSize: 12,
34
22
  whiteSpace: 'nowrap',
35
23
  textOverflow: 'ellipsis',
36
- overflow: 'hidden',
37
24
  color: (0, TimelineSelection_1.getTimelineColor)(selected, false),
38
25
  userSelect: 'none',
39
26
  WebkitUserSelect: 'none',
40
- textDecoration: hoverEffect ? 'underline' : 'none',
41
- cursor: hoverEffect ? 'pointer' : undefined,
27
+ textDecoration: 'none',
42
28
  boxShadow: containsSelection && !selected
43
29
  ? `inset 0 0 0 2px ${TimelineSelection_1.TIMELINE_SELECTED_LABEL_BACKGROUND}`
44
30
  : undefined,
45
31
  };
46
- }, [hovered, hoverable, selected, containsSelection]);
32
+ }, [selected, containsSelection]);
47
33
  const text = getTruncatedDisplayName(sequence.displayName) || '<Sequence>';
48
- return (jsx_runtime_1.jsx("div", { onPointerEnter: hoverable ? onPointerEnter : undefined, onPointerLeave: hoverable ? onPointerLeave : undefined, title: documentationLink ? `Open documentation: ${documentationLink}` : text, style: style, onClick: hoverable ? onClick : undefined, children: text }));
34
+ return (jsx_runtime_1.jsx("div", { title: text, style: style, children: text }));
49
35
  };
50
36
  exports.TimelineSequenceName = TimelineSequenceName;
@@ -142,7 +142,7 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
142
142
  schema,
143
143
  key: field.key,
144
144
  }),
145
- }) ? (jsx_runtime_1.jsx(TimelineKeyframeControls_1.TimelineKeyframeControls, { fieldKey: field.key, propStatus: propStatus, nodePath: nodePath, fileName: validatedLocation.source, keyframeDisplayOffset: keyframeDisplayOffset, defaultValue: field.fieldSchema.default, dragOverrideValue: dragOverrideValue, schema: schema, effectIndex: null })) : null;
145
+ }) ? (jsx_runtime_1.jsx(TimelineKeyframeControls_1.TimelineKeyframeControls, { fieldKey: field.key, propStatus: propStatus, nodePath: nodePath, fileName: validatedLocation.source, keyframeDisplayOffset: keyframeDisplayOffset, defaultValue: field.fieldSchema.default, dragOverrideValue: dragOverrideValue, schema: schema, effectIndex: null, nodePathInfo: nodePathInfo })) : null;
146
146
  const style = (0, react_1.useMemo)(() => {
147
147
  return {
148
148
  ...fieldRowBase,
@@ -10,13 +10,15 @@ const render_frame_1 = require("../../state/render-frame");
10
10
  const TimeValue_1 = require("../TimeValue");
11
11
  const timeline_refs_1 = require("./timeline-refs");
12
12
  const timeline_scroll_logic_1 = require("./timeline-scroll-logic");
13
+ const TimelineSelection_1 = require("./TimelineSelection");
13
14
  const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
14
15
  exports.TIMELINE_TIME_INDICATOR_HEIGHT = 39;
15
16
  const container = {
16
17
  height: exports.TIMELINE_TIME_INDICATOR_HEIGHT,
17
18
  position: 'absolute',
18
- backgroundColor: colors_1.TIMELINE_BACKGROUND,
19
+ backgroundColor: TimelineSelection_1.TIMELINE_TICKS_BACKGROUND,
19
20
  top: 0,
21
+ borderBottom: `${timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM}px solid ${colors_1.TIMELINE_TRACK_SEPARATOR}`,
20
22
  };
21
23
  const tick = {
22
24
  width: 1,
@@ -41,7 +43,7 @@ const timeValue = {
41
43
  height: exports.TIMELINE_TIME_INDICATOR_HEIGHT,
42
44
  position: 'absolute',
43
45
  top: 0,
44
- width: '100%',
46
+ width: 'calc(100% + 1.5px)',
45
47
  paddingLeft: 10,
46
48
  display: 'flex',
47
49
  alignItems: 'center',
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { CanUpdateSequencePropStatusStatic } from 'remotion';
3
+ import type { SchemaFieldInfo, TimelineFieldOnDragValueChange, TimelineFieldOnSave } from '../../helpers/timeline-layout';
4
+ export declare const TimelineTransformOriginField: React.FC<{
5
+ readonly field: SchemaFieldInfo;
6
+ readonly propStatus: CanUpdateSequencePropStatusStatic;
7
+ readonly effectiveValue: unknown;
8
+ readonly onSave: TimelineFieldOnSave;
9
+ readonly onDragValueChange: TimelineFieldOnDragValueChange;
10
+ readonly onDragEnd: () => void;
11
+ }>;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineTransformOriginField = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const InputDragger_1 = require("../NewComposition/InputDragger");
7
+ const timeline_field_utils_1 = require("./timeline-field-utils");
8
+ const TimelineSchemaField_1 = require("./TimelineSchemaField");
9
+ const transform_origin_utils_1 = require("./transform-origin-utils");
10
+ const leftDraggerStyle = {
11
+ paddingLeft: 0,
12
+ };
13
+ const rightDraggerStyle = {
14
+ paddingRight: 0,
15
+ };
16
+ const containerStyle = {
17
+ display: 'flex',
18
+ gap: 4,
19
+ };
20
+ const TimelineTransformOriginField = ({ field, propStatus, effectiveValue, onSave, onDragValueChange, onDragEnd, }) => {
21
+ const [dragX, setDragX] = (0, react_1.useState)(null);
22
+ const [dragY, setDragY] = (0, react_1.useState)(null);
23
+ const parsed = (0, react_1.useMemo)(() => (0, transform_origin_utils_1.parseTransformOrigin)(effectiveValue), [effectiveValue]);
24
+ const percent = (0, react_1.useMemo)(() => (parsed === null ? null : (0, transform_origin_utils_1.parsedTransformOriginToPercent)(parsed)), [parsed]);
25
+ const configuredStep = field.fieldSchema.type === 'transform-origin'
26
+ ? field.fieldSchema.step
27
+ : undefined;
28
+ const step = configuredStep !== null && configuredStep !== void 0 ? configuredStep : 1;
29
+ const decimalPlaces = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getTimelineDisplayDecimalPlaces)({
30
+ defaultDecimalPlaces: 2,
31
+ step: configuredStep,
32
+ }), [configuredStep]);
33
+ const formatter = (0, react_1.useCallback)((v) => {
34
+ const formatted = (0, timeline_field_utils_1.formatTimelineNumber)({
35
+ decimalPlaces,
36
+ fixed: false,
37
+ value: v,
38
+ });
39
+ return `${formatted}%`;
40
+ }, [decimalPlaces]);
41
+ const serialize = (0, react_1.useCallback)((x, y) => {
42
+ var _a;
43
+ return (0, transform_origin_utils_1.serializeTransformOrigin)({
44
+ uv: (0, transform_origin_utils_1.transformOriginPercentToUv)([x, y]),
45
+ z: (_a = parsed === null || parsed === void 0 ? void 0 : parsed.z) !== null && _a !== void 0 ? _a : null,
46
+ decimalPlaces,
47
+ });
48
+ }, [decimalPlaces, parsed === null || parsed === void 0 ? void 0 : parsed.z]);
49
+ const onXChange = (0, react_1.useCallback)((newVal) => {
50
+ if (percent === null) {
51
+ return;
52
+ }
53
+ setDragX(newVal);
54
+ const currentY = dragY !== null && dragY !== void 0 ? dragY : percent[1];
55
+ onDragValueChange(serialize(newVal, currentY));
56
+ }, [dragY, onDragValueChange, percent, serialize]);
57
+ const onXChangeEnd = (0, react_1.useCallback)((newVal) => {
58
+ if (percent === null) {
59
+ return;
60
+ }
61
+ const currentY = dragY !== null && dragY !== void 0 ? dragY : percent[1];
62
+ const value = serialize(newVal, currentY);
63
+ if (value !== propStatus.codeValue) {
64
+ onSave(value).finally(() => {
65
+ setDragX(null);
66
+ onDragEnd();
67
+ });
68
+ }
69
+ else {
70
+ setDragX(null);
71
+ onDragEnd();
72
+ }
73
+ }, [dragY, onDragEnd, onSave, percent, propStatus.codeValue, serialize]);
74
+ const onXTextChange = (0, react_1.useCallback)((newVal) => {
75
+ if (percent === null) {
76
+ return;
77
+ }
78
+ const parsedValue = Number(newVal);
79
+ if (!Number.isNaN(parsedValue)) {
80
+ const currentY = dragY !== null && dragY !== void 0 ? dragY : percent[1];
81
+ const value = serialize(parsedValue, currentY);
82
+ if (value !== propStatus.codeValue) {
83
+ setDragX(parsedValue);
84
+ onSave(value).finally(() => {
85
+ setDragX(null);
86
+ });
87
+ }
88
+ }
89
+ }, [dragY, onSave, percent, propStatus.codeValue, serialize]);
90
+ const onYChange = (0, react_1.useCallback)((newVal) => {
91
+ if (percent === null) {
92
+ return;
93
+ }
94
+ setDragY(newVal);
95
+ const currentX = dragX !== null && dragX !== void 0 ? dragX : percent[0];
96
+ onDragValueChange(serialize(currentX, newVal));
97
+ }, [dragX, onDragValueChange, percent, serialize]);
98
+ const onYChangeEnd = (0, react_1.useCallback)((newVal) => {
99
+ if (percent === null) {
100
+ return;
101
+ }
102
+ const currentX = dragX !== null && dragX !== void 0 ? dragX : percent[0];
103
+ const value = serialize(currentX, newVal);
104
+ if (value !== propStatus.codeValue) {
105
+ onSave(value).finally(() => {
106
+ setDragY(null);
107
+ onDragEnd();
108
+ });
109
+ }
110
+ else {
111
+ setDragY(null);
112
+ onDragEnd();
113
+ }
114
+ }, [dragX, onDragEnd, onSave, percent, propStatus.codeValue, serialize]);
115
+ const onYTextChange = (0, react_1.useCallback)((newVal) => {
116
+ if (percent === null) {
117
+ return;
118
+ }
119
+ const parsedValue = Number(newVal);
120
+ if (!Number.isNaN(parsedValue)) {
121
+ const currentX = dragX !== null && dragX !== void 0 ? dragX : percent[0];
122
+ const value = serialize(currentX, parsedValue);
123
+ if (value !== propStatus.codeValue) {
124
+ setDragY(parsedValue);
125
+ onSave(value).finally(() => {
126
+ setDragY(null);
127
+ });
128
+ }
129
+ }
130
+ }, [dragX, onSave, percent, propStatus.codeValue, serialize]);
131
+ if (percent === null) {
132
+ return jsx_runtime_1.jsx(TimelineSchemaField_1.UnsupportedStatus, { label: "unsupported origin" });
133
+ }
134
+ return (jsx_runtime_1.jsxs("span", { style: containerStyle, children: [
135
+ jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : percent[0], style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false, snapToStep: false }), jsx_runtime_1.jsx("div", { style: { marginLeft: -6, marginRight: -6 } }), jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragY !== null && dragY !== void 0 ? dragY : percent[1], style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false, snapToStep: false })
136
+ ] }));
137
+ };
138
+ exports.TimelineTransformOriginField = TimelineTransformOriginField;
@@ -1,5 +1,16 @@
1
1
  import type { SequencePropsSubscriptionKey, SequenceSchema } from 'remotion';
2
2
  import type { SetPropStatuses } from './save-sequence-prop';
3
+ export type AddSequenceKeyframeChange = {
4
+ fileName: string;
5
+ nodePath: SequencePropsSubscriptionKey;
6
+ fieldKey: string;
7
+ sourceFrame: number;
8
+ value: unknown;
9
+ schema: SequenceSchema;
10
+ };
11
+ export type AddEffectKeyframeChange = AddSequenceKeyframeChange & {
12
+ effectIndex: number;
13
+ };
3
14
  export declare const callAddSequenceKeyframe: ({ fileName, nodePath, fieldKey, sourceFrame, value, schema, setPropStatuses, clientId, }: {
4
15
  fileName: string;
5
16
  nodePath: SequencePropsSubscriptionKey;
@@ -10,6 +21,12 @@ export declare const callAddSequenceKeyframe: ({ fileName, nodePath, fieldKey, s
10
21
  setPropStatuses: SetPropStatuses;
11
22
  clientId: string;
12
23
  }) => Promise<void>;
24
+ export declare const callAddKeyframes: ({ sequenceKeyframes, effectKeyframes, setPropStatuses, clientId, }: {
25
+ sequenceKeyframes: AddSequenceKeyframeChange[];
26
+ effectKeyframes: AddEffectKeyframeChange[];
27
+ setPropStatuses: SetPropStatuses;
28
+ clientId: string;
29
+ }) => Promise<void>;
13
30
  export declare const callAddEffectKeyframe: ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, value, schema, setPropStatuses, clientId, }: {
14
31
  fileName: string;
15
32
  nodePath: SequencePropsSubscriptionKey;
@@ -1,10 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.callAddEffectKeyframe = exports.callAddSequenceKeyframe = void 0;
3
+ exports.callAddEffectKeyframe = exports.callAddKeyframes = exports.callAddSequenceKeyframe = void 0;
4
4
  const studio_shared_1 = require("@remotion/studio-shared");
5
5
  const call_api_1 = require("../call-api");
6
6
  const apply_effect_response_to_prop_statuses_1 = require("./apply-effect-response-to-prop-statuses");
7
7
  const save_prop_queue_1 = require("./save-prop-queue");
8
+ const groupByNodePath = (keyframes) => {
9
+ var _a;
10
+ const groups = new Map();
11
+ for (const keyframe of keyframes) {
12
+ const key = JSON.stringify(keyframe.nodePath);
13
+ const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : [];
14
+ group.push(keyframe);
15
+ groups.set(key, group);
16
+ }
17
+ return [...groups.values()];
18
+ };
8
19
  const callAddSequenceKeyframe = ({ fileName, nodePath, fieldKey, sourceFrame, value, schema, setPropStatuses, clientId, }) => {
9
20
  return (0, save_prop_queue_1.enqueueSavePropChange)({
10
21
  nodePath,
@@ -29,6 +40,59 @@ const callAddSequenceKeyframe = ({ fileName, nodePath, fieldKey, sourceFrame, va
29
40
  });
30
41
  };
31
42
  exports.callAddSequenceKeyframe = callAddSequenceKeyframe;
43
+ const callAddKeyframes = ({ sequenceKeyframes, effectKeyframes, setPropStatuses, clientId, }) => {
44
+ if (sequenceKeyframes.length === 0 && effectKeyframes.length === 0) {
45
+ return Promise.resolve();
46
+ }
47
+ for (const keyframes of groupByNodePath(sequenceKeyframes)) {
48
+ const [firstKeyframe] = keyframes;
49
+ if (!firstKeyframe) {
50
+ continue;
51
+ }
52
+ setPropStatuses(firstKeyframe.nodePath, (prev) => keyframes.reduce((current, keyframe) => (0, studio_shared_1.optimisticAddSequenceKeyframe)({
53
+ previous: current,
54
+ fieldKey: keyframe.fieldKey,
55
+ frame: keyframe.sourceFrame,
56
+ value: keyframe.value,
57
+ schema: keyframe.schema,
58
+ }), prev));
59
+ }
60
+ for (const keyframes of groupByNodePath(effectKeyframes)) {
61
+ const [firstKeyframe] = keyframes;
62
+ if (!firstKeyframe) {
63
+ continue;
64
+ }
65
+ setPropStatuses(firstKeyframe.nodePath, (prev) => keyframes.reduce((current, keyframe) => (0, studio_shared_1.optimisticAddEffectKeyframe)({
66
+ previous: current,
67
+ effectIndex: keyframe.effectIndex,
68
+ fieldKey: keyframe.fieldKey,
69
+ frame: keyframe.sourceFrame,
70
+ value: keyframe.value,
71
+ schema: keyframe.schema,
72
+ }), prev));
73
+ }
74
+ return (0, call_api_1.callApi)('/api/add-keyframes', {
75
+ sequenceKeyframes: sequenceKeyframes.map((keyframe) => ({
76
+ fileName: keyframe.fileName,
77
+ nodePath: keyframe.nodePath,
78
+ key: keyframe.fieldKey,
79
+ frame: keyframe.sourceFrame,
80
+ value: JSON.stringify(keyframe.value),
81
+ schema: keyframe.schema,
82
+ })),
83
+ effectKeyframes: effectKeyframes.map((keyframe) => ({
84
+ fileName: keyframe.fileName,
85
+ sequenceNodePath: keyframe.nodePath,
86
+ effectIndex: keyframe.effectIndex,
87
+ key: keyframe.fieldKey,
88
+ frame: keyframe.sourceFrame,
89
+ value: JSON.stringify(keyframe.value),
90
+ schema: keyframe.schema,
91
+ })),
92
+ clientId,
93
+ }).then(() => undefined);
94
+ };
95
+ exports.callAddKeyframes = callAddKeyframes;
32
96
  const callAddEffectKeyframe = ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, value, schema, setPropStatuses, clientId, }) => {
33
97
  return (0, save_prop_queue_1.enqueueSavePropChange)({
34
98
  nodePath,
@@ -134,6 +134,7 @@ const isSequenceRowSelection = (selection) => selection.type === 'sequence';
134
134
  const isSequenceEffectSelection = (selection) => selection.type === 'sequence-effect';
135
135
  const isSequenceAllEffectsSelection = (selection) => selection.type === 'sequence-all-effects';
136
136
  const isKeyframeSelection = (selection) => selection.type === 'keyframe';
137
+ const areSelectionsOnlyOfType = (selections, type) => selections.every((selection) => selection.type === type);
137
138
  const assertTimelineSelectionsHaveSameType = (selections) => {
138
139
  const firstSelection = selections[0];
139
140
  if (!firstSelection) {
@@ -145,12 +146,33 @@ const assertTimelineSelectionsHaveSameType = (selections) => {
145
146
  }
146
147
  }
147
148
  };
149
+ const containsOnlyKeyframesAndEasings = (selections) => selections.every((selection) => selection.type === 'keyframe' || selection.type === 'easing');
148
150
  const deleteSelectedTimelineItems = ({ selections, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }) => {
149
151
  var _a;
150
152
  const firstSelection = selections[0];
151
153
  if (!firstSelection) {
152
154
  return null;
153
155
  }
156
+ if (containsOnlyKeyframesAndEasings(selections)) {
157
+ const keyframes = selections.filter(isKeyframeSelection);
158
+ if (keyframes.length === 0) {
159
+ return null;
160
+ }
161
+ const promise = (0, delete_selected_keyframe_1.deleteSelectedKeyframes)({
162
+ keyframes: keyframes.map((selection) => ({
163
+ nodePathInfo: selection.nodePathInfo,
164
+ frame: selection.frame,
165
+ })),
166
+ sequences,
167
+ overrideIdsToNodePaths,
168
+ setPropStatuses,
169
+ clientId,
170
+ });
171
+ return (_a = promise === null || promise === void 0 ? void 0 : promise.then(() => true)) !== null && _a !== void 0 ? _a : null;
172
+ }
173
+ if (!areSelectionsOnlyOfType(selections, firstSelection.type)) {
174
+ return null;
175
+ }
154
176
  assertTimelineSelectionsHaveSameType(selections);
155
177
  switch (firstSelection.type) {
156
178
  case 'sequence':
@@ -163,19 +185,7 @@ const deleteSelectedTimelineItems = ({ selections, sequences, overrideIdsToNodeP
163
185
  nodePathInfo: selection.nodePathInfo,
164
186
  effectIndex: selection.i,
165
187
  })));
166
- case 'keyframe': {
167
- const promise = (0, delete_selected_keyframe_1.deleteSelectedKeyframes)({
168
- keyframes: selections.filter(isKeyframeSelection).map((selection) => ({
169
- nodePathInfo: selection.nodePathInfo,
170
- frame: selection.frame,
171
- })),
172
- sequences,
173
- overrideIdsToNodePaths,
174
- setPropStatuses,
175
- clientId,
176
- });
177
- return (_a = promise === null || promise === void 0 ? void 0 : promise.then(() => true)) !== null && _a !== void 0 ? _a : null;
178
- }
188
+ case 'keyframe':
179
189
  case 'sequence-prop':
180
190
  case 'sequence-effect-prop':
181
191
  case 'easing':
@@ -7,6 +7,13 @@ const save_effect_prop_1 = require("./save-effect-prop");
7
7
  const save_sequence_prop_1 = require("./save-sequence-prop");
8
8
  const isPropResetSelection = (selection) => selection.type === 'sequence-prop' ||
9
9
  selection.type === 'sequence-effect-prop';
10
+ function assertPropResetSelections(selections) {
11
+ for (const selection of selections) {
12
+ if (!isPropResetSelection(selection)) {
13
+ throw new Error(`Assertion failed: Cannot reset timeline selection of type ${selection.type}`);
14
+ }
15
+ }
16
+ }
10
17
  const isVisibleFieldSchema = (fieldSchema) => fieldSchema !== undefined && fieldSchema.type !== 'hidden';
11
18
  const isNonDefaultCodeValue = ({ propStatus, defaultValue, }) => JSON.stringify(propStatus !== null && propStatus !== void 0 ? propStatus : defaultValue) !== JSON.stringify(defaultValue);
12
19
  const isResettablePropStatus = ({ propStatus, defaultValue, }) => {
@@ -30,15 +37,16 @@ const getDefaultValue = (fieldSchema) => fieldSchema.default !== undefined
30
37
  const getTimelinePropResetTargets = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, }) => {
31
38
  var _a;
32
39
  var _b;
33
- const firstSelection = selections[0];
34
- if (!firstSelection || !isPropResetSelection(firstSelection)) {
40
+ const propSelections = selections.filter(isPropResetSelection);
41
+ if (propSelections.length === 0) {
35
42
  return null;
36
43
  }
44
+ if (propSelections.length !== selections.length) {
45
+ return null;
46
+ }
47
+ assertPropResetSelections(selections);
37
48
  const resetTargets = [];
38
49
  for (const selection of selections) {
39
- if (!isPropResetSelection(selection)) {
40
- throw new Error(`Assertion failed: Cannot reset timeline selections of different types (${firstSelection.type}, ${selection.type})`);
41
- }
42
50
  const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
43
51
  sequences,
44
52
  overrideIdsToNodePaths,
@@ -0,0 +1,2 @@
1
+ export declare const parseCssRotationToDegrees: (value: string) => number;
2
+ export declare const serializeCssRotation: (value: number) => string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeCssRotation = exports.parseCssRotationToDegrees = void 0;
4
+ const timeline_field_utils_1 = require("./timeline-field-utils");
5
+ const unitPattern = /^([+-]?(?:\d+\.?\d*|\.\d+))(deg|rad|turn|grad)$/;
6
+ const unitToDegrees = {
7
+ deg: 1,
8
+ rad: 180 / Math.PI,
9
+ turn: 360,
10
+ grad: 360 / 400,
11
+ };
12
+ const parseCssRotationToDegrees = (value) => {
13
+ const match = value.trim().match(unitPattern);
14
+ if (match) {
15
+ return (0, timeline_field_utils_1.normalizeTimelineNumber)(Number(match[1]) * unitToDegrees[match[2]]);
16
+ }
17
+ if (typeof DOMMatrix === 'undefined') {
18
+ return 0;
19
+ }
20
+ try {
21
+ const m = new DOMMatrix(`rotate(${value})`);
22
+ return (0, timeline_field_utils_1.normalizeTimelineNumber)(Math.atan2(m.b, m.a) * (180 / Math.PI));
23
+ }
24
+ catch (_a) {
25
+ return 0;
26
+ }
27
+ };
28
+ exports.parseCssRotationToDegrees = parseCssRotationToDegrees;
29
+ const serializeCssRotation = (value) => {
30
+ return `${(0, timeline_field_utils_1.normalizeTimelineNumber)(value)}deg`;
31
+ };
32
+ exports.serializeCssRotation = serializeCssRotation;