@remotion/studio 4.0.483 → 4.0.485

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 (113) hide show
  1. package/dist/components/ColorPicker/ColorPicker.js +65 -3
  2. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +1 -0
  3. package/dist/components/ColorPicker/ColorPickerPopup.js +3 -2
  4. package/dist/components/ContextMenu.js +75 -1
  5. package/dist/components/CurrentComposition.js +3 -2
  6. package/dist/components/InlineCompositionName.d.ts +7 -0
  7. package/dist/components/InlineCompositionName.js +58 -0
  8. package/dist/components/InlineEditableTitle.d.ts +7 -0
  9. package/dist/components/InlineEditableTitle.js +129 -0
  10. package/dist/components/InspectorPanel/EasingInspector.js +184 -10
  11. package/dist/components/InspectorPanel/KeyframeEasingNavigator.d.ts +14 -0
  12. package/dist/components/InspectorPanel/KeyframeEasingNavigator.js +146 -0
  13. package/dist/components/InspectorPanel/KeyframeInspector.d.ts +1 -1
  14. package/dist/components/InspectorPanel/KeyframeInspector.js +229 -5
  15. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +17 -0
  16. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +80 -0
  17. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -58
  18. package/dist/components/InspectorPanel/common.d.ts +12 -0
  19. package/dist/components/InspectorPanel/common.js +78 -1
  20. package/dist/components/InspectorPanel/easing-inspector-selection.d.ts +14 -0
  21. package/dist/components/InspectorPanel/easing-inspector-selection.js +18 -0
  22. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.d.ts +24 -0
  23. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.js +40 -0
  24. package/dist/components/InspectorPanel/keyframe-inspector-frame.d.ts +8 -0
  25. package/dist/components/InspectorPanel/keyframe-inspector-frame.js +14 -0
  26. package/dist/components/InspectorPanel/styles.d.ts +1 -0
  27. package/dist/components/InspectorPanel/styles.js +9 -3
  28. package/dist/components/InspectorSequenceSection.js +37 -10
  29. package/dist/components/Modals.js +1 -1
  30. package/dist/components/NewComposition/CodemodFooter.d.ts +7 -1
  31. package/dist/components/NewComposition/CodemodFooter.js +17 -12
  32. package/dist/components/NewComposition/DeleteComposition.js +7 -1
  33. package/dist/components/NewComposition/DeleteFolder.js +7 -1
  34. package/dist/components/NewComposition/DuplicateComposition.js +17 -10
  35. package/dist/components/NewComposition/InputAndValidationContainer.d.ts +3 -0
  36. package/dist/components/NewComposition/InputAndValidationContainer.js +15 -0
  37. package/dist/components/NewComposition/NewCompDuration.js +7 -6
  38. package/dist/components/NewComposition/NewComposition.d.ts +5 -1
  39. package/dist/components/NewComposition/NewComposition.js +29 -86
  40. package/dist/components/NewComposition/RenameComposition.js +13 -14
  41. package/dist/components/NewComposition/RenameFolder.js +9 -2
  42. package/dist/components/NewComposition/RenameStaticFile.js +2 -1
  43. package/dist/components/NewComposition/ValidationMessage.js +9 -1
  44. package/dist/components/OptionsPanel.d.ts +0 -3
  45. package/dist/components/OptionsPanel.js +7 -3
  46. package/dist/components/Preview.js +1 -1
  47. package/dist/components/RenderModal/ServerRenderModal.js +4 -3
  48. package/dist/components/RenderModal/WebRenderModal.js +2 -1
  49. package/dist/components/SelectedOutlineElement.js +45 -3
  50. package/dist/components/SelectedOutlineOverlay.d.ts +3 -1
  51. package/dist/components/SelectedOutlineOverlay.js +48 -15
  52. package/dist/components/Timeline/EasingEditorModal.js +9 -4
  53. package/dist/components/Timeline/TimelineDeleteKeybindings.js +45 -2
  54. package/dist/components/Timeline/TimelineEffectPropItem.js +82 -1
  55. package/dist/components/Timeline/TimelineExpandedSection.js +1 -0
  56. package/dist/components/Timeline/TimelineInOutPointerHandle.js +2 -1
  57. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +1 -1
  58. package/dist/components/Timeline/TimelineKeyframeControls.js +38 -7
  59. package/dist/components/Timeline/TimelineKeyframeEasingLine.d.ts +4 -0
  60. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +12 -6
  61. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +4 -0
  62. package/dist/components/Timeline/TimelineSelection.js +1 -0
  63. package/dist/components/Timeline/TimelineSequenceItem.js +13 -62
  64. package/dist/components/Timeline/TimelineSequenceName.d.ts +1 -0
  65. package/dist/components/Timeline/TimelineSequenceName.js +7 -6
  66. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +1 -1
  67. package/dist/components/Timeline/TimelineSequencePropItem.js +86 -4
  68. package/dist/components/Timeline/TimelineSlider.js +17 -3
  69. package/dist/components/Timeline/TimelineTextContentField.d.ts +12 -0
  70. package/dist/components/Timeline/TimelineTextContentField.js +100 -0
  71. package/dist/components/Timeline/TimelineWidthProvider.js +18 -3
  72. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +8 -2
  73. package/dist/components/Timeline/delete-selected-timeline-item.js +80 -1
  74. package/dist/components/Timeline/focus-inspector-field.d.ts +16 -0
  75. package/dist/components/Timeline/focus-inspector-field.js +49 -0
  76. package/dist/components/Timeline/get-animation-item-selection-for-frame.d.ts +18 -0
  77. package/dist/components/Timeline/get-animation-item-selection-for-frame.js +49 -0
  78. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.d.ts +15 -0
  79. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +26 -0
  80. package/dist/components/Timeline/save-sequence-prop.js +2 -0
  81. package/dist/components/Timeline/split-selected-timeline-item.d.ts +38 -0
  82. package/dist/components/Timeline/split-selected-timeline-item.js +156 -0
  83. package/dist/components/Timeline/timeline-field-display-utils.js +2 -0
  84. package/dist/components/Timeline/update-selected-easing.d.ts +1 -0
  85. package/dist/components/Timeline/update-selected-easing.js +4 -3
  86. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +1 -0
  87. package/dist/components/Timeline/use-rename-sequence.d.ts +30 -0
  88. package/dist/components/Timeline/use-rename-sequence.js +115 -0
  89. package/dist/components/Timeline/use-timeline-expanded-tree.d.ts +2 -1
  90. package/dist/components/Timeline/use-timeline-expanded-tree.js +3 -1
  91. package/dist/components/Timeline/use-timeline-height.js +1 -0
  92. package/dist/components/composition-menu-items.js +3 -0
  93. package/dist/components/folder-menu-items.js +20 -0
  94. package/dist/components/options-sidebar-tabs.d.ts +4 -0
  95. package/dist/components/options-sidebar-tabs.js +5 -0
  96. package/dist/components/selected-outline-types.d.ts +6 -1
  97. package/dist/esm/{chunk-fq0j774v.js → chunk-103pp4n7.js} +17652 -15098
  98. package/dist/esm/internals.mjs +17652 -15098
  99. package/dist/esm/previewEntry.mjs +18357 -15803
  100. package/dist/esm/renderEntry.mjs +1 -1
  101. package/dist/helpers/render-codec-label.d.ts +1 -1
  102. package/dist/helpers/timeline-layout.d.ts +4 -3
  103. package/dist/helpers/timeline-layout.js +3 -1
  104. package/dist/helpers/use-create-composition.d.ts +35 -0
  105. package/dist/helpers/use-create-composition.js +111 -0
  106. package/dist/helpers/use-menu-structure.js +0 -14
  107. package/dist/helpers/use-rename-composition.d.ts +16 -0
  108. package/dist/helpers/use-rename-composition.js +49 -0
  109. package/dist/state/modals.d.ts +3 -0
  110. package/dist/state/timeline-zoom.js +17 -14
  111. package/dist/state/z-index.d.ts +1 -0
  112. package/dist/state/z-index.js +11 -2
  113. package/package.json +12 -12
@@ -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 })
@@ -47,7 +47,25 @@ const z_index_1 = require("../state/z-index");
47
47
  const portals_1 = require("./Menu/portals");
48
48
  const styles_1 = require("./Menu/styles");
49
49
  const MenuContent_1 = require("./NewComposition/MenuContent");
50
+ const CONTEXT_MENU_Z_INDEX = 1001;
51
+ const contextMenuFullScreenOverlay = {
52
+ ...styles_1.fullScreenOverlay,
53
+ pointerEvents: 'none',
54
+ zIndex: CONTEXT_MENU_Z_INDEX,
55
+ };
56
+ const contextMenuOuterPortal = {
57
+ ...styles_1.outerPortal,
58
+ pointerEvents: 'auto',
59
+ };
60
+ const contextMenuOpenedEvent = 'remotion-context-menu-opened';
61
+ let nextContextMenuId = 0;
62
+ const notifyContextMenuOpened = (id) => {
63
+ window.dispatchEvent(new CustomEvent(contextMenuOpenedEvent, {
64
+ detail: id,
65
+ }));
66
+ };
50
67
  const ContextMenuPortal = ({ sizeSource, currentZIndex, onHide, opened, values }) => {
68
+ const menuRef = (0, react_1.useRef)(null);
51
69
  const size = player_1.PlayerInternals.useElementSize(sizeSource, {
52
70
  triggerOnWindowResize: true,
53
71
  shouldApplyCssTransforms: true,
@@ -103,6 +121,34 @@ const ContextMenuPortal = ({ sizeSource, currentZIndex, onHide, opened, values }
103
121
  spaceToTop,
104
122
  spaceToBottom,
105
123
  ]);
124
+ (0, react_1.useEffect)(() => {
125
+ const preventNativeContextMenu = (event) => {
126
+ event.preventDefault();
127
+ };
128
+ window.addEventListener('contextmenu', preventNativeContextMenu, true);
129
+ return () => {
130
+ window.removeEventListener('contextmenu', preventNativeContextMenu, true);
131
+ };
132
+ }, []);
133
+ (0, react_1.useEffect)(() => {
134
+ const dismissWithoutClickThrough = (event) => {
135
+ var _a;
136
+ if (event.button !== 0) {
137
+ return;
138
+ }
139
+ if ((_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target)) {
140
+ return;
141
+ }
142
+ event.preventDefault();
143
+ event.stopPropagation();
144
+ event.stopImmediatePropagation();
145
+ onHide();
146
+ };
147
+ window.addEventListener('pointerdown', dismissWithoutClickThrough, true);
148
+ return () => {
149
+ window.removeEventListener('pointerdown', dismissWithoutClickThrough, true);
150
+ };
151
+ }, [onHide]);
106
152
  // Prevent deselection of a selected item
107
153
  const onMenuPointerDown = (0, react_1.useCallback)((e) => {
108
154
  e.stopPropagation();
@@ -110,10 +156,11 @@ const ContextMenuPortal = ({ sizeSource, currentZIndex, onHide, opened, values }
110
156
  if (!portalStyle) {
111
157
  return null;
112
158
  }
113
- return 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));
159
+ return react_dom_1.default.createPortal(jsx_runtime_1.jsx("div", { style: contextMenuFullScreenOverlay, children: jsx_runtime_1.jsx("div", { style: contextMenuOuterPortal, className: "css-reset", children: jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, outsideClickButton: "primary", children: jsx_runtime_1.jsx("div", { ref: menuRef, 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));
114
160
  };
115
161
  exports.ContextMenu = react_1.default.forwardRef(({ children, values, onOpen, style = undefined, className = undefined, onPointerDown = undefined, }, forwardedRef) => {
116
162
  const ref = (0, react_1.useRef)(null);
163
+ const idRef = (0, react_1.useRef)(nextContextMenuId++);
117
164
  const [opened, setOpened] = (0, react_1.useState)({ type: 'not-open' });
118
165
  const { currentZIndex } = (0, z_index_1.useZIndex)();
119
166
  const setRef = (0, react_1.useCallback)((node) => {
@@ -137,6 +184,7 @@ exports.ContextMenu = react_1.default.forwardRef(({ children, values, onOpen, st
137
184
  if ((onOpen === null || onOpen === void 0 ? void 0 : onOpen()) === false) {
138
185
  return false;
139
186
  }
187
+ notifyContextMenuOpened(idRef.current);
140
188
  setOpened({ type: 'open', left: e.clientX, top: e.clientY });
141
189
  return false;
142
190
  };
@@ -148,11 +196,24 @@ exports.ContextMenu = react_1.default.forwardRef(({ children, values, onOpen, st
148
196
  const onHide = (0, react_1.useCallback)(() => {
149
197
  setOpened({ type: 'not-open' });
150
198
  }, []);
199
+ (0, react_1.useEffect)(() => {
200
+ const onOtherContextMenuOpened = (event) => {
201
+ if (event.detail === idRef.current) {
202
+ return;
203
+ }
204
+ onHide();
205
+ };
206
+ window.addEventListener(contextMenuOpenedEvent, onOtherContextMenuOpened);
207
+ return () => {
208
+ window.removeEventListener(contextMenuOpenedEvent, onOtherContextMenuOpened);
209
+ };
210
+ }, [onHide]);
151
211
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
152
212
  jsx_runtime_1.jsx("div", { ref: setRef, onContextMenu: () => false, style: style, className: className, onPointerDown: onPointerDown, children: children }), opened.type === 'open' ? (jsx_runtime_1.jsx(ContextMenuPortal, { sizeSource: ref, currentZIndex: currentZIndex, onHide: onHide, opened: opened, values: values })) : null] }));
153
213
  });
154
214
  exports.ContextMenu.displayName = 'ContextMenu';
155
215
  const ContextMenuForTarget = ({ triggerRef, values, onOpen }) => {
216
+ const idRef = (0, react_1.useRef)(nextContextMenuId++);
156
217
  const [opened, setOpened] = (0, react_1.useState)({ type: 'not-open' });
157
218
  const [openedValues, setOpenedValues] = (0, react_1.useState)(values);
158
219
  const [body, setBody] = (0, react_1.useState)(null);
@@ -179,6 +240,7 @@ const ContextMenuForTarget = ({ triggerRef, values, onOpen }) => {
179
240
  if (nextValues.length === 0) {
180
241
  return false;
181
242
  }
243
+ notifyContextMenuOpened(idRef.current);
182
244
  setOpenedValues(nextValues);
183
245
  setOpened({ type: 'open', left: e.clientX, top: e.clientY });
184
246
  return false;
@@ -191,6 +253,18 @@ const ContextMenuForTarget = ({ triggerRef, values, onOpen }) => {
191
253
  const onHide = (0, react_1.useCallback)(() => {
192
254
  setOpened({ type: 'not-open' });
193
255
  }, []);
256
+ (0, react_1.useEffect)(() => {
257
+ const onOtherContextMenuOpened = (event) => {
258
+ if (event.detail === idRef.current) {
259
+ return;
260
+ }
261
+ onHide();
262
+ };
263
+ window.addEventListener(contextMenuOpenedEvent, onOtherContextMenuOpened);
264
+ return () => {
265
+ window.removeEventListener(contextMenuOpenedEvent, onOtherContextMenuOpened);
266
+ };
267
+ }, [onHide]);
194
268
  return opened.type === 'open' ? (jsx_runtime_1.jsx(ContextMenuPortal, { sizeSource: body, currentZIndex: currentZIndex, onHide: onHide, opened: opened, values: [...openedValues] })) : null;
195
269
  };
196
270
  exports.ContextMenuForTarget = ContextMenuForTarget;
@@ -7,13 +7,14 @@ const remotion_1 = require("remotion");
7
7
  const is_composition_still_1 = require("../helpers/is-composition-still");
8
8
  const open_in_editor_1 = require("../helpers/open-in-editor");
9
9
  const render_frame_1 = require("../state/render-frame");
10
+ const InlineCompositionName_1 = require("./InlineCompositionName");
10
11
  const InspectorInfoHeader_1 = require("./InspectorInfoHeader");
11
12
  const InspectorSourceLocation_1 = require("./InspectorSourceLocation");
12
13
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
13
14
  const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
14
15
  exports.CURRENT_COMPOSITION_HEIGHT = InspectorInfoHeader_1.INSPECTOR_INFO_HEADER_MIN_HEIGHT;
15
16
  const CurrentComposition = () => {
16
- var _a;
17
+ var _a, _b;
17
18
  const video = remotion_1.Internals.useVideo();
18
19
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
19
20
  const currentComposition = (0, react_1.useMemo)(() => {
@@ -44,6 +45,6 @@ const CurrentComposition = () => {
44
45
  });
45
46
  }, [validatedLocation]);
46
47
  return (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoHeader, { children: video ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
47
- jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoTitle, { children: video.id }), jsx_runtime_1.jsx(InspectorSourceLocation_1.InspectorSourceLocation, { location: validatedLocation, canOpen: validatedLocation !== null, onOpen: openFileLocation }), jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: "Still" })) : (jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] })) : null }));
48
+ jsx_runtime_1.jsx(InlineCompositionName_1.InlineCompositionName, { compositionId: video.id, stack: (_b = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _b !== void 0 ? _b : null, compositions: compositions }, video.id), jsx_runtime_1.jsx(InspectorSourceLocation_1.InspectorSourceLocation, { location: validatedLocation, canOpen: validatedLocation !== null, onOpen: openFileLocation }), jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: "Still" })) : (jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] })) : null }));
48
49
  };
49
50
  exports.CurrentComposition = CurrentComposition;
@@ -0,0 +1,7 @@
1
+ import type * as React from 'react';
2
+ import type { _InternalTypes } from 'remotion';
3
+ export declare const InlineCompositionName: React.FC<{
4
+ readonly compositionId: string;
5
+ readonly stack: string | null;
6
+ readonly compositions: _InternalTypes['AnyComposition'][];
7
+ }>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineCompositionName = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const resolved_stack_to_symbolicated_1 = require("../helpers/resolved-stack-to-symbolicated");
7
+ const use_rename_composition_1 = require("../helpers/use-rename-composition");
8
+ const InlineEditableTitle_1 = require("./InlineEditableTitle");
9
+ const NotificationCenter_1 = require("./Notifications/NotificationCenter");
10
+ const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
11
+ const InlineCompositionName = ({ compositionId, stack, compositions }) => {
12
+ const canRename = !window.remotion_isReadOnlyStudio;
13
+ const resolvedLocation = (0, use_resolved_stack_1.useResolvedStack)(stack);
14
+ const symbolicatedStack = (0, react_1.useMemo)(() => (0, resolved_stack_to_symbolicated_1.resolvedStackToSymbolicated)(resolvedLocation), [resolvedLocation]);
15
+ const { getValidationMessage, renameComposition } = (0, use_rename_composition_1.useRenameComposition)({
16
+ compositions,
17
+ currentId: compositionId,
18
+ newId: compositionId,
19
+ });
20
+ const commit = (0, react_1.useCallback)((newId) => {
21
+ if (newId === compositionId) {
22
+ return;
23
+ }
24
+ const compNameErrMessage = getValidationMessage(newId);
25
+ if (compNameErrMessage) {
26
+ (0, NotificationCenter_1.showNotification)(compNameErrMessage, 2000);
27
+ return;
28
+ }
29
+ if (!stack || !symbolicatedStack) {
30
+ (0, NotificationCenter_1.showNotification)('Could not determine where this composition is defined', 2000);
31
+ return;
32
+ }
33
+ const notification = (0, NotificationCenter_1.showNotification)('Renaming...', null);
34
+ renameComposition({
35
+ newCompositionId: newId,
36
+ signal: new AbortController().signal,
37
+ symbolicatedStack,
38
+ })
39
+ .then((result) => {
40
+ if (!result.success) {
41
+ notification.replaceContent(`Could not rename composition: ${result.reason}`, 2000);
42
+ return;
43
+ }
44
+ notification.replaceContent(`Renamed to ${newId}`, 2000);
45
+ })
46
+ .catch((err) => {
47
+ notification.replaceContent(`Could not rename composition: ${err.message}`, 2000);
48
+ });
49
+ }, [
50
+ compositionId,
51
+ getValidationMessage,
52
+ renameComposition,
53
+ stack,
54
+ symbolicatedStack,
55
+ ]);
56
+ return (jsx_runtime_1.jsx(InlineEditableTitle_1.InlineEditableTitle, { value: compositionId, canRename: canRename, onCommit: commit }));
57
+ };
58
+ exports.InlineCompositionName = InlineCompositionName;
@@ -0,0 +1,7 @@
1
+ import type * as React from 'react';
2
+ export declare const InlineEditableTitle: React.FC<{
3
+ readonly value: string;
4
+ readonly canRename: boolean;
5
+ readonly onCommit: (newValue: string) => void;
6
+ readonly title?: string;
7
+ }>;
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineEditableTitle = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const colors_1 = require("../helpers/colors");
7
+ const titleWrapper = {
8
+ boxSizing: 'border-box',
9
+ color: 'white',
10
+ fontSize: 12,
11
+ height: 18,
12
+ lineHeight: '18px',
13
+ marginLeft: -4,
14
+ overflow: 'hidden',
15
+ textOverflow: 'ellipsis',
16
+ whiteSpace: 'nowrap',
17
+ width: 'calc(100% + 4px)',
18
+ };
19
+ const titleInner = {
20
+ borderRadius: 4,
21
+ boxSizing: 'border-box',
22
+ display: 'inline-grid',
23
+ fontSize: 12,
24
+ lineHeight: '18px',
25
+ maxWidth: '100%',
26
+ paddingLeft: 4,
27
+ paddingRight: 4,
28
+ verticalAlign: 'top',
29
+ };
30
+ const titleGridItem = {
31
+ fontSize: 12,
32
+ gridArea: '1 / 1',
33
+ minWidth: 0,
34
+ overflow: 'hidden',
35
+ textOverflow: 'ellipsis',
36
+ whiteSpace: 'nowrap',
37
+ };
38
+ const titleInput = {
39
+ appearance: 'none',
40
+ backgroundColor: 'transparent',
41
+ border: 'none',
42
+ boxShadow: 'none',
43
+ color: 'white',
44
+ fontFamily: 'inherit',
45
+ fontSize: 12,
46
+ height: 18,
47
+ lineHeight: '18px',
48
+ margin: 0,
49
+ minWidth: 0,
50
+ outline: 'none',
51
+ overflow: 'hidden',
52
+ padding: 0,
53
+ WebkitAppearance: 'none',
54
+ width: '100%',
55
+ };
56
+ const InlineEditableTitle = ({ value, canRename, onCommit, title }) => {
57
+ const [isEditing, setIsEditing] = (0, react_1.useState)(false);
58
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
59
+ const [draftValue, setDraftValue] = (0, react_1.useState)(value);
60
+ const inputRef = (0, react_1.useRef)(null);
61
+ const cancelledRef = (0, react_1.useRef)(false);
62
+ (0, react_1.useEffect)(() => {
63
+ if (!isEditing) {
64
+ setDraftValue(value);
65
+ }
66
+ }, [isEditing, value]);
67
+ const focusInput = (0, react_1.useCallback)((input) => {
68
+ inputRef.current = input;
69
+ if (!input) {
70
+ return;
71
+ }
72
+ input.focus();
73
+ input.select();
74
+ }, []);
75
+ const commit = (0, react_1.useCallback)((newValue) => {
76
+ if (cancelledRef.current) {
77
+ return;
78
+ }
79
+ setIsEditing(false);
80
+ onCommit(newValue);
81
+ }, [onCommit]);
82
+ const startEditing = (0, react_1.useCallback)(() => {
83
+ if (!canRename) {
84
+ return;
85
+ }
86
+ cancelledRef.current = false;
87
+ setDraftValue(value);
88
+ setIsEditing(true);
89
+ }, [canRename, value]);
90
+ const onChange = (0, react_1.useCallback)((e) => {
91
+ setDraftValue(e.target.value);
92
+ }, []);
93
+ const onBlur = (0, react_1.useCallback)((e) => {
94
+ commit(e.currentTarget.value);
95
+ }, [commit]);
96
+ const onKeyDown = (0, react_1.useCallback)((e) => {
97
+ var _a;
98
+ if (e.key === 'Enter') {
99
+ e.preventDefault();
100
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
101
+ }
102
+ if (e.key === 'Escape') {
103
+ e.preventDefault();
104
+ cancelledRef.current = true;
105
+ setDraftValue(value);
106
+ setIsEditing(false);
107
+ }
108
+ }, [value]);
109
+ const backgroundColor = isEditing
110
+ ? colors_1.INPUT_BACKGROUND
111
+ : isHovered && canRename
112
+ ? colors_1.CLEAR_HOVER
113
+ : 'transparent';
114
+ const innerStyle = (0, react_1.useMemo)(() => {
115
+ return {
116
+ ...titleInner,
117
+ backgroundColor,
118
+ cursor: isEditing ? 'text' : canRename ? 'pointer' : 'default',
119
+ userSelect: isEditing ? 'text' : 'none',
120
+ width: isEditing ? '100%' : undefined,
121
+ };
122
+ }, [backgroundColor, canRename, isEditing]);
123
+ return (jsx_runtime_1.jsx("div", { style: titleWrapper, title: title !== null && title !== void 0 ? title : value, children: jsx_runtime_1.jsxs("span", { style: innerStyle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: isEditing || !canRename ? undefined : startEditing, children: [
124
+ jsx_runtime_1.jsx("span", { "aria-hidden": isEditing, style: {
125
+ ...titleGridItem,
126
+ visibility: isEditing ? 'hidden' : 'visible',
127
+ }, children: value }), isEditing ? (jsx_runtime_1.jsx("input", { ref: focusInput, style: { ...titleGridItem, ...titleInput }, value: draftValue, onChange: onChange, onBlur: onBlur, onKeyDown: onKeyDown })) : null] }) }));
128
+ };
129
+ exports.InlineEditableTitle = InlineEditableTitle;