@remotion/studio 4.0.475 → 4.0.477

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 (88) hide show
  1. package/dist/components/Canvas.js +40 -1
  2. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +6 -0
  3. package/dist/components/ColorPicker/ColorPickerPopup.js +11 -6
  4. package/dist/components/ControlButton.d.ts +1 -0
  5. package/dist/components/ControlButton.js +7 -2
  6. package/dist/components/EditorGuides/Guide.js +122 -20
  7. package/dist/components/EditorRuler/Ruler.js +21 -15
  8. package/dist/components/EditorRuler/index.js +18 -10
  9. package/dist/components/GlobalKeybindings.js +12 -0
  10. package/dist/components/KeyboardShortcutsExplainer.js +24 -0
  11. package/dist/components/NewComposition/InputDragger.d.ts +6 -0
  12. package/dist/components/NewComposition/InputDragger.js +40 -14
  13. package/dist/components/NewComposition/RenameComposition.js +8 -1
  14. package/dist/components/NewComposition/RenameFolder.js +8 -1
  15. package/dist/components/NewComposition/RenameStaticFile.js +11 -1
  16. package/dist/components/Notifications/Notification.js +5 -4
  17. package/dist/components/Notifications/NotificationCenter.js +1 -1
  18. package/dist/components/ObserveDefaultPropsContext.js +6 -2
  19. package/dist/components/OutlineToggle.js +1 -1
  20. package/dist/components/PlayPause.js +22 -66
  21. package/dist/components/PreviewToolbar.js +15 -1
  22. package/dist/components/RenderModal/RenderModalJSONPropsEditor.js +2 -1
  23. package/dist/components/SelectedOutlineElement.d.ts +17 -0
  24. package/dist/components/SelectedOutlineElement.js +938 -0
  25. package/dist/components/SelectedOutlineOverlay.d.ts +4 -174
  26. package/dist/components/SelectedOutlineOverlay.js +310 -1392
  27. package/dist/components/SelectedOutlineUvControls.js +1 -1
  28. package/dist/components/ShowGuidesProvider.js +4 -4
  29. package/dist/components/Timeline/SubscribeToNodePaths.d.ts +2 -1
  30. package/dist/components/Timeline/SubscribeToNodePaths.js +2 -1
  31. package/dist/components/Timeline/Timeline.js +3 -1
  32. package/dist/components/Timeline/TimelineClipboardKeybindings.js +9 -10
  33. package/dist/components/Timeline/TimelineDeleteKeybindings.js +15 -4
  34. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +7 -11
  35. package/dist/components/Timeline/TimelineList.js +1 -1
  36. package/dist/components/Timeline/TimelineRotationField.js +17 -17
  37. package/dist/components/Timeline/TimelineScaleField.js +1 -1
  38. package/dist/components/Timeline/TimelineSelection.d.ts +27 -13
  39. package/dist/components/Timeline/TimelineSelection.js +47 -28
  40. package/dist/components/Timeline/TimelineSequence.js +169 -8
  41. package/dist/components/Timeline/TimelineSequenceFrame.d.ts +1 -0
  42. package/dist/components/Timeline/TimelineSequenceFrame.js +17 -6
  43. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
  44. package/dist/components/Timeline/TimelineSequenceItem.js +294 -142
  45. package/dist/components/Timeline/TimelineSequenceName.d.ts +4 -2
  46. package/dist/components/Timeline/TimelineSequenceName.js +67 -2
  47. package/dist/components/Timeline/TimelineTransformOriginField.js +1 -1
  48. package/dist/components/Timeline/TimelineTranslateField.js +1 -1
  49. package/dist/components/Timeline/TimelineUvCoordinateField.js +1 -1
  50. package/dist/components/Timeline/delete-selected-timeline-item.js +4 -0
  51. package/dist/components/Timeline/disable-sequence-interactivity.d.ts +8 -0
  52. package/dist/components/Timeline/disable-sequence-interactivity.js +24 -0
  53. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +1 -2
  54. package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +20 -0
  55. package/dist/components/Timeline/get-sequence-context-menu-items.js +160 -0
  56. package/dist/components/Timeline/reset-selected-timeline-props.js +2 -2
  57. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +2 -1
  58. package/dist/components/Timeline/sequence-props-subscription-store.js +11 -3
  59. package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +2 -0
  60. package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +16 -2
  61. package/dist/components/Timeline/timeline-rotation-utils.d.ts +1 -1
  62. package/dist/components/Timeline/timeline-rotation-utils.js +4 -2
  63. package/dist/components/Timeline/update-selected-easing.d.ts +4 -6
  64. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +2 -1
  65. package/dist/components/Timeline/use-sequence-props-subscription.js +3 -1
  66. package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +37 -1
  67. package/dist/components/Timeline/use-timeline-keyframe-drag.js +290 -14
  68. package/dist/components/import-assets.d.ts +36 -8
  69. package/dist/components/import-assets.js +170 -10
  70. package/dist/components/selected-outline-drag.d.ts +117 -0
  71. package/dist/components/selected-outline-drag.js +427 -0
  72. package/dist/components/selected-outline-measurement.d.ts +67 -0
  73. package/dist/components/selected-outline-measurement.js +355 -0
  74. package/dist/components/selected-outline-types.d.ts +121 -0
  75. package/dist/components/selected-outline-types.js +15 -0
  76. package/dist/components/selected-outline-uv.d.ts +1 -0
  77. package/dist/components/selected-outline-uv.js +12 -0
  78. package/dist/esm/{chunk-qaqqvw4q.js → chunk-t8fjnw2d.js} +14059 -12029
  79. package/dist/esm/internals.mjs +14059 -12029
  80. package/dist/esm/previewEntry.mjs +14066 -12036
  81. package/dist/esm/renderEntry.mjs +1 -1
  82. package/dist/helpers/editor-guide-selection.d.ts +31 -0
  83. package/dist/helpers/editor-guide-selection.js +58 -0
  84. package/dist/helpers/editor-ruler.d.ts +3 -3
  85. package/dist/helpers/editor-ruler.js +16 -18
  86. package/dist/state/editor-guides.d.ts +2 -2
  87. package/dist/state/editor-guides.js +2 -2
  88. package/package.json +11 -11
@@ -1,13 +1,46 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.TimelineSequenceItem = void 0;
4
37
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
38
+ const react_1 = __importStar(require("react"));
6
39
  const remotion_1 = require("remotion");
7
- const no_react_1 = require("remotion/no-react");
8
40
  const client_id_1 = require("../../helpers/client-id");
9
41
  const format_file_location_1 = require("../../helpers/format-file-location");
10
42
  const timeline_layout_1 = require("../../helpers/timeline-layout");
43
+ const use_keybinding_1 = require("../../helpers/use-keybinding");
11
44
  const call_api_1 = require("../call-api");
12
45
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
13
46
  const ContextMenu_1 = require("../ContextMenu");
@@ -16,7 +49,9 @@ const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
16
49
  const layout_1 = require("../layout");
17
50
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
18
51
  const use_select_asset_1 = require("../use-select-asset");
52
+ const disable_sequence_interactivity_1 = require("./disable-sequence-interactivity");
19
53
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
54
+ const get_sequence_context_menu_items_1 = require("./get-sequence-context-menu-items");
20
55
  const save_sequence_prop_1 = require("./save-sequence-prop");
21
56
  const timeline_asset_link_1 = require("./timeline-asset-link");
22
57
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
@@ -102,22 +137,26 @@ const getSequenceReorderDragData = (dataTransfer) => {
102
137
  const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
103
138
  return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
104
139
  };
105
- const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, trackIndex, }) => {
106
- var _a, _b;
107
- var _c, _d;
108
- const nodePath = (_c = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _c !== void 0 ? _c : null;
140
+ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, sequenceFrameOffset, trackIndex, }) => {
141
+ var _a, _b, _c;
142
+ var _d, _e;
143
+ const nodePath = (_d = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _d !== void 0 ? _d : null;
109
144
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
110
145
  const previewConnected = previewServerState.type === 'connected';
111
146
  const { getIsExpanded } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksGetterContext);
112
147
  const { toggleTrack } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksSetterContext);
113
148
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
114
149
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
150
+ const { isHighestContext } = (0, use_keybinding_1.useKeybinding)();
115
151
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
116
152
  const { onSelect, selectable, selected } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
153
+ const { selectedItems } = (0, TimelineSelection_1.useTimelineSelection)();
117
154
  const containsSelection = (0, TimelineSelection_1.useTimelineRowContainsSelection)(nodePathInfo);
118
155
  const [effectDropHovered, setEffectDropHovered] = (0, react_1.useState)(false);
156
+ const [isRenaming, setIsRenaming] = (0, react_1.useState)(false);
119
157
  const [sequenceDropIndicator, setSequenceDropIndicator] = (0, react_1.useState)(null);
120
158
  const [sequenceDropRejection, setSequenceDropRejection] = (0, react_1.useState)(null);
159
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
121
160
  const { canOpenInEditor, openInEditor, originalLocation } = (0, use_open_sequence_in_editor_1.useOpenSequenceInEditor)(sequence);
122
161
  const fileLocation = (0, react_1.useMemo)(() => (0, format_file_location_1.formatFileLocation)({
123
162
  location: originalLocation,
@@ -138,7 +177,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
138
177
  }, [originalLocation]);
139
178
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
140
179
  const nodePathKey = (0, react_1.useMemo)(() => nodePath ? remotion_1.Internals.makeSequencePropsSubscriptionKey(nodePath) : null, [nodePath]);
141
- const parentId = (_d = sequence.parent) !== null && _d !== void 0 ? _d : null;
180
+ const parentId = (_e = sequence.parent) !== null && _e !== void 0 ? _e : null;
142
181
  const canReorderSequence = previewConnected &&
143
182
  Boolean(nodePath && nodePathKey && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) &&
144
183
  (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) === 1;
@@ -146,6 +185,10 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
146
185
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
147
186
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
148
187
  const duplicateDisabled = deleteDisabled;
188
+ const disableInteractivityDisabled = !previewConnected ||
189
+ !sequence.showInTimeline ||
190
+ !nodePath ||
191
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source);
149
192
  const onDuplicateSequenceFromSource = (0, react_1.useCallback)(() => {
150
193
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePathInfo) {
151
194
  return;
@@ -188,6 +231,26 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
188
231
  (0, NotificationCenter_1.showNotification)(err.message, 4000);
189
232
  }
190
233
  }, [confirm, nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source, nodePathInfo]);
234
+ const onDisableSequenceInteractivity = (0, react_1.useCallback)(() => {
235
+ if (disableInteractivityDisabled ||
236
+ !nodePath ||
237
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) ||
238
+ previewServerState.type !== 'connected') {
239
+ return;
240
+ }
241
+ (0, disable_sequence_interactivity_1.disableSequenceInteractivity)({
242
+ fileName: validatedLocation.source,
243
+ nodePath,
244
+ setPropStatuses,
245
+ clientId: previewServerState.clientId,
246
+ });
247
+ }, [
248
+ disableInteractivityDisabled,
249
+ nodePath,
250
+ previewServerState,
251
+ setPropStatuses,
252
+ validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
253
+ ]);
191
254
  const getSequenceDropTarget = (0, react_1.useCallback)((e) => {
192
255
  const dragData = getSequenceReorderDragData(e.dataTransfer);
193
256
  if (!dragData) {
@@ -354,139 +417,6 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
354
417
  ? sequence.src
355
418
  : null;
356
419
  const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
357
- const contextMenuValues = (0, react_1.useMemo)(() => {
358
- if (!previewConnected) {
359
- return [];
360
- }
361
- const editorName = window.remotion_editorName;
362
- const { documentationLink } = sequence;
363
- return [
364
- editorName
365
- ? {
366
- type: 'item',
367
- id: 'show-in-editor',
368
- keyHint: null,
369
- label: `Show in ${editorName}`,
370
- leftItem: null,
371
- disabled: !canOpenInEditor,
372
- onClick: () => {
373
- openInEditor();
374
- },
375
- quickSwitcherLabel: null,
376
- subMenu: null,
377
- value: 'show-in-editor',
378
- }
379
- : null,
380
- {
381
- type: 'item',
382
- id: 'copy-file-location',
383
- keyHint: null,
384
- label: 'Copy file location',
385
- leftItem: null,
386
- disabled: !fileLocation,
387
- onClick: () => {
388
- if (!fileLocation) {
389
- return;
390
- }
391
- navigator.clipboard
392
- .writeText(fileLocation)
393
- .then(() => {
394
- (0, NotificationCenter_1.showNotification)('Copied file location to clipboard', 1000);
395
- })
396
- .catch((err) => {
397
- (0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
398
- });
399
- },
400
- quickSwitcherLabel: null,
401
- subMenu: null,
402
- value: 'copy-file-location',
403
- },
404
- documentationLink
405
- ? {
406
- type: 'item',
407
- id: 'open-component-docs',
408
- keyHint: null,
409
- label: 'Open component docs',
410
- leftItem: null,
411
- disabled: false,
412
- onClick: () => {
413
- window.open(documentationLink, '_blank', 'noopener,noreferrer');
414
- },
415
- quickSwitcherLabel: null,
416
- subMenu: null,
417
- value: 'open-component-docs',
418
- }
419
- : null,
420
- assetLinkInfo
421
- ? {
422
- type: 'item',
423
- id: 'show-asset',
424
- keyHint: null,
425
- label: 'Show asset',
426
- leftItem: null,
427
- disabled: false,
428
- onClick: () => {
429
- (0, timeline_asset_link_1.openTimelineAssetLink)(assetLinkInfo, selectAsset);
430
- },
431
- quickSwitcherLabel: null,
432
- subMenu: null,
433
- value: 'show-asset',
434
- }
435
- : null,
436
- documentationLink
437
- ? {
438
- type: 'divider',
439
- id: 'open-component-docs-divider',
440
- }
441
- : null,
442
- {
443
- type: 'item',
444
- id: 'duplicate-sequence',
445
- keyHint: null,
446
- label: 'Duplicate',
447
- leftItem: null,
448
- disabled: duplicateDisabled,
449
- onClick: () => {
450
- if (duplicateDisabled) {
451
- return;
452
- }
453
- onDuplicateSequenceFromSource();
454
- },
455
- quickSwitcherLabel: null,
456
- subMenu: null,
457
- value: 'duplicate-sequence',
458
- },
459
- {
460
- type: 'item',
461
- id: 'delete-sequence',
462
- keyHint: null,
463
- label: 'Delete',
464
- leftItem: null,
465
- disabled: deleteDisabled,
466
- onClick: () => {
467
- if (deleteDisabled) {
468
- return;
469
- }
470
- onDeleteSequenceFromSource();
471
- },
472
- quickSwitcherLabel: null,
473
- subMenu: null,
474
- value: 'delete-sequence',
475
- },
476
- ].filter(no_react_1.NoReactInternals.truthy);
477
- }, [
478
- assetLinkInfo,
479
- deleteDisabled,
480
- duplicateDisabled,
481
- fileLocation,
482
- onDeleteSequenceFromSource,
483
- onDuplicateSequenceFromSource,
484
- canOpenInEditor,
485
- openInEditor,
486
- previewConnected,
487
- selectAsset,
488
- sequence,
489
- ]);
490
420
  const isExpanded = previewConnected && nodePathInfo !== null && getIsExpanded(nodePathInfo);
491
421
  const onToggleExpand = (0, react_1.useCallback)(() => {
492
422
  if (nodePathInfo === null) {
@@ -511,6 +441,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
511
441
  : undefined;
512
442
  }, [propStatuses, nodePath]);
513
443
  const codeHiddenStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.hidden;
444
+ const codeNameStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.name;
514
445
  const isItemHidden = (0, react_1.useMemo)(() => {
515
446
  var _a;
516
447
  const propStatus = codeHiddenStatus && codeHiddenStatus.status === 'static'
@@ -520,6 +451,14 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
520
451
  const effective = (propStatus !== null && propStatus !== void 0 ? propStatus : runtimeValue);
521
452
  return effective !== null && effective !== void 0 ? effective : false;
522
453
  }, [codeHiddenStatus, (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation]);
454
+ const displayName = (0, react_1.useMemo)(() => {
455
+ if (codeNameStatus &&
456
+ codeNameStatus.status === 'static' &&
457
+ typeof codeNameStatus.codeValue === 'string') {
458
+ return codeNameStatus.codeValue;
459
+ }
460
+ return sequence.displayName;
461
+ }, [codeNameStatus, sequence.displayName]);
523
462
  const onToggleVisibility = (0, react_1.useCallback)((type) => {
524
463
  if (!sequence.controls ||
525
464
  !nodePath ||
@@ -588,10 +527,223 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
588
527
  codeHiddenStatus !== undefined &&
589
528
  codeHiddenStatus !== null &&
590
529
  codeHiddenStatus.status === 'static';
530
+ const canRenameThisSequence = previewServerState.type === 'connected' &&
531
+ !window.remotion_isReadOnlyStudio &&
532
+ Boolean(sequence.controls) &&
533
+ nodePath !== null &&
534
+ validatedLocation !== null &&
535
+ codeNameStatus !== undefined &&
536
+ codeNameStatus !== null &&
537
+ codeNameStatus.status === 'static';
538
+ const canRenameSelectedSequence = canRenameThisSequence &&
539
+ selected &&
540
+ selectedItems.length === 1 &&
541
+ ((_b = selectedItems[0]) === null || _b === void 0 ? void 0 : _b.type) === 'sequence';
542
+ const onCancelRenaming = (0, react_1.useCallback)(() => {
543
+ setIsRenaming(false);
544
+ }, []);
545
+ const onSaveName = (0, react_1.useCallback)(async (name) => {
546
+ if (!canRenameThisSequence ||
547
+ previewServerState.type !== 'connected' ||
548
+ !sequence.controls ||
549
+ !nodePath ||
550
+ !validatedLocation) {
551
+ setIsRenaming(false);
552
+ return;
553
+ }
554
+ if (name === displayName) {
555
+ setIsRenaming(false);
556
+ return;
557
+ }
558
+ const savePromise = (0, save_sequence_prop_1.saveSequenceProps)({
559
+ changes: [
560
+ {
561
+ fileName: validatedLocation.source,
562
+ nodePath,
563
+ fieldKey: 'name',
564
+ value: name,
565
+ defaultValue: null,
566
+ schema: sequence.controls.schema,
567
+ },
568
+ ],
569
+ setPropStatuses,
570
+ clientId: previewServerState.clientId,
571
+ undoLabel: 'Rename sequence',
572
+ redoLabel: 'Rename sequence again',
573
+ });
574
+ setIsRenaming(false);
575
+ await savePromise;
576
+ }, [
577
+ canRenameThisSequence,
578
+ displayName,
579
+ nodePath,
580
+ previewServerState,
581
+ sequence.controls,
582
+ setPropStatuses,
583
+ validatedLocation,
584
+ ]);
585
+ react_1.default.useEffect(() => {
586
+ if (!canRenameSelectedSequence || !process.env.KEYBOARD_SHORTCUTS_ENABLED) {
587
+ setIsRenaming(false);
588
+ return;
589
+ }
590
+ const onKeyDown = (e) => {
591
+ if (!isHighestContext) {
592
+ return;
593
+ }
594
+ const commandKey = window.navigator.platform.startsWith('Mac')
595
+ ? e.metaKey
596
+ : e.ctrlKey;
597
+ if (commandKey || e.key.toLowerCase() !== 'enter') {
598
+ return;
599
+ }
600
+ if (document.activeElement instanceof HTMLInputElement ||
601
+ document.activeElement instanceof HTMLTextAreaElement) {
602
+ return;
603
+ }
604
+ e.preventDefault();
605
+ e.stopImmediatePropagation();
606
+ setIsRenaming(true);
607
+ };
608
+ window.addEventListener('keydown', onKeyDown, true);
609
+ return () => {
610
+ window.removeEventListener('keydown', onKeyDown, true);
611
+ };
612
+ }, [canRenameSelectedSequence, isHighestContext]);
613
+ const onRenameSequence = (0, react_1.useCallback)(() => {
614
+ if (!canRenameThisSequence) {
615
+ return;
616
+ }
617
+ setIsRenaming(true);
618
+ }, [canRenameThisSequence]);
619
+ const freezeStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.freeze;
620
+ const isFrozen = (freezeStatus === null || freezeStatus === void 0 ? void 0 : freezeStatus.status) === 'static' &&
621
+ typeof freezeStatus.codeValue === 'number';
622
+ const canToggleFreeze = previewConnected &&
623
+ Boolean(sequence.controls) &&
624
+ nodePath !== null &&
625
+ validatedLocation !== null &&
626
+ freezeStatus !== undefined &&
627
+ freezeStatus !== null &&
628
+ freezeStatus.status === 'static';
629
+ const onToggleFreezeFrame = (0, react_1.useCallback)(() => {
630
+ if (!canToggleFreeze ||
631
+ !sequence.controls ||
632
+ !nodePath ||
633
+ !validatedLocation ||
634
+ previewServerState.type !== 'connected') {
635
+ return;
636
+ }
637
+ const rawFreezeFrame = Math.round(timelinePosition - sequence.from + sequenceFrameOffset);
638
+ const maxFrame = Number.isFinite(sequence.duration)
639
+ ? Math.max(0, sequence.duration - 1)
640
+ : rawFreezeFrame;
641
+ const freezeFrame = Math.min(Math.max(0, rawFreezeFrame), maxFrame);
642
+ const remove = isFrozen;
643
+ (0, save_sequence_prop_1.saveSequenceProps)({
644
+ changes: [
645
+ {
646
+ fileName: validatedLocation.source,
647
+ nodePath,
648
+ fieldKey: 'freeze',
649
+ value: remove ? null : freezeFrame,
650
+ defaultValue: null,
651
+ schema: sequence.controls.schema,
652
+ },
653
+ ],
654
+ setPropStatuses,
655
+ clientId: previewServerState.clientId,
656
+ undoLabel: remove ? 'Unfreeze sequence' : 'Freeze sequence',
657
+ redoLabel: remove ? 'Freeze sequence again' : 'Unfreeze sequence again',
658
+ });
659
+ }, [
660
+ canToggleFreeze,
661
+ isFrozen,
662
+ nodePath,
663
+ previewServerState,
664
+ sequence.controls,
665
+ sequence.duration,
666
+ sequence.from,
667
+ sequenceFrameOffset,
668
+ setPropStatuses,
669
+ timelinePosition,
670
+ validatedLocation,
671
+ ]);
672
+ const contextMenuValues = (0, react_1.useMemo)(() => {
673
+ if (!previewConnected) {
674
+ return [];
675
+ }
676
+ return (0, get_sequence_context_menu_items_1.getSequenceContextMenuItems)({
677
+ assetLinkInfo,
678
+ canOpenInEditor,
679
+ deleteDisabled,
680
+ disableInteractivityDisabled,
681
+ duplicateDisabled,
682
+ fileLocation,
683
+ includeSourceEditItems: true,
684
+ onDeleteSequenceFromSource,
685
+ onDisableSequenceInteractivity,
686
+ onDuplicateSequenceFromSource,
687
+ openInEditor,
688
+ originalLocation,
689
+ selectAsset,
690
+ sequence,
691
+ sourceActions: [
692
+ {
693
+ type: 'item',
694
+ id: 'rename-sequence',
695
+ keyHint: null,
696
+ label: 'Rename...',
697
+ leftItem: null,
698
+ disabled: !canRenameThisSequence,
699
+ onClick: () => {
700
+ onRenameSequence();
701
+ },
702
+ quickSwitcherLabel: null,
703
+ subMenu: null,
704
+ value: 'rename-sequence',
705
+ },
706
+ {
707
+ type: 'item',
708
+ id: 'toggle-freeze-frame',
709
+ keyHint: null,
710
+ label: isFrozen ? 'Unfreeze frame' : 'Freeze frame',
711
+ leftItem: null,
712
+ disabled: !canToggleFreeze,
713
+ onClick: () => {
714
+ onToggleFreezeFrame();
715
+ },
716
+ quickSwitcherLabel: null,
717
+ subMenu: null,
718
+ value: 'toggle-freeze-frame',
719
+ },
720
+ ],
721
+ });
722
+ }, [
723
+ assetLinkInfo,
724
+ canOpenInEditor,
725
+ canRenameThisSequence,
726
+ canToggleFreeze,
727
+ deleteDisabled,
728
+ disableInteractivityDisabled,
729
+ duplicateDisabled,
730
+ fileLocation,
731
+ isFrozen,
732
+ onDeleteSequenceFromSource,
733
+ onDisableSequenceInteractivity,
734
+ onDuplicateSequenceFromSource,
735
+ onRenameSequence,
736
+ onToggleFreezeFrame,
737
+ openInEditor,
738
+ originalLocation,
739
+ previewConnected,
740
+ selectAsset,
741
+ sequence,
742
+ ]);
591
743
  const canDropEffect = previewServerState.type === 'connected' &&
592
744
  nodePath !== null &&
593
745
  validatedLocation !== null &&
594
- ((_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.supportsEffects) === true;
746
+ ((_c = sequence.controls) === null || _c === void 0 ? void 0 : _c.supportsEffects) === true;
595
747
  const sequenceReorderLineStyle = (0, react_1.useMemo)(() => {
596
748
  if (!sequenceDropIndicator) {
597
749
  return null;
@@ -647,7 +799,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
647
799
  });
648
800
  }, [canDropEffect, nodePath, previewServerState, validatedLocation]);
649
801
  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: [
802
+ jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { displayName: displayName, selected: selected, containsSelection: containsSelection, editing: isRenaming, onCancelEditing: onCancelRenaming, onSaveName: onSaveName }), mediaSrc ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
651
803
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }),
652
804
  " ",
653
805
  jsx_runtime_1.jsx(TimelineMediaInfo_1.TimelineMediaInfo, { src: mediaSrc })
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
- import type { TSequence } from 'remotion';
3
2
  export declare const TimelineSequenceName: React.FC<{
4
- readonly sequence: TSequence;
3
+ readonly displayName: string;
5
4
  readonly selected: boolean;
6
5
  readonly containsSelection: boolean;
6
+ readonly editing: boolean;
7
+ readonly onCancelEditing: () => void;
8
+ readonly onSaveName: (name: string) => Promise<void>;
7
9
  }>;
@@ -5,13 +5,18 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const TimelineSelection_1 = require("./TimelineSelection");
7
7
  const MAX_DISPLAY_NAME_LENGTH = 1000;
8
+ const MAX_RENAME_INPUT_WIDTH = 240;
9
+ const RENAME_INPUT_CLASS_NAME = 'remotion-timeline-sequence-name-input';
8
10
  const getTruncatedDisplayName = (displayName) => {
9
11
  if (displayName.length > MAX_DISPLAY_NAME_LENGTH) {
10
12
  return displayName.slice(0, MAX_DISPLAY_NAME_LENGTH) + '...';
11
13
  }
12
14
  return displayName;
13
15
  };
14
- const TimelineSequenceName = ({ sequence, selected, containsSelection }) => {
16
+ const TimelineSequenceName = ({ displayName, selected, containsSelection, editing, onCancelEditing, onSaveName, }) => {
17
+ const inputRef = (0, react_1.useRef)(null);
18
+ const [draftName, setDraftName] = (0, react_1.useState)(displayName);
19
+ const cancelNextBlurRef = (0, react_1.useRef)(false);
15
20
  const style = (0, react_1.useMemo)(() => {
16
21
  return {
17
22
  alignItems: 'center',
@@ -30,7 +35,67 @@ const TimelineSequenceName = ({ sequence, selected, containsSelection }) => {
30
35
  : undefined,
31
36
  };
32
37
  }, [selected, containsSelection]);
33
- const text = getTruncatedDisplayName(sequence.displayName) || '<Sequence>';
38
+ const inputStyle = (0, react_1.useMemo)(() => {
39
+ return {
40
+ ...style,
41
+ background: 'transparent',
42
+ border: 0,
43
+ color: (0, TimelineSelection_1.getTimelineColor)(false, false),
44
+ fontFamily: 'inherit',
45
+ fontSize: 12,
46
+ outline: 'none',
47
+ paddingBottom: 0,
48
+ paddingTop: 0,
49
+ boxSizing: 'border-box',
50
+ maxWidth: MAX_RENAME_INPUT_WIDTH,
51
+ minWidth: 0,
52
+ userSelect: 'text',
53
+ WebkitUserSelect: 'text',
54
+ };
55
+ }, [style]);
56
+ const text = getTruncatedDisplayName(displayName) || '<Sequence>';
57
+ (0, react_1.useEffect)(() => {
58
+ if (!editing) {
59
+ setDraftName(displayName);
60
+ return;
61
+ }
62
+ const input = inputRef.current;
63
+ if (!input) {
64
+ return;
65
+ }
66
+ input.focus();
67
+ const basenameIndex = displayName.lastIndexOf('.');
68
+ const selectionEnd = basenameIndex > 0 ? basenameIndex : displayName.length;
69
+ input.setSelectionRange(0, selectionEnd);
70
+ }, [displayName, editing]);
71
+ const save = (0, react_1.useCallback)(() => {
72
+ onSaveName(draftName).catch(() => undefined);
73
+ }, [draftName, onSaveName]);
74
+ const onKeyDown = (0, react_1.useCallback)((e) => {
75
+ if (e.key === 'Escape') {
76
+ cancelNextBlurRef.current = true;
77
+ e.preventDefault();
78
+ onCancelEditing();
79
+ return;
80
+ }
81
+ if (e.key === 'Enter') {
82
+ cancelNextBlurRef.current = true;
83
+ e.preventDefault();
84
+ save();
85
+ }
86
+ }, [onCancelEditing, save]);
87
+ const onBlur = (0, react_1.useCallback)(() => {
88
+ if (cancelNextBlurRef.current) {
89
+ cancelNextBlurRef.current = false;
90
+ return;
91
+ }
92
+ save();
93
+ }, [save]);
94
+ if (editing) {
95
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
96
+ jsx_runtime_1.jsx("style", { children: `.${RENAME_INPUT_CLASS_NAME}::selection { background: rgba(255, 255, 255, 0.72); color: black; }` }), jsx_runtime_1.jsx("input", { ref: inputRef, className: RENAME_INPUT_CLASS_NAME, value: draftName, onChange: (e) => setDraftName(e.target.value), onBlur: onBlur, onKeyDown: onKeyDown, size: Math.max(1, draftName.length), style: inputStyle })
97
+ ] }));
98
+ }
34
99
  return (jsx_runtime_1.jsx("div", { title: text, style: style, children: text }));
35
100
  };
36
101
  exports.TimelineSequenceName = TimelineSequenceName;
@@ -132,7 +132,7 @@ const TimelineTransformOriginField = ({ field, propStatus, effectiveValue, onSav
132
132
  return jsx_runtime_1.jsx(TimelineSchemaField_1.UnsupportedStatus, { label: "unsupported origin" });
133
133
  }
134
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 })
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, dragDecimalPlaces: decimalPlaces }), 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, dragDecimalPlaces: decimalPlaces })
136
136
  ] }));
137
137
  };
138
138
  exports.TimelineTransformOriginField = TimelineTransformOriginField;
@@ -101,7 +101,7 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
101
101
  }
102
102
  }, [propStatus, onSave, dragX, codeX, decimalPlaces]);
103
103
  return (jsx_runtime_1.jsxs("span", { style: containerStyle, children: [
104
- jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: 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 : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false })
104
+ jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false, snapToStep: false, dragDecimalPlaces: decimalPlaces }), 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 : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false, snapToStep: false, dragDecimalPlaces: decimalPlaces })
105
105
  ] }));
106
106
  };
107
107
  exports.TimelineTranslateField = TimelineTranslateField;
@@ -120,7 +120,7 @@ const TimelineUvCoordinateField = ({ field, propStatus, effectiveValue, onSave,
120
120
  }
121
121
  }, [propStatus, onSave, dragX, codeX]);
122
122
  return (jsx_runtime_1.jsxs("span", { style: containerStyle, children: [
123
- jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: min, max: max, 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 : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: min, max: max, step: step, formatter: formatter, rightAlign: false, snapToStep: false })
123
+ jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: min, max: max, step: step, formatter: formatter, rightAlign: false, snapToStep: false, dragDecimalPlaces: decimalPlaces }), 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 : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: min, max: max, step: step, formatter: formatter, rightAlign: false, snapToStep: false, dragDecimalPlaces: decimalPlaces })
124
124
  ] }));
125
125
  };
126
126
  exports.TimelineUvCoordinateField = TimelineUvCoordinateField;