@remotion/studio 4.0.475 → 4.0.476

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 (36) hide show
  1. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +6 -0
  2. package/dist/components/ColorPicker/ColorPickerPopup.js +11 -6
  3. package/dist/components/GlobalKeybindings.js +12 -0
  4. package/dist/components/KeyboardShortcutsExplainer.js +24 -0
  5. package/dist/components/NewComposition/InputDragger.d.ts +6 -0
  6. package/dist/components/NewComposition/InputDragger.js +40 -14
  7. package/dist/components/NewComposition/RenameComposition.js +8 -1
  8. package/dist/components/NewComposition/RenameFolder.js +8 -1
  9. package/dist/components/NewComposition/RenameStaticFile.js +11 -1
  10. package/dist/components/Notifications/Notification.js +5 -4
  11. package/dist/components/Notifications/NotificationCenter.js +1 -1
  12. package/dist/components/ObserveDefaultPropsContext.js +6 -2
  13. package/dist/components/PlayPause.js +22 -66
  14. package/dist/components/PreviewToolbar.js +15 -1
  15. package/dist/components/RenderModal/RenderModalJSONPropsEditor.js +2 -1
  16. package/dist/components/SelectedOutlineOverlay.d.ts +47 -11
  17. package/dist/components/SelectedOutlineOverlay.js +545 -54
  18. package/dist/components/Timeline/TimelineRotationField.js +17 -17
  19. package/dist/components/Timeline/TimelineScaleField.js +1 -1
  20. package/dist/components/Timeline/TimelineSequenceItem.js +301 -109
  21. package/dist/components/Timeline/TimelineSequenceName.d.ts +4 -2
  22. package/dist/components/Timeline/TimelineSequenceName.js +67 -2
  23. package/dist/components/Timeline/TimelineTransformOriginField.js +1 -1
  24. package/dist/components/Timeline/TimelineTranslateField.js +1 -1
  25. package/dist/components/Timeline/TimelineUvCoordinateField.js +1 -1
  26. package/dist/components/Timeline/disable-sequence-interactivity.d.ts +8 -0
  27. package/dist/components/Timeline/disable-sequence-interactivity.js +24 -0
  28. package/dist/components/Timeline/reset-selected-timeline-props.js +2 -2
  29. package/dist/components/Timeline/timeline-rotation-utils.d.ts +1 -1
  30. package/dist/components/Timeline/timeline-rotation-utils.js +4 -2
  31. package/dist/components/Timeline/use-timeline-keyframe-drag.js +8 -13
  32. package/dist/esm/{chunk-qaqqvw4q.js → chunk-0atarw3p.js} +2659 -1707
  33. package/dist/esm/internals.mjs +2659 -1707
  34. package/dist/esm/previewEntry.mjs +2661 -1709
  35. package/dist/esm/renderEntry.mjs +1 -1
  36. package/package.json +11 -11
@@ -16,11 +16,26 @@ const TimelineRotationField = ({ field, effectiveValue, propStatus, onSave, onDr
16
16
  }
17
17
  return typeof effectiveValue === 'number' ? effectiveValue : 0;
18
18
  }, [effectiveValue, isCssRotation]);
19
+ const configuredStep = field.fieldSchema.type === 'rotation-css' ||
20
+ field.fieldSchema.type === 'rotation-degrees'
21
+ ? field.fieldSchema.step
22
+ : undefined;
23
+ const step = configuredStep !== null && configuredStep !== void 0 ? configuredStep : 1;
24
+ const min = field.fieldSchema.type === 'rotation-degrees'
25
+ ? ((_a = field.fieldSchema.min) !== null && _a !== void 0 ? _a : -Infinity)
26
+ : -Infinity;
27
+ const max = field.fieldSchema.type === 'rotation-degrees'
28
+ ? ((_b = field.fieldSchema.max) !== null && _b !== void 0 ? _b : Infinity)
29
+ : Infinity;
30
+ const decimalPlaces = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getTimelineDisplayDecimalPlaces)({
31
+ defaultDecimalPlaces: 1,
32
+ step: configuredStep,
33
+ }), [configuredStep]);
19
34
  const serializeValue = (0, react_1.useCallback)((value) => {
20
35
  return isCssRotation
21
- ? (0, timeline_rotation_utils_1.serializeCssRotation)(value)
36
+ ? (0, timeline_rotation_utils_1.serializeCssRotation)(value, decimalPlaces)
22
37
  : (0, timeline_field_utils_1.normalizeTimelineNumber)(value);
23
- }, [isCssRotation]);
38
+ }, [decimalPlaces, isCssRotation]);
24
39
  const onValueChange = (0, react_1.useCallback)((newVal) => {
25
40
  setDragValue(newVal);
26
41
  onDragValueChange(serializeValue(newVal));
@@ -50,21 +65,6 @@ const TimelineRotationField = ({ field, effectiveValue, propStatus, onSave, onDr
50
65
  }
51
66
  }
52
67
  }, [propStatus, onSave, serializeValue]);
53
- const configuredStep = field.fieldSchema.type === 'rotation-css' ||
54
- field.fieldSchema.type === 'rotation-degrees'
55
- ? field.fieldSchema.step
56
- : undefined;
57
- const step = configuredStep !== null && configuredStep !== void 0 ? configuredStep : 1;
58
- const min = field.fieldSchema.type === 'rotation-degrees'
59
- ? ((_a = field.fieldSchema.min) !== null && _a !== void 0 ? _a : -Infinity)
60
- : -Infinity;
61
- const max = field.fieldSchema.type === 'rotation-degrees'
62
- ? ((_b = field.fieldSchema.max) !== null && _b !== void 0 ? _b : Infinity)
63
- : Infinity;
64
- const decimalPlaces = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getTimelineDisplayDecimalPlaces)({
65
- defaultDecimalPlaces: 1,
66
- step: configuredStep,
67
- }), [configuredStep]);
68
68
  const formatter = (0, react_1.useCallback)((v) => {
69
69
  const formatted = (0, timeline_field_utils_1.formatTimelineNumber)({
70
70
  decimalPlaces,
@@ -99,7 +99,7 @@ const TimelineScaleField = ({ field, propStatus, effectiveValue, onSave, onDragV
99
99
  ? ((_b = field.fieldSchema.max) !== null && _b !== void 0 ? _b : Infinity)
100
100
  : Infinity;
101
101
  const decimalPlaces = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getTimelineDisplayDecimalPlaces)({
102
- defaultDecimalPlaces: 2,
102
+ defaultDecimalPlaces: 3,
103
103
  step: configuredStep,
104
104
  }), [configuredStep]);
105
105
  const formatter = (0, react_1.useCallback)((v) => {
@@ -1,13 +1,47 @@
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
40
  const no_react_1 = require("remotion/no-react");
8
41
  const client_id_1 = require("../../helpers/client-id");
9
42
  const format_file_location_1 = require("../../helpers/format-file-location");
10
43
  const timeline_layout_1 = require("../../helpers/timeline-layout");
44
+ const use_keybinding_1 = require("../../helpers/use-keybinding");
11
45
  const call_api_1 = require("../call-api");
12
46
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
13
47
  const ContextMenu_1 = require("../ContextMenu");
@@ -16,6 +50,7 @@ const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
16
50
  const layout_1 = require("../layout");
17
51
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
18
52
  const use_select_asset_1 = require("../use-select-asset");
53
+ const disable_sequence_interactivity_1 = require("./disable-sequence-interactivity");
19
54
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
20
55
  const save_sequence_prop_1 = require("./save-sequence-prop");
21
56
  const timeline_asset_link_1 = require("./timeline-asset-link");
@@ -103,19 +138,22 @@ const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
103
138
  return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
104
139
  };
105
140
  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;
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);
121
159
  const { canOpenInEditor, openInEditor, originalLocation } = (0, use_open_sequence_in_editor_1.useOpenSequenceInEditor)(sequence);
@@ -138,7 +176,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
138
176
  }, [originalLocation]);
139
177
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
140
178
  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;
179
+ const parentId = (_e = sequence.parent) !== null && _e !== void 0 ? _e : null;
142
180
  const canReorderSequence = previewConnected &&
143
181
  Boolean(nodePath && nodePathKey && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) &&
144
182
  (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) === 1;
@@ -146,6 +184,10 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
146
184
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
147
185
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
148
186
  const duplicateDisabled = deleteDisabled;
187
+ const disableInteractivityDisabled = !previewConnected ||
188
+ !sequence.showInTimeline ||
189
+ !nodePath ||
190
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source);
149
191
  const onDuplicateSequenceFromSource = (0, react_1.useCallback)(() => {
150
192
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePathInfo) {
151
193
  return;
@@ -188,6 +230,26 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
188
230
  (0, NotificationCenter_1.showNotification)(err.message, 4000);
189
231
  }
190
232
  }, [confirm, nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source, nodePathInfo]);
233
+ const onDisableSequenceInteractivity = (0, react_1.useCallback)(() => {
234
+ if (disableInteractivityDisabled ||
235
+ !nodePath ||
236
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) ||
237
+ previewServerState.type !== 'connected') {
238
+ return;
239
+ }
240
+ (0, disable_sequence_interactivity_1.disableSequenceInteractivity)({
241
+ fileName: validatedLocation.source,
242
+ nodePath,
243
+ setPropStatuses,
244
+ clientId: previewServerState.clientId,
245
+ });
246
+ }, [
247
+ disableInteractivityDisabled,
248
+ nodePath,
249
+ previewServerState,
250
+ setPropStatuses,
251
+ validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
252
+ ]);
191
253
  const getSequenceDropTarget = (0, react_1.useCallback)((e) => {
192
254
  const dragData = getSequenceReorderDragData(e.dataTransfer);
193
255
  if (!dragData) {
@@ -354,6 +416,205 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
354
416
  ? sequence.src
355
417
  : null;
356
418
  const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
419
+ const isExpanded = previewConnected && nodePathInfo !== null && getIsExpanded(nodePathInfo);
420
+ const onToggleExpand = (0, react_1.useCallback)(() => {
421
+ if (nodePathInfo === null) {
422
+ return;
423
+ }
424
+ toggleTrack(nodePathInfo);
425
+ }, [nodePathInfo, toggleTrack]);
426
+ const onShowInEditorDoubleClick = (0, react_1.useCallback)((e) => {
427
+ if (!canOpenInEditor) {
428
+ return;
429
+ }
430
+ if ((0, TimelineSelection_1.isTimelineSelectionModifierEvent)(e)) {
431
+ e.stopPropagation();
432
+ return;
433
+ }
434
+ e.stopPropagation();
435
+ openInEditor();
436
+ }, [canOpenInEditor, openInEditor]);
437
+ const propStatusesForOverride = (0, react_1.useMemo)(() => {
438
+ return nodePath
439
+ ? remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)
440
+ : undefined;
441
+ }, [propStatuses, nodePath]);
442
+ const codeHiddenStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.hidden;
443
+ const codeNameStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.name;
444
+ const isItemHidden = (0, react_1.useMemo)(() => {
445
+ var _a;
446
+ const propStatus = codeHiddenStatus && codeHiddenStatus.status === 'static'
447
+ ? codeHiddenStatus.codeValue
448
+ : undefined;
449
+ const runtimeValue = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation.hidden;
450
+ const effective = (propStatus !== null && propStatus !== void 0 ? propStatus : runtimeValue);
451
+ return effective !== null && effective !== void 0 ? effective : false;
452
+ }, [codeHiddenStatus, (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation]);
453
+ const displayName = (0, react_1.useMemo)(() => {
454
+ if (codeNameStatus &&
455
+ codeNameStatus.status === 'static' &&
456
+ typeof codeNameStatus.codeValue === 'string') {
457
+ return codeNameStatus.codeValue;
458
+ }
459
+ return sequence.displayName;
460
+ }, [codeNameStatus, sequence.displayName]);
461
+ const onToggleVisibility = (0, react_1.useCallback)((type) => {
462
+ if (!sequence.controls ||
463
+ !nodePath ||
464
+ !validatedLocation ||
465
+ !propStatusesForOverride ||
466
+ !codeHiddenStatus ||
467
+ codeHiddenStatus.status !== 'static' ||
468
+ previewServerState.type !== 'connected') {
469
+ return;
470
+ }
471
+ const newValue = type !== 'enable';
472
+ const { schema } = sequence.controls;
473
+ const fieldSchema = schema.hidden;
474
+ const defaultValue = fieldSchema && fieldSchema.type === 'boolean'
475
+ ? JSON.stringify(fieldSchema.default)
476
+ : null;
477
+ (0, save_sequence_prop_1.saveSequenceProps)({
478
+ changes: [
479
+ {
480
+ fileName: validatedLocation.source,
481
+ nodePath,
482
+ fieldKey: 'hidden',
483
+ value: newValue,
484
+ defaultValue,
485
+ schema,
486
+ },
487
+ ],
488
+ setPropStatuses,
489
+ clientId: previewServerState.clientId,
490
+ undoLabel: newValue ? 'Hide sequence' : 'Show sequence',
491
+ redoLabel: newValue ? 'Hide sequence again' : 'Show sequence again',
492
+ });
493
+ }, [
494
+ codeHiddenStatus,
495
+ propStatusesForOverride,
496
+ nodePath,
497
+ previewServerState,
498
+ sequence.controls,
499
+ setPropStatuses,
500
+ validatedLocation,
501
+ ]);
502
+ const outerHeight = (0, react_1.useMemo)(() => (0, timeline_layout_1.getTimelineLayerHeight)(sequence.type) + timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM, [sequence.type]);
503
+ const inner = (0, react_1.useMemo)(() => {
504
+ return {
505
+ height: timeline_layout_1.TIMELINE_LIST_ITEM_ROW_HEIGHT,
506
+ color: 'white',
507
+ fontFamily: 'Arial, Helvetica, sans-serif',
508
+ wordBreak: 'break-all',
509
+ textAlign: 'left',
510
+ flexShrink: 0,
511
+ };
512
+ }, []);
513
+ const rowStyle = (0, react_1.useMemo)(() => {
514
+ return effectDropHovered
515
+ ? {
516
+ ...inner,
517
+ ...effectDropHighlight,
518
+ }
519
+ : inner;
520
+ }, [effectDropHovered, inner]);
521
+ const hasExpandableContent = Boolean(sequence.controls) || sequence.effects.length > 0;
522
+ const canToggleVisibility = previewConnected &&
523
+ Boolean(sequence.controls) &&
524
+ nodePath !== null &&
525
+ validatedLocation !== null &&
526
+ codeHiddenStatus !== undefined &&
527
+ codeHiddenStatus !== null &&
528
+ codeHiddenStatus.status === 'static';
529
+ const canRenameThisSequence = previewServerState.type === 'connected' &&
530
+ !window.remotion_isReadOnlyStudio &&
531
+ Boolean(sequence.controls) &&
532
+ nodePath !== null &&
533
+ validatedLocation !== null &&
534
+ codeNameStatus !== undefined &&
535
+ codeNameStatus !== null &&
536
+ codeNameStatus.status === 'static';
537
+ const canRenameSelectedSequence = canRenameThisSequence &&
538
+ selected &&
539
+ selectedItems.length === 1 &&
540
+ ((_b = selectedItems[0]) === null || _b === void 0 ? void 0 : _b.type) === 'sequence';
541
+ const onCancelRenaming = (0, react_1.useCallback)(() => {
542
+ setIsRenaming(false);
543
+ }, []);
544
+ const onSaveName = (0, react_1.useCallback)(async (name) => {
545
+ if (!canRenameThisSequence ||
546
+ previewServerState.type !== 'connected' ||
547
+ !sequence.controls ||
548
+ !nodePath ||
549
+ !validatedLocation) {
550
+ setIsRenaming(false);
551
+ return;
552
+ }
553
+ if (name === displayName) {
554
+ setIsRenaming(false);
555
+ return;
556
+ }
557
+ const savePromise = (0, save_sequence_prop_1.saveSequenceProps)({
558
+ changes: [
559
+ {
560
+ fileName: validatedLocation.source,
561
+ nodePath,
562
+ fieldKey: 'name',
563
+ value: name,
564
+ defaultValue: null,
565
+ schema: sequence.controls.schema,
566
+ },
567
+ ],
568
+ setPropStatuses,
569
+ clientId: previewServerState.clientId,
570
+ undoLabel: 'Rename sequence',
571
+ redoLabel: 'Rename sequence again',
572
+ });
573
+ setIsRenaming(false);
574
+ await savePromise;
575
+ }, [
576
+ canRenameThisSequence,
577
+ displayName,
578
+ nodePath,
579
+ previewServerState,
580
+ sequence.controls,
581
+ setPropStatuses,
582
+ validatedLocation,
583
+ ]);
584
+ react_1.default.useEffect(() => {
585
+ if (!canRenameSelectedSequence || !process.env.KEYBOARD_SHORTCUTS_ENABLED) {
586
+ setIsRenaming(false);
587
+ return;
588
+ }
589
+ const onKeyDown = (e) => {
590
+ if (!isHighestContext) {
591
+ return;
592
+ }
593
+ const commandKey = window.navigator.platform.startsWith('Mac')
594
+ ? e.metaKey
595
+ : e.ctrlKey;
596
+ if (commandKey || e.key.toLowerCase() !== 'enter') {
597
+ return;
598
+ }
599
+ if (document.activeElement instanceof HTMLInputElement ||
600
+ document.activeElement instanceof HTMLTextAreaElement) {
601
+ return;
602
+ }
603
+ e.preventDefault();
604
+ e.stopImmediatePropagation();
605
+ setIsRenaming(true);
606
+ };
607
+ window.addEventListener('keydown', onKeyDown, true);
608
+ return () => {
609
+ window.removeEventListener('keydown', onKeyDown, true);
610
+ };
611
+ }, [canRenameSelectedSequence, isHighestContext]);
612
+ const onRenameSequence = (0, react_1.useCallback)(() => {
613
+ if (!canRenameThisSequence) {
614
+ return;
615
+ }
616
+ setIsRenaming(true);
617
+ }, [canRenameThisSequence]);
357
618
  const contextMenuValues = (0, react_1.useMemo)(() => {
358
619
  if (!previewConnected) {
359
620
  return [];
@@ -439,6 +700,34 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
439
700
  id: 'open-component-docs-divider',
440
701
  }
441
702
  : null,
703
+ {
704
+ type: 'item',
705
+ id: 'rename-sequence',
706
+ keyHint: 'Enter',
707
+ label: 'Rename...',
708
+ leftItem: null,
709
+ disabled: !canRenameThisSequence,
710
+ onClick: () => {
711
+ onRenameSequence();
712
+ },
713
+ quickSwitcherLabel: null,
714
+ subMenu: null,
715
+ value: 'rename-sequence',
716
+ },
717
+ {
718
+ type: 'item',
719
+ id: 'disable-interactivity',
720
+ keyHint: null,
721
+ label: 'Disable interactivity',
722
+ leftItem: null,
723
+ disabled: disableInteractivityDisabled,
724
+ onClick: () => {
725
+ onDisableSequenceInteractivity();
726
+ },
727
+ quickSwitcherLabel: null,
728
+ subMenu: null,
729
+ value: 'disable-interactivity',
730
+ },
442
731
  {
443
732
  type: 'item',
444
733
  id: 'duplicate-sequence',
@@ -476,122 +765,25 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
476
765
  ].filter(no_react_1.NoReactInternals.truthy);
477
766
  }, [
478
767
  assetLinkInfo,
768
+ canOpenInEditor,
769
+ canRenameThisSequence,
479
770
  deleteDisabled,
771
+ disableInteractivityDisabled,
480
772
  duplicateDisabled,
481
773
  fileLocation,
482
774
  onDeleteSequenceFromSource,
775
+ onDisableSequenceInteractivity,
483
776
  onDuplicateSequenceFromSource,
484
- canOpenInEditor,
777
+ onRenameSequence,
485
778
  openInEditor,
486
779
  previewConnected,
487
780
  selectAsset,
488
781
  sequence,
489
782
  ]);
490
- const isExpanded = previewConnected && nodePathInfo !== null && getIsExpanded(nodePathInfo);
491
- const onToggleExpand = (0, react_1.useCallback)(() => {
492
- if (nodePathInfo === null) {
493
- return;
494
- }
495
- toggleTrack(nodePathInfo);
496
- }, [nodePathInfo, toggleTrack]);
497
- const onShowInEditorDoubleClick = (0, react_1.useCallback)((e) => {
498
- if (!canOpenInEditor) {
499
- return;
500
- }
501
- if ((0, TimelineSelection_1.isTimelineSelectionModifierEvent)(e)) {
502
- e.stopPropagation();
503
- return;
504
- }
505
- e.stopPropagation();
506
- openInEditor();
507
- }, [canOpenInEditor, openInEditor]);
508
- const propStatusesForOverride = (0, react_1.useMemo)(() => {
509
- return nodePath
510
- ? remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)
511
- : undefined;
512
- }, [propStatuses, nodePath]);
513
- const codeHiddenStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.hidden;
514
- const isItemHidden = (0, react_1.useMemo)(() => {
515
- var _a;
516
- const propStatus = codeHiddenStatus && codeHiddenStatus.status === 'static'
517
- ? codeHiddenStatus.codeValue
518
- : undefined;
519
- const runtimeValue = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation.hidden;
520
- const effective = (propStatus !== null && propStatus !== void 0 ? propStatus : runtimeValue);
521
- return effective !== null && effective !== void 0 ? effective : false;
522
- }, [codeHiddenStatus, (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation]);
523
- const onToggleVisibility = (0, react_1.useCallback)((type) => {
524
- if (!sequence.controls ||
525
- !nodePath ||
526
- !validatedLocation ||
527
- !propStatusesForOverride ||
528
- !codeHiddenStatus ||
529
- codeHiddenStatus.status !== 'static' ||
530
- previewServerState.type !== 'connected') {
531
- return;
532
- }
533
- const newValue = type !== 'enable';
534
- const { schema } = sequence.controls;
535
- const fieldSchema = schema.hidden;
536
- const defaultValue = fieldSchema && fieldSchema.type === 'boolean'
537
- ? JSON.stringify(fieldSchema.default)
538
- : null;
539
- (0, save_sequence_prop_1.saveSequenceProps)({
540
- changes: [
541
- {
542
- fileName: validatedLocation.source,
543
- nodePath,
544
- fieldKey: 'hidden',
545
- value: newValue,
546
- defaultValue,
547
- schema,
548
- },
549
- ],
550
- setPropStatuses,
551
- clientId: previewServerState.clientId,
552
- undoLabel: newValue ? 'Hide sequence' : 'Show sequence',
553
- redoLabel: newValue ? 'Hide sequence again' : 'Show sequence again',
554
- });
555
- }, [
556
- codeHiddenStatus,
557
- propStatusesForOverride,
558
- nodePath,
559
- previewServerState,
560
- sequence.controls,
561
- setPropStatuses,
562
- validatedLocation,
563
- ]);
564
- const outerHeight = (0, react_1.useMemo)(() => (0, timeline_layout_1.getTimelineLayerHeight)(sequence.type) + timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM, [sequence.type]);
565
- const inner = (0, react_1.useMemo)(() => {
566
- return {
567
- height: timeline_layout_1.TIMELINE_LIST_ITEM_ROW_HEIGHT,
568
- color: 'white',
569
- fontFamily: 'Arial, Helvetica, sans-serif',
570
- wordBreak: 'break-all',
571
- textAlign: 'left',
572
- flexShrink: 0,
573
- };
574
- }, []);
575
- const rowStyle = (0, react_1.useMemo)(() => {
576
- return effectDropHovered
577
- ? {
578
- ...inner,
579
- ...effectDropHighlight,
580
- }
581
- : inner;
582
- }, [effectDropHovered, inner]);
583
- const hasExpandableContent = Boolean(sequence.controls) || sequence.effects.length > 0;
584
- const canToggleVisibility = previewConnected &&
585
- Boolean(sequence.controls) &&
586
- nodePath !== null &&
587
- validatedLocation !== null &&
588
- codeHiddenStatus !== undefined &&
589
- codeHiddenStatus !== null &&
590
- codeHiddenStatus.status === 'static';
591
783
  const canDropEffect = previewServerState.type === 'connected' &&
592
784
  nodePath !== null &&
593
785
  validatedLocation !== null &&
594
- ((_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.supportsEffects) === true;
786
+ ((_c = sequence.controls) === null || _c === void 0 ? void 0 : _c.supportsEffects) === true;
595
787
  const sequenceReorderLineStyle = (0, react_1.useMemo)(() => {
596
788
  if (!sequenceDropIndicator) {
597
789
  return null;
@@ -647,7 +839,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
647
839
  });
648
840
  }, [canDropEffect, nodePath, previewServerState, validatedLocation]);
649
841
  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: [
842
+ 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
843
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }),
652
844
  " ",
653
845
  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;