@remotion/studio 4.0.519 → 4.0.520

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 (79) hide show
  1. package/dist/api/visual-control.js +2 -2
  2. package/dist/components/AudioWaveform.js +6 -1
  3. package/dist/components/Canvas.js +30 -36
  4. package/dist/components/CompositionSelector.js +6 -10
  5. package/dist/components/CompositionSelectorItem.js +7 -12
  6. package/dist/components/CurrentCompositionSideEffects.js +5 -0
  7. package/dist/components/ElementInstallConfirmation.d.ts +2 -23
  8. package/dist/components/ElementInstallConfirmation.js +16 -2
  9. package/dist/components/FpsCounter.js +1 -1
  10. package/dist/components/FramePersistor.js +1 -1
  11. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -3
  12. package/dist/components/InspectorPanel/use-composition-actions.js +5 -8
  13. package/dist/components/Modals.js +1 -1
  14. package/dist/components/NewComposition/NewComposition.js +2 -2
  15. package/dist/components/PlayPause.js +2 -13
  16. package/dist/components/PreviewToolbar.js +1 -1
  17. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +29 -15
  18. package/dist/components/QuickSwitcher/QuickSwitcherResult.d.ts +14 -1
  19. package/dist/components/QuickSwitcher/QuickSwitcherResult.js +64 -9
  20. package/dist/components/QuickSwitcher/composition-search.d.ts +16 -0
  21. package/dist/components/QuickSwitcher/composition-search.js +136 -0
  22. package/dist/components/ResetZoomButton.js +17 -2
  23. package/dist/components/SelectedOutlineElement.js +10 -30
  24. package/dist/components/Timeline/Timeline.js +2 -1
  25. package/dist/components/Timeline/TimelineAssetField.js +1 -0
  26. package/dist/components/Timeline/TimelineDeleteKeybindings.js +5 -90
  27. package/dist/components/Timeline/TimelineDragHandler.js +18 -8
  28. package/dist/components/Timeline/TimelineInOutDragHandler.js +2 -3
  29. package/dist/components/Timeline/TimelinePinchZoom.js +14 -4
  30. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +8 -4
  31. package/dist/components/Timeline/TimelineSequence.js +16 -41
  32. package/dist/components/Timeline/TimelineSequenceItem.js +14 -35
  33. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +3 -3
  34. package/dist/components/Timeline/TimelineSlider.js +2 -2
  35. package/dist/components/Timeline/TimelineWidthProvider.js +15 -8
  36. package/dist/components/Timeline/TimelineZoomControls.js +25 -8
  37. package/dist/components/Timeline/delete-selected-timeline-item.js +2 -2
  38. package/dist/components/Timeline/timeline-scroll-logic.d.ts +1 -0
  39. package/dist/components/Timeline/timeline-scroll-logic.js +21 -17
  40. package/dist/components/Timeline/use-delete-timeline-items.d.ts +1 -0
  41. package/dist/components/Timeline/use-delete-timeline-items.js +118 -0
  42. package/dist/components/Timeline/use-timeline-asset-drop.js +8 -14
  43. package/dist/components/WebMcp.js +61 -8
  44. package/dist/components/ZoomPersistor.js +2 -2
  45. package/dist/components/composition-drag-data.d.ts +36 -0
  46. package/dist/components/composition-drag-data.js +232 -0
  47. package/dist/components/drop-handler-data.d.ts +2 -1
  48. package/dist/components/drop-handler-data.js +6 -4
  49. package/dist/components/effect-drag-and-drop.d.ts +2 -5
  50. package/dist/components/handle-drop.js +6 -2
  51. package/dist/components/import-assets.d.ts +5 -13
  52. package/dist/error-overlay/current-error.d.ts +13 -0
  53. package/dist/error-overlay/current-error.js +21 -0
  54. package/dist/error-overlay/remotion-overlay/ErrorLoader.js +5 -1
  55. package/dist/esm/{chunk-1fkq5bfq.js → chunk-np6q13k5.js} +21571 -18952
  56. package/dist/esm/index.mjs +4 -1
  57. package/dist/esm/internals.mjs +17206 -14587
  58. package/dist/esm/previewEntry.mjs +19510 -16804
  59. package/dist/esm/renderEntry.mjs +1 -1
  60. package/dist/helpers/create-folder-tree.js +2 -5
  61. package/dist/helpers/document-title.d.ts +2 -0
  62. package/dist/helpers/document-title.js +14 -3
  63. package/dist/helpers/get-timeline-max-zoom.d.ts +34 -28
  64. package/dist/helpers/get-timeline-max-zoom.js +46 -29
  65. package/dist/helpers/install-fiber-sequence-order-observer.d.ts +37 -0
  66. package/dist/helpers/install-fiber-sequence-order-observer.js +109 -0
  67. package/dist/helpers/open-in-editor.js +2 -1
  68. package/dist/helpers/use-runtime-values.d.ts +1 -1
  69. package/dist/helpers/use-runtime-values.js +5 -4
  70. package/dist/helpers/use-sync-external-store.d.ts +3 -0
  71. package/dist/helpers/use-sync-external-store.js +5 -0
  72. package/dist/previewEntry.js +2 -0
  73. package/dist/state/modals.d.ts +18 -2
  74. package/dist/state/timeline-sequence-hover.js +3 -2
  75. package/dist/state/timeline-zoom.d.ts +0 -1
  76. package/dist/state/timeline-zoom.js +13 -6
  77. package/package.json +16 -16
  78. package/dist/helpers/sort-by-nonce-history.d.ts +0 -1
  79. package/dist/helpers/sort-by-nonce-history.js +0 -6
@@ -98,7 +98,7 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
98
98
  !showCompositionControls ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
99
99
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SnappingToggle_1.SnappingToggle, {}) })
100
100
  ] }))] })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), canvasContent && isFullscreenSupported ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(FullscreenToggle_1.FullScreenToggle, { hidden: isMobileLayout }) })) : null, jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsxs("div", { style: sideContainer, children: [
101
- jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(RenderButton_1.RenderButton, { readOnlyStudio: readOnlyStudio, size: "compact", narrow: isMobileLayout }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
101
+ jsx_runtime_1.jsx(layout_1.Flex, {}), isMobileLayout ? null : jsx_runtime_1.jsx(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(RenderButton_1.RenderButton, { readOnlyStudio: readOnlyStudio, size: "compact", narrow: isMobileLayout }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
102
102
  ] }), jsx_runtime_1.jsx(PlaybackKeyboardShortcutsManager_1.PlaybackKeyboardShortcutsManager, { setPlaybackRate: setPlaybackRate }), jsx_runtime_1.jsx(PlaybackRatePersistor_1.PlaybackRatePersistor, {})
103
103
  ] }));
104
104
  };
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const colors_1 = require("../../helpers/colors");
8
+ const create_folder_tree_1 = require("../../helpers/create-folder-tree");
8
9
  const get_preview_file_type_1 = require("../../helpers/get-preview-file-type");
9
10
  const is_composition_still_1 = require("../../helpers/is-composition-still");
10
11
  const url_state_1 = require("../../helpers/url-state");
@@ -19,6 +20,7 @@ const use_select_asset_1 = require("../use-select-asset");
19
20
  const use_static_files_1 = require("../use-static-files");
20
21
  const algolia_search_1 = require("./algolia-search");
21
22
  const asset_search_1 = require("./asset-search");
23
+ const composition_search_1 = require("./composition-search");
22
24
  const fuzzy_search_1 = require("./fuzzy-search");
23
25
  const NoResults_1 = require("./NoResults");
24
26
  const QuickSwitcherResult_1 = require("./QuickSwitcherResult");
@@ -108,7 +110,9 @@ const mapModeToQuery = (mode) => {
108
110
  throw new Error('no mode' + mode);
109
111
  };
110
112
  const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio, assetSelection, compositionSelection, }) => {
111
- const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
113
+ var _a;
114
+ var _b;
115
+ const { compositions, folders } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
112
116
  const staticFiles = (0, use_static_files_1.useStaticFiles)();
113
117
  const [state, setState] = (0, react_1.useState)(() => {
114
118
  return {
@@ -201,37 +205,45 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
201
205
  ...assetResults,
202
206
  ];
203
207
  }
204
- return (0, fuzzy_search_1.fuzzySearch)(actualQuery, compositions
205
- .filter((c) => c.id !== (compositionSelection === null || compositionSelection === void 0 ? void 0 : compositionSelection.excludeCompositionId))
206
- .map((c) => {
208
+ const tree = (0, create_folder_tree_1.createFolderTree)(compositions.filter((composition) => composition.id !== (compositionSelection === null || compositionSelection === void 0 ? void 0 : compositionSelection.excludeCompositionId)), folders, {});
209
+ return (0, composition_search_1.searchCompositionTree)({ items: tree, query: actualQuery }).map((result) => {
210
+ if (result.type === 'folder') {
211
+ return result;
212
+ }
213
+ const { composition } = result;
207
214
  return {
208
- id: 'composition-' + c.id,
209
- title: c.id,
215
+ id: 'composition-' + composition.id,
216
+ title: composition.id,
210
217
  type: 'composition',
218
+ composition,
219
+ level: result.level,
211
220
  onSelected: () => {
212
221
  var _a;
213
222
  if (compositionSelection !== null) {
214
- compositionSelection.onSelected(c);
223
+ compositionSelection.onSelected(composition);
215
224
  setSelectedModal(null);
216
225
  return;
217
226
  }
218
- selectComposition(c, true);
227
+ selectComposition(composition, true);
219
228
  setSelectedModal(null);
220
- const selector = `.__remotion-composition[data-compname="${c.id}"]`;
221
- (_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.expandComposition(c.id);
229
+ const selector = `.__remotion-composition[data-compname="${composition.id}"]`;
230
+ (_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.expandComposition(composition.id);
222
231
  waitForElm(selector).then(() => {
223
232
  var _a;
224
233
  (_a = document
225
234
  .querySelector(selector)) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'center' });
226
235
  });
227
236
  },
228
- compositionType: (0, is_composition_still_1.isCompositionStill)(c) ? 'still' : 'composition',
237
+ compositionType: (0, is_composition_still_1.isCompositionStill)(composition)
238
+ ? 'still'
239
+ : 'composition',
229
240
  };
230
- }));
241
+ });
231
242
  }, [
232
243
  mode,
233
244
  actualQuery,
234
245
  compositions,
246
+ folders,
235
247
  menuActions,
236
248
  docResults,
237
249
  assetSearch,
@@ -319,7 +331,9 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
319
331
  const onTextChange = (0, react_1.useCallback)((e) => {
320
332
  setState({ query: e.target.value, selectedIndex: 0 });
321
333
  }, []);
322
- const selectedIndexRounded = (0, shared_1.loopIndex)(state.selectedIndex, resultsArray.length);
334
+ const selectableResults = resultsArray.filter(QuickSwitcherResult_1.isQuickSwitcherResultSelectable);
335
+ const selectedIndexRounded = (0, shared_1.loopIndex)(state.selectedIndex, selectableResults.length);
336
+ const selectedResultId = (_b = (_a = selectableResults[selectedIndexRounded]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
323
337
  const focusInput = (0, react_1.useCallback)(() => {
324
338
  var _a;
325
339
  if (!isTouchscreen) {
@@ -369,8 +383,8 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
369
383
  ] })), jsx_runtime_1.jsx("div", { style: assetSelection === null && compositionSelection === null
370
384
  ? content
371
385
  : contentWithoutModeSelector, children: jsx_runtime_1.jsx(RemInput_1.RemotionInput, { ref: inputRef, type: "text", style: isTouchscreen ? touchscreenInput : input, autoFocus: !isTouchscreen, status: "ok", value: state.query, onChange: onTextChange, placeholder: placeholder, rightAlign: false }) }), jsx_runtime_1.jsx("div", { style: results, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: showEmptyDocSearch ||
372
- showSearchLoadingState ? null : resultsArray.length === 0 ? (jsx_runtime_1.jsx(NoResults_1.QuickSwitcherNoResults, { mode: mode, query: actualQuery })) : (resultsArray.map((result, i) => {
373
- return (jsx_runtime_1.jsx(QuickSwitcherResult_1.QuickSwitcherResult, { selected: selectedIndexRounded === i, result: result }, result.id));
386
+ showSearchLoadingState ? null : resultsArray.length === 0 ? (jsx_runtime_1.jsx(NoResults_1.QuickSwitcherNoResults, { mode: mode, query: actualQuery })) : (resultsArray.map((result) => {
387
+ return (jsx_runtime_1.jsx(QuickSwitcherResult_1.QuickSwitcherResult, { selected: selectedResultId === result.id, result: result }, result.id));
374
388
  })) })
375
389
  ] }));
376
390
  };
@@ -1,11 +1,14 @@
1
1
  import React from 'react';
2
+ import type { _InternalTypes } from 'remotion';
2
3
  import type { AssetFileType } from '../../helpers/get-preview-file-type';
3
4
  type QuickSwitcherResultDetail = {
4
5
  type: 'asset';
5
6
  fileType: AssetFileType;
6
7
  } | {
7
8
  type: 'composition';
9
+ composition: _InternalTypes['AnyComposition'];
8
10
  compositionType: 'composition' | 'still';
11
+ level: number;
9
12
  } | {
10
13
  type: 'menu-item';
11
14
  } | {
@@ -15,7 +18,17 @@ type QuickSwitcherResultDetail = {
15
18
  titleLine: string;
16
19
  subtitleLine: string;
17
20
  };
18
- export type TQuickSwitcherResult = {
21
+ export type TQuickSwitcherResult = ({
22
+ title: string;
23
+ id: string;
24
+ onSelected: () => void;
25
+ } & QuickSwitcherResultDetail) | {
26
+ title: string;
27
+ id: string;
28
+ type: 'folder';
29
+ level: number;
30
+ };
31
+ export declare const isQuickSwitcherResultSelectable: (result: TQuickSwitcherResult) => result is {
19
32
  title: string;
20
33
  id: string;
21
34
  onSelected: () => void;
@@ -1,16 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QuickSwitcherResult = void 0;
3
+ exports.QuickSwitcherResult = exports.isQuickSwitcherResultSelectable = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
+ const client_id_1 = require("../../helpers/client-id");
6
7
  const colors_1 = require("../../helpers/colors");
8
+ const noop_1 = require("../../helpers/noop");
7
9
  const use_keybinding_1 = require("../../helpers/use-keybinding");
10
+ const folder_1 = require("../../icons/folder");
8
11
  const still_1 = require("../../icons/still");
9
12
  const upload_1 = require("../../icons/upload");
10
13
  const video_1 = require("../../icons/video");
14
+ const modals_1 = require("../../state/modals");
11
15
  const AssetFileIcon_1 = require("../AssetFileIcon");
16
+ const composition_menu_items_1 = require("../composition-menu-items");
17
+ const ContextMenu_1 = require("../ContextMenu");
12
18
  const layout_1 = require("../layout");
19
+ const use_resolved_stack_1 = require("../Timeline/use-resolved-stack");
20
+ const use_default_editor_info_1 = require("../use-default-editor-info");
13
21
  const shared_1 = require("./shared");
22
+ const isQuickSwitcherResultSelectable = (result) => {
23
+ return result.type !== 'folder';
24
+ };
25
+ exports.isQuickSwitcherResultSelectable = isQuickSwitcherResultSelectable;
14
26
  const container = {
15
27
  paddingLeft: 16,
16
28
  paddingRight: 16,
@@ -48,10 +60,44 @@ const labelContainer = {
48
60
  paddingBottom: 5,
49
61
  };
50
62
  const QuickSwitcherResult = ({ result, selected }) => {
63
+ var _a;
51
64
  const [hovered, setIsHovered] = (0, react_1.useState)(false);
52
65
  const ref = (0, react_1.useRef)(null);
53
66
  const keybindings = (0, use_keybinding_1.useKeybinding)();
67
+ const onSelected = result.type === 'folder' ? null : result.onSelected;
68
+ const composition = result.type === 'composition' ? result.composition : null;
69
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
70
+ const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
71
+ .previewServerState.type;
72
+ const { defaultEditorId, defaultEditorName } = (0, use_default_editor_info_1.useEditorOpening)(connectionStatus === 'connected');
73
+ const resolvedLocation = (0, use_resolved_stack_1.useResolvedStack)((_a = composition === null || composition === void 0 ? void 0 : composition.stack) !== null && _a !== void 0 ? _a : null);
74
+ const getContextMenuItems = (0, react_1.useCallback)(() => {
75
+ if (composition === null) {
76
+ return [];
77
+ }
78
+ return (0, composition_menu_items_1.getCompositionContextMenuItems)({
79
+ closeMenu: noop_1.noop,
80
+ composition,
81
+ connectionStatus,
82
+ editorId: defaultEditorId,
83
+ editorName: defaultEditorName,
84
+ includeCompositionManagementItems: true,
85
+ resolvedLocation,
86
+ setSelectedModal,
87
+ readOnlyStudio: window.remotion_isReadOnlyStudio,
88
+ });
89
+ }, [
90
+ composition,
91
+ connectionStatus,
92
+ defaultEditorId,
93
+ defaultEditorName,
94
+ resolvedLocation,
95
+ setSelectedModal,
96
+ ]);
54
97
  (0, react_1.useEffect)(() => {
98
+ if (result.type === 'folder') {
99
+ return;
100
+ }
55
101
  const { current } = ref;
56
102
  if (!current) {
57
103
  return;
@@ -64,14 +110,14 @@ const QuickSwitcherResult = ({ result, selected }) => {
64
110
  current.removeEventListener('mouseenter', onMouseEnter);
65
111
  current.removeEventListener('mouseleave', onMouseLeave);
66
112
  };
67
- }, []);
113
+ }, [result.type]);
68
114
  (0, react_1.useEffect)(() => {
69
- if (!selected) {
115
+ if (!selected || onSelected === null) {
70
116
  return;
71
117
  }
72
118
  const binding = keybindings.registerKeybinding({
73
119
  key: 'Enter',
74
- callback: result.onSelected,
120
+ callback: onSelected,
75
121
  commandCtrlKey: false,
76
122
  event: 'keydown',
77
123
  preventDefault: true,
@@ -82,18 +128,23 @@ const QuickSwitcherResult = ({ result, selected }) => {
82
128
  return () => {
83
129
  binding.unregister();
84
130
  };
85
- }, [keybindings, result.onSelected, selected]);
131
+ }, [keybindings, onSelected, selected]);
86
132
  (0, shared_1.useScrollIntoViewOnSelected)(ref, selected);
87
133
  const style = (0, react_1.useMemo)(() => {
88
134
  return {
89
135
  ...container,
90
- backgroundColor: hovered || selected ? colors_1.WHITE_ALPHA_06 : colors_1.TRANSPARENT,
136
+ paddingLeft: result.type === 'folder' || result.type === 'composition'
137
+ ? 16 + result.level * 8
138
+ : container.paddingLeft,
139
+ backgroundColor: result.type !== 'folder' && (hovered || selected)
140
+ ? colors_1.WHITE_ALPHA_06
141
+ : colors_1.TRANSPARENT,
91
142
  };
92
- }, [hovered, selected]);
143
+ }, [hovered, result, selected]);
93
144
  const labelStyle = (0, react_1.useMemo)(() => {
94
145
  return {
95
146
  ...(result.type === 'search-result' ? searchLabel : label),
96
- color: result.type === 'search-result'
147
+ color: result.type === 'search-result' || result.type === 'folder'
97
148
  ? colors_1.LIGHT_TEXT
98
149
  : selected || hovered
99
150
  ? colors_1.WHITE
@@ -101,7 +152,7 @@ const QuickSwitcherResult = ({ result, selected }) => {
101
152
  fontSize: shared_1.QUICK_SWITCHER_RESULT_LABEL_FONT_SIZE,
102
153
  };
103
154
  }, [hovered, result.type, selected]);
104
- return (jsx_runtime_1.jsxs("div", { ref: ref, style: style, onClick: result.onSelected, children: [result.type === 'composition' ? (result.compositionType === 'still' ? (jsx_runtime_1.jsx(still_1.StillIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle })) : (jsx_runtime_1.jsx(video_1.FilmIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle }))) : result.type === 'asset' ? (jsx_runtime_1.jsx(AssetFileIcon_1.AssetFileIcon, { fileType: result.fileType, color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle })) : result.type === 'select-file' ? (jsx_runtime_1.jsx(upload_1.UploadIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: selectFileIconStyle })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: labelContainer, children: result.type === 'search-result' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
155
+ const row = (jsx_runtime_1.jsxs("div", { ref: ref, style: style, onClick: onSelected !== null && onSelected !== void 0 ? onSelected : undefined, children: [result.type === 'composition' ? (result.compositionType === 'still' ? (jsx_runtime_1.jsx(still_1.StillIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle })) : (jsx_runtime_1.jsx(video_1.FilmIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle }))) : result.type === 'folder' ? (jsx_runtime_1.jsx(folder_1.ExpandedFolderIcon, { color: colors_1.LIGHT_TEXT, style: iconStyle })) : result.type === 'asset' ? (jsx_runtime_1.jsx(AssetFileIcon_1.AssetFileIcon, { fileType: result.fileType, color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: iconStyle })) : result.type === 'select-file' ? (jsx_runtime_1.jsx(upload_1.UploadIcon, { color: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, style: selectFileIconStyle })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: labelContainer, children: result.type === 'search-result' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
105
156
  jsx_runtime_1.jsx("div", {
106
157
  // eslint-disable-next-line react/no-danger
107
158
  dangerouslySetInnerHTML: {
@@ -113,5 +164,9 @@ const QuickSwitcherResult = ({ result, selected }) => {
113
164
  }, style: labelStyle })
114
165
  ] })) : (jsx_runtime_1.jsx("div", { style: labelStyle, children: result.title })) })
115
166
  ] }, result.id));
167
+ if (composition === null) {
168
+ return row;
169
+ }
170
+ return jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { getItems: getContextMenuItems, children: row });
116
171
  };
117
172
  exports.QuickSwitcherResult = QuickSwitcherResult;
@@ -0,0 +1,16 @@
1
+ import type { _InternalTypes } from 'remotion';
2
+ import type { CompositionSelectorItemType } from '../CompositionSelectorItem';
3
+ export type CompositionSearchResult = {
4
+ readonly type: 'folder';
5
+ readonly id: string;
6
+ readonly title: string;
7
+ readonly level: number;
8
+ } | {
9
+ readonly type: 'composition';
10
+ readonly composition: _InternalTypes['AnyComposition'];
11
+ readonly level: number;
12
+ };
13
+ export declare const searchCompositionTree: ({ items, query, }: {
14
+ readonly items: CompositionSelectorItemType[];
15
+ readonly query: string;
16
+ }) => CompositionSearchResult[];
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchCompositionTree = void 0;
4
+ const normalizeSearchText = (text) => {
5
+ return text
6
+ .trim()
7
+ .toLowerCase()
8
+ .replace(/[\s/-]/g, '');
9
+ };
10
+ const getMatchScore = (query, candidate) => {
11
+ const normalizedCandidate = normalizeSearchText(candidate);
12
+ if (normalizedCandidate === query) {
13
+ return 400000 - normalizedCandidate.length;
14
+ }
15
+ if (normalizedCandidate.startsWith(query)) {
16
+ return 300000 - (normalizedCandidate.length - query.length);
17
+ }
18
+ const substringIndex = normalizedCandidate.indexOf(query);
19
+ if (substringIndex !== -1) {
20
+ return (200000 -
21
+ substringIndex * 100 -
22
+ (normalizedCandidate.length - query.length));
23
+ }
24
+ let previousIndex = -1;
25
+ let firstIndex = -1;
26
+ let gapCount = 0;
27
+ for (const character of query) {
28
+ const nextIndex = normalizedCandidate.indexOf(character, previousIndex + 1);
29
+ if (nextIndex === -1) {
30
+ return null;
31
+ }
32
+ if (firstIndex === -1) {
33
+ firstIndex = nextIndex;
34
+ }
35
+ else {
36
+ gapCount += nextIndex - previousIndex - 1;
37
+ }
38
+ previousIndex = nextIndex;
39
+ }
40
+ return (100000 -
41
+ gapCount * 100 -
42
+ firstIndex * 10 -
43
+ (normalizedCandidate.length - query.length));
44
+ };
45
+ const searchCompositionTree = ({ items, query, }) => {
46
+ const normalizedQuery = normalizeSearchText(query);
47
+ const filterAndRank = (treeItems, level, inheritedFolderScore) => {
48
+ const rankedItems = treeItems
49
+ .map((item, originalIndex) => {
50
+ if (item.type === 'composition') {
51
+ const compositionPath = [
52
+ item.composition.parentFolderName,
53
+ item.composition.folderName,
54
+ item.composition.id,
55
+ ]
56
+ .filter(Boolean)
57
+ .join('/');
58
+ const idScore = normalizedQuery === ''
59
+ ? 0
60
+ : getMatchScore(normalizedQuery, item.composition.id);
61
+ const compositionPathScore = normalizedQuery === ''
62
+ ? 0
63
+ : getMatchScore(normalizedQuery, compositionPath);
64
+ const directScore = Math.max(idScore !== null && idScore !== void 0 ? idScore : -1, compositionPathScore !== null && compositionPathScore !== void 0 ? compositionPathScore : -1);
65
+ const score = Math.max(directScore, inheritedFolderScore !== null && inheritedFolderScore !== void 0 ? inheritedFolderScore : -1);
66
+ if (score === -1) {
67
+ return null;
68
+ }
69
+ return {
70
+ result: {
71
+ type: 'composition',
72
+ composition: item.composition,
73
+ level,
74
+ score,
75
+ },
76
+ originalIndex,
77
+ };
78
+ }
79
+ const fullPath = [item.parentName, item.folderName]
80
+ .filter(Boolean)
81
+ .join('/');
82
+ const nameScore = normalizedQuery === ''
83
+ ? 0
84
+ : getMatchScore(normalizedQuery, item.folderName);
85
+ const pathScore = normalizedQuery === '' ? 0 : getMatchScore(normalizedQuery, fullPath);
86
+ const directFolderScore = Math.max(nameScore !== null && nameScore !== void 0 ? nameScore : -1, pathScore !== null && pathScore !== void 0 ? pathScore : -1);
87
+ const folderScore = Math.max(directFolderScore === -1 ? -1 : directFolderScore - 1, inheritedFolderScore !== null && inheritedFolderScore !== void 0 ? inheritedFolderScore : -1);
88
+ const children = filterAndRank(item.items, level + 1, folderScore === -1 ? null : folderScore);
89
+ if (children.length === 0) {
90
+ return null;
91
+ }
92
+ return {
93
+ result: {
94
+ type: 'folder',
95
+ id: `folder-${fullPath}`,
96
+ title: item.folderName,
97
+ level,
98
+ score: Math.max(folderScore, ...children.map((child) => child.score)),
99
+ children,
100
+ },
101
+ originalIndex,
102
+ };
103
+ })
104
+ .filter((item) => item !== null);
105
+ if (normalizedQuery !== '') {
106
+ rankedItems.sort((a, b) => {
107
+ return (b.result.score - a.result.score || a.originalIndex - b.originalIndex);
108
+ });
109
+ }
110
+ return rankedItems.map((item) => item.result);
111
+ };
112
+ const flatten = (rankedItems) => {
113
+ return rankedItems.flatMap((item) => {
114
+ if (item.type === 'composition') {
115
+ return [
116
+ {
117
+ type: 'composition',
118
+ composition: item.composition,
119
+ level: item.level,
120
+ },
121
+ ];
122
+ }
123
+ return [
124
+ {
125
+ type: 'folder',
126
+ id: item.id,
127
+ title: item.title,
128
+ level: item.level,
129
+ },
130
+ ...flatten(item.children),
131
+ ];
132
+ });
133
+ };
134
+ return flatten(filterAndRank(items, 0, null));
135
+ };
136
+ exports.searchCompositionTree = searchCompositionTree;
@@ -3,11 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResetZoomButton = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
- const Button_1 = require("./Button");
6
+ const colors_1 = require("../helpers/colors");
7
+ const button = {
8
+ appearance: 'none',
9
+ backgroundColor: colors_1.INPUT_BACKGROUND,
10
+ border: `1px solid ${colors_1.BLACK_ALPHA_60}`,
11
+ borderRadius: 4,
12
+ color: colors_1.WHITE,
13
+ flexDirection: 'row',
14
+ fontFamily: 'inherit',
15
+ fontSize: 14,
16
+ };
17
+ const buttonContainer = {
18
+ cursor: 'pointer',
19
+ fontSize: 14,
20
+ padding: 10,
21
+ };
7
22
  const ResetZoomButton = ({ onClick }) => {
8
23
  const onPointerDown = (0, react_1.useCallback)((event) => {
9
24
  event.stopPropagation();
10
25
  }, []);
11
- return (jsx_runtime_1.jsx(Button_1.Button, { onClick: onClick, onPointerDown: onPointerDown, children: "Reset zoom" }));
26
+ return (jsx_runtime_1.jsx("button", { style: button, type: "button", onClick: onClick, onPointerDown: onPointerDown, children: jsx_runtime_1.jsx("div", { className: "css-reset", style: buttonContainer, children: "Reset zoom" }) }));
12
27
  };
13
28
  exports.ResetZoomButton = ResetZoomButton;
@@ -45,7 +45,6 @@ const open_in_editor_1 = require("../helpers/open-in-editor");
45
45
  const modals_1 = require("../state/modals");
46
46
  const transform_3d_mode_1 = require("../state/transform-3d-mode");
47
47
  const ConfirmationDialog_1 = require("./ConfirmationDialog");
48
- const delete_jsx_node_api_1 = require("./delete-jsx-node-api");
49
48
  const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
50
49
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
51
50
  const selected_outline_types_1 = require("./selected-outline-types");
@@ -57,6 +56,7 @@ const get_sequence_context_menu_items_1 = require("./Timeline/get-sequence-conte
57
56
  const timeline_asset_link_1 = require("./Timeline/timeline-asset-link");
58
57
  const TimelineSelection_1 = require("./Timeline/TimelineSelection");
59
58
  const get_stack_1 = require("./Timeline/TimelineStack/get-stack");
59
+ const use_delete_timeline_items_1 = require("./Timeline/use-delete-timeline-items");
60
60
  const use_default_editor_info_1 = require("./use-default-editor-info");
61
61
  const use_select_asset_1 = require("./use-select-asset");
62
62
  const use_selected_outline_control_target_1 = require("./use-selected-outline-control-target");
@@ -68,6 +68,7 @@ const SelectedOutlineElementUnmemoized = ({ compositionHeight, compositionWidth,
68
68
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
69
69
  const updateResolvedStackTrace = (0, react_1.useContext)(remotion_1.Internals.SequenceStackTracesUpdateContext);
70
70
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
71
+ const deleteTimelineItems = (0, use_delete_timeline_items_1.useDeleteTimelineItems)();
71
72
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
72
73
  const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
73
74
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
@@ -180,38 +181,16 @@ const SelectedOutlineElementUnmemoized = ({ compositionHeight, compositionWidth,
180
181
  });
181
182
  }
182
183
  : null,
183
- onDeleteSequenceFromSource: async () => {
184
+ onDeleteSequenceFromSource: () => {
184
185
  if (sourceEditDisabled || previewServerState.type !== 'connected') {
185
186
  return;
186
187
  }
187
- if (contextMenuTarget.nodePathInfo.numberOfSequencesWithThisNodePath > 1) {
188
- const shouldDelete = await confirm({
189
- title: 'Delete sequence?',
190
- message: 'This sequence is programmatically duplicated ' +
191
- contextMenuTarget.nodePathInfo.numberOfSequencesWithThisNodePath +
192
- ' times in the code. Deleting removes all instances. Continue?',
193
- confirmLabel: 'Delete',
194
- });
195
- if (!shouldDelete) {
196
- return;
197
- }
198
- }
199
- try {
200
- const result = await (0, delete_jsx_node_api_1.deleteJsxNode)({
201
- nodes: [
202
- {
203
- fileName: nodePath.absolutePath,
204
- nodePath: nodePath.nodePath,
205
- },
206
- ],
207
- });
208
- if (!result.success) {
209
- (0, NotificationCenter_1.showNotification)(result.reason, 4000);
210
- }
211
- }
212
- catch (err) {
213
- (0, NotificationCenter_1.showNotification)(err.message, 4000);
214
- }
188
+ deleteTimelineItems([
189
+ {
190
+ type: 'sequence',
191
+ nodePathInfo: contextMenuTarget.nodePathInfo,
192
+ },
193
+ ]);
215
194
  },
216
195
  onDisableSequenceInteractivity: () => {
217
196
  if (disableInteractivityDisabled ||
@@ -343,6 +322,7 @@ const SelectedOutlineElementUnmemoized = ({ compositionHeight, compositionWidth,
343
322
  canConfigureApps,
344
323
  codingAgentInfo,
345
324
  confirm,
325
+ deleteTimelineItems,
346
326
  editorInfo,
347
327
  getTarget,
348
328
  onSelect,
@@ -48,6 +48,7 @@ const is_current_selected_still_1 = require("../../helpers/is-current-selected-s
48
48
  const open_in_editor_1 = require("../../helpers/open-in-editor");
49
49
  const studio_runtime_config_1 = require("../../helpers/studio-runtime-config");
50
50
  const timeline_node_path_key_1 = require("../../helpers/timeline-node-path-key");
51
+ const use_sync_external_store_1 = require("../../helpers/use-sync-external-store");
51
52
  const call_api_1 = require("../call-api");
52
53
  const ContextMenu_1 = require("../ContextMenu");
53
54
  const import_assets_1 = require("../import-assets");
@@ -296,7 +297,7 @@ const TimelineInner = () => {
296
297
  overrideIdToNodePathMappings,
297
298
  compositions,
298
299
  ]);
299
- const pendingInsertedElementSelection = (0, react_1.useSyncExternalStore)(inserted_element_selection_1.subscribeToInsertedElementSelection, inserted_element_selection_1.getInsertedElementSelection, inserted_element_selection_1.getInsertedElementSelection);
300
+ const pendingInsertedElementSelection = (0, use_sync_external_store_1.useSyncExternalStore)(inserted_element_selection_1.subscribeToInsertedElementSelection, inserted_element_selection_1.getInsertedElementSelection, inserted_element_selection_1.getInsertedElementSelection);
300
301
  const { fastRefreshes } = (0, react_1.useContext)(fast_refresh_context_1.FastRefreshContext);
301
302
  const pendingSelectionStart = (0, react_1.useRef)(null);
302
303
  const { selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
@@ -23,6 +23,7 @@ const sourceActions = {
23
23
  display: 'flex',
24
24
  flex: 1,
25
25
  gap: 4,
26
+ margin: '0 4px',
26
27
  minWidth: 0,
27
28
  };
28
29
  const standaloneSourceActionStyle = {