@remotion/studio 4.0.482 → 4.0.484

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 (77) hide show
  1. package/dist/components/Canvas.js +19 -0
  2. package/dist/components/ColorPicker/ColorPicker.js +65 -3
  3. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +1 -0
  4. package/dist/components/ColorPicker/ColorPickerPopup.js +3 -2
  5. package/dist/components/InspectorPanel/EasingInspector.js +184 -10
  6. package/dist/components/InspectorPanel/KeyframeEasingNavigator.d.ts +14 -0
  7. package/dist/components/InspectorPanel/KeyframeEasingNavigator.js +146 -0
  8. package/dist/components/InspectorPanel/KeyframeInspector.d.ts +1 -1
  9. package/dist/components/InspectorPanel/KeyframeInspector.js +228 -5
  10. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +17 -0
  11. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +93 -0
  12. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -58
  13. package/dist/components/InspectorPanel/common.d.ts +12 -0
  14. package/dist/components/InspectorPanel/common.js +78 -1
  15. package/dist/components/InspectorPanel/easing-inspector-selection.d.ts +14 -0
  16. package/dist/components/InspectorPanel/easing-inspector-selection.js +18 -0
  17. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.d.ts +24 -0
  18. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.js +40 -0
  19. package/dist/components/InspectorPanel/keyframe-inspector-frame.d.ts +8 -0
  20. package/dist/components/InspectorPanel/keyframe-inspector-frame.js +14 -0
  21. package/dist/components/InspectorPanel/styles.d.ts +1 -0
  22. package/dist/components/InspectorPanel/styles.js +9 -1
  23. package/dist/components/InspectorSequenceSection.js +47 -10
  24. package/dist/components/Preview.js +1 -1
  25. package/dist/components/SelectedOutlineOverlay.d.ts +2 -0
  26. package/dist/components/SelectedOutlineOverlay.js +33 -12
  27. package/dist/components/SelectedOutlineUvControls.js +461 -2
  28. package/dist/components/Timeline/EasingEditorModal.js +48 -5
  29. package/dist/components/Timeline/Timeline.js +2 -1
  30. package/dist/components/Timeline/TimelineDeleteKeybindings.js +11 -1
  31. package/dist/components/Timeline/TimelineEffectItem.js +8 -5
  32. package/dist/components/Timeline/TimelineEffectPropItem.js +82 -1
  33. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +2 -2
  34. package/dist/components/Timeline/TimelineKeyframeControls.js +37 -7
  35. package/dist/components/Timeline/TimelineKeyframeEasingLine.d.ts +4 -0
  36. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +12 -6
  37. package/dist/components/Timeline/TimelineKeyframedValue.js +1 -0
  38. package/dist/components/Timeline/TimelineRowChrome.js +6 -4
  39. package/dist/components/Timeline/TimelineSelection.d.ts +7 -1
  40. package/dist/components/Timeline/TimelineSelection.js +19 -3
  41. package/dist/components/Timeline/TimelineSequence.js +20 -8
  42. package/dist/components/Timeline/TimelineSequenceItem.js +64 -28
  43. package/dist/components/Timeline/TimelineSequenceName.d.ts +1 -0
  44. package/dist/components/Timeline/TimelineSequenceName.js +7 -6
  45. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +1 -1
  46. package/dist/components/Timeline/TimelineSequencePropItem.js +80 -1
  47. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +40 -1
  48. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +308 -1
  49. package/dist/components/Timeline/TimelineSlider.js +17 -3
  50. package/dist/components/Timeline/TimelineTrack.js +2 -4
  51. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +8 -2
  52. package/dist/components/Timeline/delete-selected-timeline-item.js +80 -1
  53. package/dist/components/Timeline/get-animation-item-selection-for-frame.d.ts +18 -0
  54. package/dist/components/Timeline/get-animation-item-selection-for-frame.js +49 -0
  55. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.d.ts +15 -0
  56. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +26 -0
  57. package/dist/components/Timeline/save-sequence-prop.js +2 -0
  58. package/dist/components/Timeline/should-subscribe-to-sequence-props.d.ts +4 -0
  59. package/dist/components/Timeline/should-subscribe-to-sequence-props.js +10 -0
  60. package/dist/components/Timeline/update-selected-easing.d.ts +1 -0
  61. package/dist/components/Timeline/update-selected-easing.js +4 -3
  62. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.d.ts +2 -1
  63. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.js +19 -13
  64. package/dist/components/element-drag-and-drop.d.ts +3 -0
  65. package/dist/components/element-drag-and-drop.js +30 -0
  66. package/dist/components/import-assets.d.ts +11 -0
  67. package/dist/components/import-assets.js +23 -1
  68. package/dist/components/selected-outline-uv.d.ts +71 -1
  69. package/dist/components/selected-outline-uv.js +332 -10
  70. package/dist/esm/{chunk-nkqfa5bw.js → chunk-9erwh79m.js} +11896 -9019
  71. package/dist/esm/internals.mjs +11896 -9019
  72. package/dist/esm/previewEntry.mjs +11923 -9046
  73. package/dist/esm/renderEntry.mjs +1 -1
  74. package/dist/helpers/timeline-layout.d.ts +3 -3
  75. package/dist/helpers/timeline-layout.js +3 -1
  76. package/dist/helpers/use-menu-structure.js +0 -14
  77. package/package.json +11 -11
@@ -23,6 +23,7 @@ const EditorGuides_1 = __importDefault(require("./EditorGuides"));
23
23
  const EditorRuler_1 = require("./EditorRuler");
24
24
  const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
25
25
  const effect_drag_and_drop_1 = require("./effect-drag-and-drop");
26
+ const element_drag_and_drop_1 = require("./element-drag-and-drop");
26
27
  const import_assets_1 = require("./import-assets");
27
28
  const layout_1 = require("./layout");
28
29
  const Preview_1 = require("./Preview");
@@ -57,6 +58,11 @@ const isComponentDragEvent = (event) => {
57
58
  var _b;
58
59
  return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.COMPONENT_DRAG_MIME_TYPE);
59
60
  };
61
+ const isElementDragEvent = (event) => {
62
+ var _a;
63
+ var _b;
64
+ return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.ELEMENT_DRAG_MIME_TYPE);
65
+ };
60
66
  const isSfxDragEvent = (event) => {
61
67
  var _a;
62
68
  var _b;
@@ -66,6 +72,7 @@ const isRemoteAssetDragEvent = (event) => {
66
72
  return (!isFileDragEvent(event) &&
67
73
  !isAssetDragEvent(event) &&
68
74
  !isComponentDragEvent(event) &&
75
+ !isElementDragEvent(event) &&
69
76
  !isSfxDragEvent(event) &&
70
77
  (0, remote_asset_drag_1.hasRemoteAssetDragData)(event.dataTransfer));
71
78
  };
@@ -560,6 +567,7 @@ const Canvas = ({ canvasContent, size }) => {
560
567
  (!isFileDragEvent(event) &&
561
568
  !isAssetDragEvent(event) &&
562
569
  !isComponentDragEvent(event) &&
570
+ !isElementDragEvent(event) &&
563
571
  !isSfxDragEvent(event) &&
564
572
  !isRemoteAssetDragEvent(event)) ||
565
573
  !isDragEventInsideCanvas(event)) {
@@ -579,6 +587,7 @@ const Canvas = ({ canvasContent, size }) => {
579
587
  (!isFileDragEvent(event) &&
580
588
  !isAssetDragEvent(event) &&
581
589
  !isComponentDragEvent(event) &&
590
+ !isElementDragEvent(event) &&
582
591
  !isSfxDragEvent(event) &&
583
592
  !isRemoteAssetDragEvent(event)) ||
584
593
  !isDragEventInsideCanvas(event)) {
@@ -636,6 +645,16 @@ const Canvas = ({ canvasContent, size }) => {
636
645
  });
637
646
  }
638
647
  else {
648
+ const elementDragData = (0, element_drag_and_drop_1.getElementDragData)(event.dataTransfer);
649
+ if (elementDragData !== null) {
650
+ await (0, import_assets_1.insertElement)({
651
+ element: elementDragData.element,
652
+ compositionFile,
653
+ compositionId: currentCompositionId,
654
+ dropPosition,
655
+ });
656
+ return;
657
+ }
639
658
  const componentDragData = getComponentDragData(event);
640
659
  if (componentDragData !== null) {
641
660
  await (0, import_assets_1.insertComponent)({
@@ -8,6 +8,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const player_1 = require("@remotion/player");
9
9
  const react_1 = require("react");
10
10
  const react_dom_1 = __importDefault(require("react-dom"));
11
+ const color_conversion_1 = require("../../helpers/color-conversion");
12
+ const colors_1 = require("../../helpers/colors");
13
+ const eyedropper_1 = require("../../icons/eyedropper");
11
14
  const z_index_1 = require("../../state/z-index");
12
15
  const is_menu_item_1 = require("../Menu/is-menu-item");
13
16
  const portals_1 = require("../Menu/portals");
@@ -36,6 +39,23 @@ const fillStyle = {
36
39
  inset: 0,
37
40
  display: 'block',
38
41
  };
42
+ const controlStyle = {
43
+ display: 'inline-flex',
44
+ alignItems: 'center',
45
+ gap: 3,
46
+ flex: '0 0 auto',
47
+ };
48
+ const eyedropperButtonBaseStyle = {
49
+ background: 'transparent',
50
+ border: 'none',
51
+ padding: 0,
52
+ margin: 0,
53
+ color: colors_1.LIGHT_TEXT,
54
+ display: 'inline-flex',
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ flex: '0 0 auto',
58
+ };
39
59
  const ColorPicker = ({ value, onChange, onChangeComplete, disabled, width = 45, height = 25, borderRadius = 3, title, name, className, style: customStyle, }) => {
40
60
  const [opened, setOpened] = (0, react_1.useState)(false);
41
61
  const triggerRef = (0, react_1.useRef)(null);
@@ -65,6 +85,24 @@ const ColorPicker = ({ value, onChange, onChangeComplete, disabled, width = 45,
65
85
  ...(customStyle !== null && customStyle !== void 0 ? customStyle : {}),
66
86
  };
67
87
  }, [borderRadius, customStyle, disabled, height, width]);
88
+ const eyedropperButtonSize = Math.max(15, Math.min(28, height));
89
+ const eyedropperIconSize = Math.max(12, Math.min(18, eyedropperButtonSize - 2));
90
+ const eyedropperButtonStyle = (0, react_1.useMemo)(() => {
91
+ return {
92
+ ...eyedropperButtonBaseStyle,
93
+ width: eyedropperButtonSize,
94
+ height: eyedropperButtonSize,
95
+ cursor: disabled ? 'not-allowed' : 'pointer',
96
+ opacity: disabled ? 0.5 : 1,
97
+ };
98
+ }, [disabled, eyedropperButtonSize]);
99
+ const eyedropperIconStyle = (0, react_1.useMemo)(() => {
100
+ return {
101
+ width: eyedropperIconSize,
102
+ height: eyedropperIconSize,
103
+ pointerEvents: 'none',
104
+ };
105
+ }, [eyedropperIconSize]);
68
106
  // Toggle on pointerdown (matches Combobox) so the state flips before the
69
107
  // HigherZIndex outside-click detection runs on pointerup. If we toggled in
70
108
  // onClick, the popup would close in pointerup and immediately re-open in
@@ -98,6 +136,28 @@ const ColorPicker = ({ value, onChange, onChangeComplete, disabled, width = 45,
98
136
  return !prev;
99
137
  });
100
138
  }, [disabled, refresh]);
139
+ const onPickWithEyeDropper = (0, react_1.useCallback)(() => {
140
+ if (disabled) {
141
+ return;
142
+ }
143
+ const Ctor = window.EyeDropper;
144
+ if (!Ctor) {
145
+ return;
146
+ }
147
+ setOpened(false);
148
+ const dropper = new Ctor();
149
+ dropper
150
+ .open()
151
+ .then((result) => {
152
+ onChangeComplete((0, color_conversion_1.formatRgba)((0, ColorPickerPopup_1.parseEyeDropperColor)(result.sRGBHex)));
153
+ })
154
+ .catch(() => {
155
+ // Aborted; ignore.
156
+ });
157
+ }, [disabled, onChangeComplete]);
158
+ const onEyeDropperPointerDown = (0, react_1.useCallback)((e) => {
159
+ e.stopPropagation();
160
+ }, []);
101
161
  const portalStyle = (0, react_1.useMemo)(() => {
102
162
  if (!opened || !size) {
103
163
  return null;
@@ -139,10 +199,12 @@ const ColorPicker = ({ value, onChange, onChangeComplete, disabled, width = 45,
139
199
  window.addEventListener('blur', onWindowBlur);
140
200
  return () => window.removeEventListener('blur', onWindowBlur);
141
201
  }, [opened]);
202
+ const showEyeDropper = (0, ColorPickerPopup_1.hasEyeDropper)();
142
203
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
143
- jsx_runtime_1.jsx("button", { ref: triggerRef, type: "button", className: [is_menu_item_1.MENU_INITIATOR_CLASSNAME, SWATCH_CLASSNAME, className]
144
- .filter(Boolean)
145
- .join(' '), disabled: disabled, name: name, title: title !== null && title !== void 0 ? title : value, tabIndex: tabIndex, style: swatchStyle, onPointerDown: onTriggerPointerDown, onClick: onTriggerClick, children: jsx_runtime_1.jsx("span", { style: swatchFill }) }), portalStyle
204
+ jsx_runtime_1.jsxs("span", { style: controlStyle, children: [
205
+ jsx_runtime_1.jsx("button", { ref: triggerRef, type: "button", className: [is_menu_item_1.MENU_INITIATOR_CLASSNAME, SWATCH_CLASSNAME, className]
206
+ .filter(Boolean)
207
+ .join(' '), disabled: disabled, name: name, title: title !== null && title !== void 0 ? title : value, tabIndex: tabIndex, style: swatchStyle, onPointerDown: onTriggerPointerDown, onClick: onTriggerClick, children: jsx_runtime_1.jsx("span", { style: swatchFill }) }), showEyeDropper ? (jsx_runtime_1.jsx("button", { type: "button", disabled: disabled, style: eyedropperButtonStyle, onPointerDown: onEyeDropperPointerDown, onClick: onPickWithEyeDropper, tabIndex: tabIndex, title: "Pick color from screen", "aria-label": "Pick color from screen", children: jsx_runtime_1.jsx(eyedropper_1.EyedropperIcon, { style: eyedropperIconStyle, color: "currentColor" }) })) : null] }), portalStyle
146
208
  ? 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, children: jsx_runtime_1.jsx(ColorPickerPopup_1.ColorPickerPopup, { value: value, onChange: onChange, onChangeComplete: onChangeComplete }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
147
209
  : null] }));
148
210
  };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  export declare const POPUP_WIDTH = 240;
3
+ export declare const hasEyeDropper: () => boolean;
3
4
  export declare const parseEyeDropperColor: (pickedColor: string) => {
4
5
  r: number;
5
6
  g: number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ColorPickerPopup = exports.parseEyeDropperColor = exports.POPUP_WIDTH = void 0;
3
+ exports.ColorPickerPopup = exports.parseEyeDropperColor = exports.hasEyeDropper = exports.POPUP_WIDTH = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const color_conversion_1 = require("../../helpers/color-conversion");
@@ -100,6 +100,7 @@ const eyedropperButtonStyle = {
100
100
  flex: '0 0 auto',
101
101
  };
102
102
  const hasEyeDropper = () => typeof window !== 'undefined' && 'EyeDropper' in window;
103
+ exports.hasEyeDropper = hasEyeDropper;
103
104
  const parseEyeDropperColor = (pickedColor) => {
104
105
  const parsed = (0, color_conversion_1.parseAnyColor)(pickedColor);
105
106
  return {
@@ -268,7 +269,7 @@ const ColorPickerPopup = ({ value, onChange, onChangeComplete }) => {
268
269
  backgroundColor: formatted,
269
270
  };
270
271
  }, [formatted]);
271
- const showEyeDropper = hasEyeDropper();
272
+ const showEyeDropper = (0, exports.hasEyeDropper)();
272
273
  return (jsx_runtime_1.jsxs("div", { style: popupShellStyle, children: [
273
274
  jsx_runtime_1.jsx(SaturationValueArea_1.SaturationValueArea, { hue: hsva.h, saturation: hsva.s, value: hsva.v, onChange: onSvChange, onChangeComplete: onSvComplete }), jsx_runtime_1.jsxs("div", { style: sliderRowStyle, children: [showEyeDropper ? (jsx_runtime_1.jsx("button", { type: "button", style: eyedropperButtonStyle, onClick: onPickWithEyeDropper, tabIndex: tabIndex, title: "Pick color from screen", "aria-label": "Pick color from screen", children: jsx_runtime_1.jsx(eyedropper_1.EyedropperIcon, { style: { width: 14, height: 14 }, color: "currentColor" }) })) : null, jsx_runtime_1.jsx("div", { style: previewSwatchStyle, title: formatted, children: jsx_runtime_1.jsx("div", { style: previewFill }) }), jsx_runtime_1.jsxs("div", { style: slidersColumnStyle, children: [
274
275
  jsx_runtime_1.jsx(HueSlider_1.HueSlider, { hue: hsva.h, onChange: onHueChange, onChangeComplete: onHueComplete }), jsx_runtime_1.jsx(AlphaSlider_1.AlphaSlider, { hue: hsva.h, saturation: hsva.s, value: hsva.v, alpha: hsva.a, onChange: onAlphaChange, onChangeComplete: onAlphaComplete })
@@ -4,38 +4,212 @@ exports.EasingInspector = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
+ const client_id_1 = require("../../helpers/client-id");
8
+ const timeline_layout_1 = require("../../helpers/timeline-layout");
9
+ const plus_1 = require("../../icons/plus");
10
+ const render_frame_1 = require("../../state/render-frame");
7
11
  const is_menu_item_1 = require("../Menu/is-menu-item");
8
- const SegmentedControl_1 = require("../SegmentedControl");
12
+ const call_add_keyframe_1 = require("../Timeline/call-add-keyframe");
9
13
  const EasingEditorModal_1 = require("../Timeline/EasingEditorModal");
10
14
  const TimelineSelection_1 = require("../Timeline/TimelineSelection");
11
15
  const update_selected_easing_1 = require("../Timeline/update-selected-easing");
12
16
  const common_1 = require("./common");
17
+ const easing_inspector_selection_1 = require("./easing-inspector-selection");
18
+ const KeyframeEasingNavigator_1 = require("./KeyframeEasingNavigator");
19
+ const SequenceInspectorHeader_1 = require("./SequenceInspectorHeader");
13
20
  const styles_1 = require("./styles");
21
+ const use_track_for_selection_1 = require("./use-track-for-selection");
22
+ const addKeyframeIcon = {
23
+ display: 'block',
24
+ height: 13,
25
+ width: 12,
26
+ };
14
27
  const EasingInspector = ({ selection }) => {
28
+ var _a, _b;
29
+ const track = (0, use_track_for_selection_1.useTrackForSelection)(selection);
30
+ const videoConfig = (0, remotion_1.useVideoConfig)();
31
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
15
32
  const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
16
33
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
17
34
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
18
- const initialEasing = (0, react_1.useMemo)(() => (0, update_selected_easing_1.getTimelineEasingValueForSelection)({
35
+ const { getDragOverrides, getEffectDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
36
+ const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
37
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
38
+ const { selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
39
+ const parentSelection = (0, react_1.useMemo)(() => (0, TimelineSelection_1.getTimelineSelectionFromNodePathInfo)(selection.nodePathInfo), [selection.nodePathInfo]);
40
+ const easingUpdate = (0, react_1.useMemo)(() => (0, update_selected_easing_1.getSelectedEasingUpdate)({
19
41
  selection,
20
42
  sequences,
21
43
  overrideIdsToNodePaths: overrideIdToNodePathMappings,
22
44
  propStatuses,
23
45
  }), [overrideIdToNodePathMappings, propStatuses, selection, sequences]);
46
+ const initialEasing = (_a = easingUpdate === null || easingUpdate === void 0 ? void 0 : easingUpdate.currentEasing) !== null && _a !== void 0 ? _a : null;
47
+ const easingDetails = (0, react_1.useMemo)(() => {
48
+ var _a, _b, _c, _d, _e, _f, _g;
49
+ if (easingUpdate === null || track === null) {
50
+ return null;
51
+ }
52
+ if (easingUpdate.type === 'sequence') {
53
+ const sequenceDragOverrideValue = ((_a = getDragOverrides(easingUpdate.nodePath)) !== null && _a !== void 0 ? _a : {})[easingUpdate.fieldKey];
54
+ if (!track.sequence.controls) {
55
+ return {
56
+ defaultValue: undefined,
57
+ dragOverrideValue: sequenceDragOverrideValue,
58
+ fieldLabel: easingUpdate.fieldKey,
59
+ };
60
+ }
61
+ const sequenceFields = (0, timeline_layout_1.getFieldsToShow)({
62
+ schema: track.sequence.controls.schema,
63
+ currentRuntimeValueDotNotation: track.sequence.controls.currentRuntimeValueDotNotation,
64
+ getDragOverrides,
65
+ propStatuses,
66
+ nodePath: easingUpdate.nodePath,
67
+ });
68
+ const sequenceField = (_b = sequenceFields === null || sequenceFields === void 0 ? void 0 : sequenceFields.find((candidate) => candidate.key === easingUpdate.fieldKey)) !== null && _b !== void 0 ? _b : null;
69
+ return {
70
+ defaultValue: sequenceField === null || sequenceField === void 0 ? void 0 : sequenceField.fieldSchema.default,
71
+ dragOverrideValue: sequenceDragOverrideValue,
72
+ fieldLabel: (_d = (_c = sequenceField === null || sequenceField === void 0 ? void 0 : sequenceField.description) !== null && _c !== void 0 ? _c : sequenceField === null || sequenceField === void 0 ? void 0 : sequenceField.key) !== null && _d !== void 0 ? _d : easingUpdate.fieldKey,
73
+ };
74
+ }
75
+ const effectDragOverrideValue = getEffectDragOverrides(easingUpdate.nodePath, easingUpdate.effectIndex)[easingUpdate.fieldKey];
76
+ const effect = track.sequence.effects[easingUpdate.effectIndex];
77
+ if (!effect) {
78
+ return {
79
+ defaultValue: undefined,
80
+ dragOverrideValue: effectDragOverrideValue,
81
+ fieldLabel: easingUpdate.fieldKey,
82
+ };
83
+ }
84
+ const effectFields = (0, timeline_layout_1.getEffectFieldsToShow)({
85
+ effect,
86
+ effectIndex: easingUpdate.effectIndex,
87
+ nodePath: easingUpdate.nodePath,
88
+ propStatuses,
89
+ getEffectDragOverrides,
90
+ });
91
+ const effectField = (_e = effectFields.find((candidate) => candidate.key === easingUpdate.fieldKey)) !== null && _e !== void 0 ? _e : null;
92
+ return {
93
+ defaultValue: effectField === null || effectField === void 0 ? void 0 : effectField.fieldSchema.default,
94
+ dragOverrideValue: effectDragOverrideValue,
95
+ fieldLabel: (_g = (_f = effectField === null || effectField === void 0 ? void 0 : effectField.description) !== null && _f !== void 0 ? _f : effectField === null || effectField === void 0 ? void 0 : effectField.key) !== null && _g !== void 0 ? _g : easingUpdate.fieldKey,
96
+ };
97
+ }, [
98
+ easingUpdate,
99
+ getDragOverrides,
100
+ getEffectDragOverrides,
101
+ propStatuses,
102
+ track,
103
+ ]);
104
+ const fieldLabel = (_b = easingDetails === null || easingDetails === void 0 ? void 0 : easingDetails.fieldLabel) !== null && _b !== void 0 ? _b : null;
105
+ const currentEasingSelection = (0, react_1.useMemo)(() => {
106
+ if (easingUpdate === null || track === null) {
107
+ return null;
108
+ }
109
+ return (0, easing_inspector_selection_1.getEasingSelectionFromCurrentKeyframes)({
110
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
111
+ nodePathInfo: selection.nodePathInfo,
112
+ propStatus: easingUpdate.propStatus,
113
+ segmentIndex: easingUpdate.segmentIndex,
114
+ });
115
+ }, [easingUpdate, selection.nodePathInfo, track]);
24
116
  const state = (0, react_1.useMemo)(() => {
25
- if (initialEasing === null) {
117
+ if (initialEasing === null || currentEasingSelection === null) {
26
118
  return null;
27
119
  }
28
120
  return {
29
121
  initialEasing,
30
- selections: [selection],
122
+ selections: [currentEasingSelection],
123
+ };
124
+ }, [currentEasingSelection, initialEasing]);
125
+ const onSelectParent = (0, react_1.useCallback)((event) => {
126
+ event.stopPropagation();
127
+ if (parentSelection === null) {
128
+ return;
129
+ }
130
+ selectItems([parentSelection], { reveal: true });
131
+ }, [parentSelection, selectItems]);
132
+ const canAddKeyframeAtPlayhead = currentEasingSelection !== null &&
133
+ timelinePosition > currentEasingSelection.fromFrame &&
134
+ timelinePosition < currentEasingSelection.toFrame;
135
+ const addKeyframeTime = (0, render_frame_1.renderFrame)(timelinePosition, videoConfig.fps);
136
+ const addKeyframeDisabled = previewServerState.type !== 'connected';
137
+ const onAddKeyframeAtPlayhead = (0, react_1.useCallback)((event) => {
138
+ event.stopPropagation();
139
+ if (!canAddKeyframeAtPlayhead ||
140
+ easingUpdate === null ||
141
+ easingDetails === null ||
142
+ track === null ||
143
+ previewServerState.type !== 'connected') {
144
+ return;
145
+ }
146
+ const sourceFrame = timelinePosition - track.keyframeDisplayOffset;
147
+ const value = remotion_1.Internals.getEffectiveVisualModeValue({
148
+ propStatus: easingUpdate.propStatus,
149
+ dragOverrideValue: easingDetails.dragOverrideValue,
150
+ defaultValue: easingDetails.defaultValue,
151
+ frame: sourceFrame,
152
+ shouldResortToDefaultValueIfUndefined: true,
153
+ });
154
+ const keyframeSelection = {
155
+ type: 'keyframe',
156
+ nodePathInfo: selection.nodePathInfo,
157
+ frame: timelinePosition,
31
158
  };
32
- }, [initialEasing, selection]);
33
- const renderHeader = (0, react_1.useCallback)((modeItems) => (jsx_runtime_1.jsx(common_1.InspectorSectionHeader, { children: jsx_runtime_1.jsx("div", { style: styles_1.sectionHeaderRow, children: jsx_runtime_1.jsxs("div", { style: styles_1.sectionHeaderStart, children: [
34
- jsx_runtime_1.jsx("span", { style: styles_1.sectionHeaderTitle, children: "Easing" }), jsx_runtime_1.jsx(SegmentedControl_1.SegmentedControl, { items: modeItems, needsWrapping: false, size: "compact" })
35
- ] }) }) })), []);
36
- if (state === null) {
159
+ if (easingUpdate.type === 'sequence') {
160
+ (0, call_add_keyframe_1.callAddSequenceKeyframe)({
161
+ fileName: easingUpdate.fileName,
162
+ nodePath: easingUpdate.nodePath,
163
+ fieldKey: easingUpdate.fieldKey,
164
+ sourceFrame,
165
+ value,
166
+ schema: easingUpdate.schema,
167
+ setPropStatuses,
168
+ clientId: previewServerState.clientId,
169
+ }).catch(() => undefined);
170
+ }
171
+ else {
172
+ (0, call_add_keyframe_1.callAddEffectKeyframe)({
173
+ fileName: easingUpdate.fileName,
174
+ nodePath: easingUpdate.nodePath,
175
+ effectIndex: easingUpdate.effectIndex,
176
+ fieldKey: easingUpdate.fieldKey,
177
+ sourceFrame,
178
+ value,
179
+ schema: easingUpdate.schema,
180
+ setPropStatuses,
181
+ clientId: previewServerState.clientId,
182
+ }).catch(() => undefined);
183
+ }
184
+ selectItems([keyframeSelection], { reveal: true });
185
+ }, [
186
+ canAddKeyframeAtPlayhead,
187
+ easingDetails,
188
+ easingUpdate,
189
+ previewServerState,
190
+ selectItems,
191
+ selection.nodePathInfo,
192
+ setPropStatuses,
193
+ timelinePosition,
194
+ track,
195
+ ]);
196
+ const renderHeader = (0, react_1.useCallback)(() => (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
197
+ jsx_runtime_1.jsx(common_1.InspectorBackHeaderWithDivider, { disabled: parentSelection === null, onClick: onSelectParent, title: "Back to property", children: jsx_runtime_1.jsx("div", { style: styles_1.sectionHeaderTitle, children: fieldLabel }) }), easingUpdate === null || track === null ? null : (jsx_runtime_1.jsx(KeyframeEasingNavigator_1.KeyframeEasingNavigator, { currentSelection: currentEasingSelection !== null && currentEasingSelection !== void 0 ? currentEasingSelection : selection, includeEasings: true, keyframes: easingUpdate.propStatus.keyframes.map((keyframe) => ({
198
+ ...keyframe,
199
+ frame: keyframe.frame + track.keyframeDisplayOffset,
200
+ })), nodePathInfo: selection.nodePathInfo }))] })), [
201
+ currentEasingSelection,
202
+ easingUpdate,
203
+ fieldLabel,
204
+ onSelectParent,
205
+ parentSelection,
206
+ selection,
207
+ track,
208
+ ]);
209
+ if (state === null || track === null || currentEasingSelection === null) {
37
210
  return jsx_runtime_1.jsx(common_1.InspectorMessage, { children: "Easing unavailable" });
38
211
  }
39
- return (jsx_runtime_1.jsx("div", { style: styles_1.selectedContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(EasingEditorModal_1.EasingEditor, { state: state, renderHeader: renderHeader }, (0, TimelineSelection_1.getTimelineSelectionKey)(selection)) }));
212
+ return (jsx_runtime_1.jsxs("div", { style: styles_1.selectedContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [
213
+ jsx_runtime_1.jsx(SequenceInspectorHeader_1.SequenceInspectorHeaderWithDivider, { track: track }), jsx_runtime_1.jsx(EasingEditorModal_1.EasingEditor, { state: state, renderHeader: renderHeader }, (0, TimelineSelection_1.getTimelineSelectionKey)(currentEasingSelection)), canAddKeyframeAtPlayhead ? (jsx_runtime_1.jsx("div", { style: styles_1.detailsContainer, children: jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: addKeyframeDisabled, onClick: onAddKeyframeAtPlayhead, renderIcon: (color) => (jsx_runtime_1.jsx(plus_1.Plus, { color: color, style: addKeyframeIcon })), children: `Add keyframe at ${addKeyframeTime}` }) })) : null] }));
40
214
  };
41
215
  exports.EasingInspector = EasingInspector;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
3
+ import { type TimelineSelection } from '../Timeline/TimelineSelection';
4
+ import { type NavigatorKeyframe } from './keyframe-easing-navigator-items';
5
+ export declare const KeyframeEasingNavigator: React.FC<{
6
+ readonly currentSelection: Extract<TimelineSelection, {
7
+ type: 'keyframe';
8
+ } | {
9
+ type: 'easing';
10
+ }>;
11
+ readonly includeEasings: boolean;
12
+ readonly keyframes: readonly NavigatorKeyframe[];
13
+ readonly nodePathInfo: SequenceNodePathInfo;
14
+ }>;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeyframeEasingNavigator = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const remotion_1 = require("remotion");
7
+ const colors_1 = require("../../helpers/colors");
8
+ const InlineAction_1 = require("../InlineAction");
9
+ const InspectorPanelLayout_1 = require("../InspectorPanelLayout");
10
+ const TimelineKeyframeDiamondIcon_1 = require("../Timeline/TimelineKeyframeDiamondIcon");
11
+ const TimelineKeyframeEasingLine_1 = require("../Timeline/TimelineKeyframeEasingLine");
12
+ const TimelineSelection_1 = require("../Timeline/TimelineSelection");
13
+ const keyframe_easing_navigator_items_1 = require("./keyframe-easing-navigator-items");
14
+ const navigatorContainer = {
15
+ alignItems: 'center',
16
+ boxSizing: 'border-box',
17
+ display: 'flex',
18
+ gap: 8,
19
+ justifyContent: 'space-between',
20
+ padding: `8px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 6px`,
21
+ width: '100%',
22
+ };
23
+ const itemStrip = {
24
+ alignItems: 'center',
25
+ display: 'flex',
26
+ flex: 1,
27
+ gap: 0,
28
+ height: 24,
29
+ justifyContent: 'center',
30
+ minWidth: 0,
31
+ };
32
+ const itemButton = {
33
+ alignItems: 'center',
34
+ background: 'none',
35
+ border: 'none',
36
+ display: 'flex',
37
+ height: 24,
38
+ justifyContent: 'center',
39
+ padding: 0,
40
+ };
41
+ const diamondSize = 12;
42
+ const easingLineDiamondOverlap = diamondSize / 2;
43
+ const emptyItem = {
44
+ height: 24,
45
+ width: diamondSize,
46
+ };
47
+ const easingItem = {
48
+ height: 12,
49
+ position: 'relative',
50
+ width: 38,
51
+ };
52
+ const getEasingLineUnderlay = ({ extendLeft, extendRight, }) => {
53
+ return {
54
+ bottom: 0,
55
+ left: extendLeft ? -easingLineDiamondOverlap : 0,
56
+ pointerEvents: 'none',
57
+ position: 'absolute',
58
+ right: extendRight ? -easingLineDiamondOverlap : 0,
59
+ top: 0,
60
+ };
61
+ };
62
+ const chevronIcon = {
63
+ display: 'block',
64
+ height: 12,
65
+ width: 8,
66
+ };
67
+ const disabledChevronColor = 'rgba(255, 255, 255, 0.25)';
68
+ const NavigationChevron = ({ color, direction }) => {
69
+ const path = direction === 'left' ? 'M6 1L2 6L6 11' : 'M2 1L6 6L2 11';
70
+ return (jsx_runtime_1.jsx("svg", { viewBox: "0 0 8 12", style: chevronIcon, children: jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: color, strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5" }) }));
71
+ };
72
+ const TimelineNavigatorItem = ({ extendLineLeft, extendLineRight, item, onSelect, selected }) => {
73
+ const onClick = (0, react_1.useCallback)(() => {
74
+ if (item === null) {
75
+ return;
76
+ }
77
+ onSelect(item);
78
+ }, [item, onSelect]);
79
+ if (item === null) {
80
+ return jsx_runtime_1.jsx("div", { style: emptyItem });
81
+ }
82
+ const buttonStyle = {
83
+ ...itemButton,
84
+ position: 'relative',
85
+ width: item.type === 'easing' ? 38 : diamondSize,
86
+ zIndex: item.type === 'keyframe' ? 1 : 0,
87
+ };
88
+ const lineUnderlayStyle = getEasingLineUnderlay({
89
+ extendLeft: extendLineLeft,
90
+ extendRight: extendLineRight,
91
+ });
92
+ return (jsx_runtime_1.jsx("button", { type: "button", style: buttonStyle, onClick: onClick, title: item.type === 'keyframe'
93
+ ? `Keyframe at frame ${item.selection.frame}`
94
+ : `Easing from frame ${item.selection.fromFrame} to ${item.selection.toFrame}`, "aria-label": item.type === 'keyframe'
95
+ ? `Select keyframe at frame ${item.selection.frame}`
96
+ : `Select easing from frame ${item.selection.fromFrame} to ${item.selection.toFrame}`, children: item.type === 'keyframe' ? (jsx_runtime_1.jsx(TimelineKeyframeDiamondIcon_1.TimelineKeyframeDiamondIcon, { color: colors_1.LIGHT_TEXT, selected: selected, size: 12 })) : (jsx_runtime_1.jsx("div", { style: easingItem, children: jsx_runtime_1.jsx("div", { style: lineUnderlayStyle, children: jsx_runtime_1.jsx(TimelineKeyframeEasingLine_1.TimelineKeyframeEasingLineVisual, { selected: selected }) }) })) }));
97
+ };
98
+ const KeyframeEasingNavigator = ({ currentSelection, includeEasings, keyframes, nodePathInfo }) => {
99
+ const { isSelected, selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
100
+ const setFrame = remotion_1.Internals.useTimelineSetFrame();
101
+ const videoConfig = (0, remotion_1.useVideoConfig)();
102
+ const items = (0, react_1.useMemo)(() => (0, keyframe_easing_navigator_items_1.getKeyframeEasingNavigatorItems)({
103
+ includeEasings,
104
+ keyframes,
105
+ nodePathInfo,
106
+ }), [includeEasings, keyframes, nodePathInfo]);
107
+ const currentKey = (0, TimelineSelection_1.getTimelineSelectionKey)(currentSelection);
108
+ const currentIndex = items.findIndex((item) => (0, TimelineSelection_1.getTimelineSelectionKey)(item.selection) === currentKey);
109
+ const previousItem = currentIndex > 0 ? items[currentIndex - 1] : null;
110
+ const currentItem = currentIndex === -1 ? null : items[currentIndex];
111
+ const nextItem = currentIndex === -1 || currentIndex >= items.length - 1
112
+ ? null
113
+ : items[currentIndex + 1];
114
+ const selectItem = (0, react_1.useCallback)((item) => {
115
+ selectItems([item.selection], { reveal: true });
116
+ }, [selectItems]);
117
+ const seekToItem = (0, react_1.useCallback)((item) => {
118
+ const frame = (0, keyframe_easing_navigator_items_1.getNavigatorItemPlayheadFrame)(item);
119
+ setFrame((current) => {
120
+ const next = { ...current, [videoConfig.id]: frame };
121
+ remotion_1.Internals.persistCurrentFrame(next);
122
+ return next;
123
+ });
124
+ }, [setFrame, videoConfig.id]);
125
+ const selectPrevious = (0, react_1.useCallback)(() => {
126
+ if (previousItem === null) {
127
+ return;
128
+ }
129
+ seekToItem(previousItem);
130
+ selectItem(previousItem);
131
+ }, [previousItem, seekToItem, selectItem]);
132
+ const selectNext = (0, react_1.useCallback)(() => {
133
+ if (nextItem === null) {
134
+ return;
135
+ }
136
+ seekToItem(nextItem);
137
+ selectItem(nextItem);
138
+ }, [nextItem, seekToItem, selectItem]);
139
+ if (currentItem === null) {
140
+ return null;
141
+ }
142
+ return (jsx_runtime_1.jsxs("div", { style: navigatorContainer, children: [jsx_runtime_1.jsx(InlineAction_1.InlineAction, { disabled: previousItem === null, onClick: selectPrevious, title: "Previous animation item", renderAction: (color) => (jsx_runtime_1.jsx(NavigationChevron, { color: previousItem === null ? disabledChevronColor : color, direction: "left" })) }), jsx_runtime_1.jsxs("div", { style: itemStrip, children: [
143
+ jsx_runtime_1.jsx(TimelineNavigatorItem, { extendLineLeft: false, extendLineRight: currentItem.type === 'keyframe', item: previousItem, onSelect: selectItem, selected: previousItem === null ? false : isSelected(previousItem.selection) }), jsx_runtime_1.jsx(TimelineNavigatorItem, { extendLineLeft: (previousItem === null || previousItem === void 0 ? void 0 : previousItem.type) === 'keyframe', extendLineRight: (nextItem === null || nextItem === void 0 ? void 0 : nextItem.type) === 'keyframe', item: currentItem, onSelect: selectItem, selected: isSelected(currentItem.selection) }), jsx_runtime_1.jsx(TimelineNavigatorItem, { extendLineLeft: currentItem.type === 'keyframe', extendLineRight: false, item: nextItem, onSelect: selectItem, selected: nextItem === null ? false : isSelected(nextItem.selection) })
144
+ ] }), jsx_runtime_1.jsx(InlineAction_1.InlineAction, { disabled: nextItem === null, onClick: selectNext, title: "Next animation item", renderAction: (color) => (jsx_runtime_1.jsx(NavigationChevron, { color: nextItem === null ? disabledChevronColor : color, direction: "right" })) })] }));
145
+ };
146
+ exports.KeyframeEasingNavigator = KeyframeEasingNavigator;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { TimelineSelection } from '../Timeline/TimelineSelection';
2
+ import { type TimelineSelection } from '../Timeline/TimelineSelection';
3
3
  export declare const KeyframeInspector: React.FC<{
4
4
  readonly selection: Extract<TimelineSelection, {
5
5
  type: 'keyframe';