@remotion/studio 4.0.474 → 4.0.475

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 (73) hide show
  1. package/dist/components/Canvas.js +6 -0
  2. package/dist/components/ColorPicker/ColorPicker.js +4 -31
  3. package/dist/components/CompositionSelectorItem.js +4 -4
  4. package/dist/components/Editor.js +4 -1
  5. package/dist/components/Modals.js +2 -1
  6. package/dist/components/NewComposition/ComboBox.js +1 -0
  7. package/dist/components/PreviewToolbar.js +2 -2
  8. package/dist/components/SelectedOutlineOverlay.d.ts +58 -32
  9. package/dist/components/SelectedOutlineOverlay.js +766 -315
  10. package/dist/components/SelectedOutlineUvControls.d.ts +17 -0
  11. package/dist/components/SelectedOutlineUvControls.js +167 -0
  12. package/dist/components/StudioCanvasCapture.d.ts +5 -0
  13. package/dist/components/StudioCanvasCapture.js +40 -0
  14. package/dist/components/Timeline/EasingEditorModal.d.ts +11 -0
  15. package/dist/components/Timeline/EasingEditorModal.js +247 -0
  16. package/dist/components/Timeline/KeyframeSettingsModal.js +1 -0
  17. package/dist/components/Timeline/Timeline.js +10 -7
  18. package/dist/components/Timeline/TimelineDeleteKeybindings.js +64 -35
  19. package/dist/components/Timeline/TimelineDragHandler.js +2 -2
  20. package/dist/components/Timeline/TimelineEffectItem.js +1 -2
  21. package/dist/components/Timeline/TimelineEffectPropItem.js +1 -1
  22. package/dist/components/Timeline/TimelineExpandedKeyframeRow.d.ts +1 -0
  23. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +2 -2
  24. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +1 -1
  25. package/dist/components/Timeline/TimelineHeightContainer.js +2 -0
  26. package/dist/components/Timeline/TimelineItemStack.js +3 -56
  27. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +7 -0
  28. package/dist/components/Timeline/TimelineKeyframeControls.js +259 -62
  29. package/dist/components/Timeline/TimelineKeyframeDiamond.js +4 -2
  30. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +128 -3
  31. package/dist/components/Timeline/TimelineKeyframeTracksContext.d.ts +7 -0
  32. package/dist/components/Timeline/TimelineKeyframeTracksContext.js +17 -0
  33. package/dist/components/Timeline/TimelineMediaInfo.js +4 -24
  34. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +4 -0
  35. package/dist/components/Timeline/TimelineRotationField.js +5 -23
  36. package/dist/components/Timeline/TimelineScrollable.js +19 -3
  37. package/dist/components/Timeline/TimelineSelection.d.ts +67 -3
  38. package/dist/components/Timeline/TimelineSelection.js +289 -32
  39. package/dist/components/Timeline/TimelineSequence.js +17 -9
  40. package/dist/components/Timeline/TimelineSequenceItem.js +29 -61
  41. package/dist/components/Timeline/TimelineSequenceName.js +3 -17
  42. package/dist/components/Timeline/TimelineSequencePropItem.js +1 -1
  43. package/dist/components/Timeline/TimelineTimeIndicators.js +4 -2
  44. package/dist/components/Timeline/TimelineTransformOriginField.d.ts +11 -0
  45. package/dist/components/Timeline/TimelineTransformOriginField.js +138 -0
  46. package/dist/components/Timeline/call-add-keyframe.d.ts +17 -0
  47. package/dist/components/Timeline/call-add-keyframe.js +65 -1
  48. package/dist/components/Timeline/delete-selected-timeline-item.js +23 -13
  49. package/dist/components/Timeline/reset-selected-timeline-props.js +13 -5
  50. package/dist/components/Timeline/timeline-rotation-utils.d.ts +2 -0
  51. package/dist/components/Timeline/timeline-rotation-utils.js +32 -0
  52. package/dist/components/Timeline/transform-origin-utils.d.ts +24 -0
  53. package/dist/components/Timeline/transform-origin-utils.js +170 -0
  54. package/dist/components/Timeline/update-selected-easing.d.ts +35 -0
  55. package/dist/components/Timeline/update-selected-easing.js +133 -0
  56. package/dist/components/Timeline/use-expanded-track-keyframe-rows.d.ts +1 -0
  57. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +28 -0
  58. package/dist/components/canvas-capture-enabled.d.ts +1 -0
  59. package/dist/components/canvas-capture-enabled.js +4 -0
  60. package/dist/components/effect-drag-and-drop.d.ts +11 -0
  61. package/dist/components/effect-drag-and-drop.js +73 -0
  62. package/dist/components/selected-outline-geometry.d.ts +20 -0
  63. package/dist/components/selected-outline-geometry.js +18 -0
  64. package/dist/components/selected-outline-uv.d.ts +46 -0
  65. package/dist/components/selected-outline-uv.js +240 -0
  66. package/dist/esm/{chunk-xjvc8qen.js → chunk-qaqqvw4q.js} +7418 -4943
  67. package/dist/esm/internals.mjs +7418 -4943
  68. package/dist/esm/previewEntry.mjs +7426 -4951
  69. package/dist/esm/renderEntry.mjs +1 -1
  70. package/dist/helpers/colors.d.ts +0 -1
  71. package/dist/helpers/colors.js +1 -2
  72. package/dist/state/modals.d.ts +2 -1
  73. package/package.json +11 -10
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useTimelineRowContainsSelection = exports.useTimelineEasingSelection = exports.useTimelineKeyframeSelection = exports.useTimelineRowSelection = exports.useCurrentTimelineSelectionStateAsRef = exports.useTimelineSelection = exports.TimelineSelectionProvider = exports.TimelineSelectAllKeybindings = exports.getTimelineSequenceSelectionKey = exports.getSelectableTimelineSequenceSelections = exports.getTimelineSelectionFromNodePathInfo = exports.getTimelineSelectionAfterInteraction = exports.isTimelineSelectionModifierEvent = exports.ENABLE_OUTLINES = exports.TIMELINE_TOP_DRAG = exports.SELECTION_ENABLED = exports.getTimelineSelectedTrackHighlightStyle = exports.getTimelineColor = exports.getTimelineSelectedLabelStyle = exports.TIMELINE_SELECTED_LABEL_HORIZONTAL_PADDING = exports.TIMELINE_SELECTED_LABEL_TEXT = exports.TIMELINE_SELECTED_LABEL_BACKGROUND = exports.TIMELINE_SELECTED_BACKGROUND = void 0;
3
+ exports.useTimelineRowContainsSelection = exports.useTimelineEasingSelection = exports.useTimelineKeyframeSelection = exports.useTimelineRowSelection = exports.useTimelineMarqueeSelectableItem = exports.useTimelineMarqueeSelection = exports.useCurrentTimelineSelectionStateAsRef = exports.TIMELINE_SCRUBBER_ATTR = exports.TIMELINE_MARQUEE_ITEM_ATTR = exports.useTimelineSelection = exports.TimelineSelectionProvider = exports.TimelineSelectAllKeybindings = exports.getTimelineSequenceSelectionKey = exports.getSelectableTimelineSequenceSelections = exports.getTimelineSelectionKey = exports.getTimelineSelectionFromNodePathInfo = exports.getTimelineMarqueeSelection = exports.timelineMarqueeRectsIntersect = exports.getClampedTimelineMarqueePoint = exports.getNormalizedTimelineMarqueeRect = exports.getTimelineSelectionAfterInteraction = exports.shouldSelectTimelineRowOnPointerDown = exports.isTimelineSelectionModifierEvent = exports.TIMELINE_TICKS_BACKGROUND = exports.TIMELINE_BACKGROUND = exports.getTimelineSelectedTrackHighlightStyle = exports.getTimelineColor = exports.getTimelineSelectedLabelStyle = exports.TIMELINE_SELECTED_LABEL_HORIZONTAL_PADDING = exports.TIMELINE_SELECTED_LABEL_TEXT = exports.TIMELINE_SELECTED_LABEL_BACKGROUND = exports.TIMELINE_SELECTED_BACKGROUND = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const react_1 = require("react");
7
7
  const client_id_1 = require("../../helpers/client-id");
8
+ const colors_1 = require("../../helpers/colors");
8
9
  const timeline_layout_1 = require("../../helpers/timeline-layout");
9
10
  const timeline_node_path_key_1 = require("../../helpers/timeline-node-path-key");
10
11
  const use_keybinding_1 = require("../../helpers/use-keybinding");
12
+ const z_index_1 = require("../../state/z-index");
11
13
  const TimelineClipboardKeybindings_1 = require("./TimelineClipboardKeybindings");
12
14
  const TimelineDeleteKeybindings_1 = require("./TimelineDeleteKeybindings");
13
15
  exports.TIMELINE_SELECTED_BACKGROUND = '#3B3F42';
@@ -44,14 +46,27 @@ const getTimelineSelectedTrackHighlightStyle = (timelineWidth) => ({
44
46
  width: timelineWidth,
45
47
  });
46
48
  exports.getTimelineSelectedTrackHighlightStyle = getTimelineSelectedTrackHighlightStyle;
47
- exports.SELECTION_ENABLED = false;
48
- exports.TIMELINE_TOP_DRAG = false;
49
- exports.ENABLE_OUTLINES = false;
49
+ exports.TIMELINE_BACKGROUND = '#0F1113';
50
+ exports.TIMELINE_TICKS_BACKGROUND = colors_1.BACKGROUND;
50
51
  const isTimelineSelectionModifierEvent = ({ shiftKey, metaKey, ctrlKey, }) => {
51
52
  return shiftKey || metaKey || ctrlKey;
52
53
  };
53
54
  exports.isTimelineSelectionModifierEvent = isTimelineSelectionModifierEvent;
55
+ const shouldSelectTimelineRowOnPointerDown = ({ selected, shiftKey, metaKey, ctrlKey, }) => {
56
+ return (!selected || (0, exports.isTimelineSelectionModifierEvent)({ shiftKey, metaKey, ctrlKey }));
57
+ };
58
+ exports.shouldSelectTimelineRowOnPointerDown = shouldSelectTimelineRowOnPointerDown;
54
59
  const getTimelineSelectionType = (item) => item.type;
60
+ const areTimelineSelectionTypesCompatible = (firstType, secondType) => {
61
+ if (firstType === secondType) {
62
+ return true;
63
+ }
64
+ return ((firstType === 'sequence-prop' && secondType === 'sequence-effect-prop') ||
65
+ (firstType === 'sequence-effect-prop' && secondType === 'sequence-prop') ||
66
+ (firstType === 'keyframe' && secondType === 'easing') ||
67
+ (firstType === 'easing' && secondType === 'keyframe'));
68
+ };
69
+ const isTimelineSelectionCompatibleWithType = (item, type) => areTimelineSelectionTypesCompatible(getTimelineSelectionType(item), type);
55
70
  const getTimelineSelectionAnchor = (selectedItems, previousAnchor, targetType) => {
56
71
  if (previousAnchor &&
57
72
  getTimelineSelectionType(previousAnchor) === targetType) {
@@ -66,11 +81,11 @@ const getTimelineSelectionAnchor = (selectedItems, previousAnchor, targetType) =
66
81
  return null;
67
82
  };
68
83
  const getRangeSelection = ({ anchor, clickedItem, allSelectableItems, }) => {
69
- const anchorKey = getTimelineSelectionKey(anchor);
70
- const clickedKey = getTimelineSelectionKey(clickedItem);
84
+ const anchorKey = (0, exports.getTimelineSelectionKey)(anchor);
85
+ const clickedKey = (0, exports.getTimelineSelectionKey)(clickedItem);
71
86
  const orderedOfType = allSelectableItems.filter((item) => getTimelineSelectionType(item) === clickedItem.type);
72
- const anchorIndex = orderedOfType.findIndex((item) => getTimelineSelectionKey(item) === anchorKey);
73
- const clickedIndex = orderedOfType.findIndex((item) => getTimelineSelectionKey(item) === clickedKey);
87
+ const anchorIndex = orderedOfType.findIndex((item) => (0, exports.getTimelineSelectionKey)(item) === anchorKey);
88
+ const clickedIndex = orderedOfType.findIndex((item) => (0, exports.getTimelineSelectionKey)(item) === clickedKey);
74
89
  if (anchorIndex === -1 || clickedIndex === -1) {
75
90
  return [clickedItem];
76
91
  }
@@ -83,7 +98,7 @@ const getTimelineSelectionAfterInteraction = ({ currentState, clickedItem, inter
83
98
  const { selectedItems, anchor: previousAnchor } = currentState;
84
99
  const clickedType = getTimelineSelectionType(clickedItem);
85
100
  const nextAnchor = getTimelineSelectionAnchor(selectedItems, previousAnchor, clickedType);
86
- const clickedKey = getTimelineSelectionKey(clickedItem);
101
+ const clickedKey = (0, exports.getTimelineSelectionKey)(clickedItem);
87
102
  if (interaction.shiftKey && nextAnchor) {
88
103
  return {
89
104
  selectedItems: getRangeSelection({
@@ -95,22 +110,22 @@ const getTimelineSelectionAfterInteraction = ({ currentState, clickedItem, inter
95
110
  };
96
111
  }
97
112
  if (interaction.toggleKey) {
98
- const sameTypeItems = selectedItems.filter((item) => getTimelineSelectionType(item) === clickedType);
99
- const existingKeySet = new Set(sameTypeItems.map(getTimelineSelectionKey));
113
+ const compatibleItems = selectedItems.filter((item) => isTimelineSelectionCompatibleWithType(item, clickedType));
114
+ const existingKeySet = new Set(compatibleItems.map(exports.getTimelineSelectionKey));
100
115
  if (existingKeySet.has(clickedKey)) {
101
- const toggledSelection = sameTypeItems.filter((item) => getTimelineSelectionKey(item) !== clickedKey);
116
+ const toggledSelection = compatibleItems.filter((item) => (0, exports.getTimelineSelectionKey)(item) !== clickedKey);
102
117
  return {
103
118
  selectedItems: toggledSelection,
104
119
  anchor: toggledSelection.length === 0 ? null : clickedItem,
105
120
  };
106
121
  }
107
122
  const selectableOrderMap = new Map(allSelectableItems
108
- .filter((item) => getTimelineSelectionType(item) === clickedType)
109
- .map((item, index) => [getTimelineSelectionKey(item), index]));
110
- const extendedSelection = [...sameTypeItems, clickedItem].sort((a, b) => {
123
+ .filter((item) => isTimelineSelectionCompatibleWithType(item, clickedType))
124
+ .map((item, index) => [(0, exports.getTimelineSelectionKey)(item), index]));
125
+ const extendedSelection = [...compatibleItems, clickedItem].sort((a, b) => {
111
126
  var _a, _b;
112
- return (((_a = selectableOrderMap.get(getTimelineSelectionKey(a))) !== null && _a !== void 0 ? _a : 0) -
113
- ((_b = selectableOrderMap.get(getTimelineSelectionKey(b))) !== null && _b !== void 0 ? _b : 0));
127
+ return (((_a = selectableOrderMap.get((0, exports.getTimelineSelectionKey)(a))) !== null && _a !== void 0 ? _a : 0) -
128
+ ((_b = selectableOrderMap.get((0, exports.getTimelineSelectionKey)(b))) !== null && _b !== void 0 ? _b : 0));
114
129
  });
115
130
  return {
116
131
  selectedItems: extendedSelection,
@@ -123,13 +138,80 @@ const getTimelineSelectionAfterInteraction = ({ currentState, clickedItem, inter
123
138
  };
124
139
  };
125
140
  exports.getTimelineSelectionAfterInteraction = getTimelineSelectionAfterInteraction;
141
+ const getNormalizedTimelineMarqueeRect = ({ startX, startY, currentX, currentY, }) => ({
142
+ left: Math.min(startX, currentX),
143
+ top: Math.min(startY, currentY),
144
+ right: Math.max(startX, currentX),
145
+ bottom: Math.max(startY, currentY),
146
+ });
147
+ exports.getNormalizedTimelineMarqueeRect = getNormalizedTimelineMarqueeRect;
148
+ const getClampedTimelineMarqueePoint = ({ x, y, bounds, }) => ({
149
+ x: Math.min(bounds.right, Math.max(bounds.left, x)),
150
+ y: Math.min(bounds.bottom, Math.max(bounds.top, y)),
151
+ });
152
+ exports.getClampedTimelineMarqueePoint = getClampedTimelineMarqueePoint;
153
+ const timelineMarqueeRectsIntersect = (a, b) => a.left <= b.right &&
154
+ a.right >= b.left &&
155
+ a.top <= b.bottom &&
156
+ a.bottom >= b.top;
157
+ exports.timelineMarqueeRectsIntersect = timelineMarqueeRectsIntersect;
158
+ const getTimelineMarqueeSelectionKind = (item) => {
159
+ if (item.type === 'sequence') {
160
+ return 'sequence';
161
+ }
162
+ if (item.type === 'keyframe' || item.type === 'easing') {
163
+ return 'keyframes-and-easings';
164
+ }
165
+ return null;
166
+ };
167
+ const isTimelineSelectionCompatibleWithMarqueeKind = (item, kind) => {
168
+ if (kind === 'sequence') {
169
+ return item.type === 'sequence';
170
+ }
171
+ return item.type === 'keyframe' || item.type === 'easing';
172
+ };
173
+ const getTimelineMarqueeSelection = ({ candidates, lockedSelectionKind, marqueeRect, }) => {
174
+ const intersectingCandidates = candidates.filter((candidate) => {
175
+ return (getTimelineMarqueeSelectionKind(candidate.item) !== null &&
176
+ (0, exports.timelineMarqueeRectsIntersect)(candidate.rect, marqueeRect));
177
+ });
178
+ const getFirstIntersectingSelectionKind = () => intersectingCandidates.length === 0
179
+ ? null
180
+ : getTimelineMarqueeSelectionKind(intersectingCandidates[0].item);
181
+ let nextLockedSelectionKind = lockedSelectionKind !== null && lockedSelectionKind !== void 0 ? lockedSelectionKind : getFirstIntersectingSelectionKind();
182
+ const getSelectedItemsForKind = (kind) => intersectingCandidates
183
+ .filter((candidate) => isTimelineSelectionCompatibleWithMarqueeKind(candidate.item, kind))
184
+ .map((candidate) => candidate.item);
185
+ if (nextLockedSelectionKind === null) {
186
+ return { lockedSelectionKind: null, selectedItems: [] };
187
+ }
188
+ let selectedItems = getSelectedItemsForKind(nextLockedSelectionKind);
189
+ if (lockedSelectionKind !== null && selectedItems.length === 0) {
190
+ nextLockedSelectionKind = getFirstIntersectingSelectionKind();
191
+ selectedItems =
192
+ nextLockedSelectionKind === null
193
+ ? []
194
+ : getSelectedItemsForKind(nextLockedSelectionKind);
195
+ }
196
+ return {
197
+ lockedSelectionKind: nextLockedSelectionKind,
198
+ selectedItems,
199
+ };
200
+ };
201
+ exports.getTimelineMarqueeSelection = getTimelineMarqueeSelection;
126
202
  const defaultTimelineSelectionContextValue = {
127
203
  canSelect: false,
204
+ canSelectEasing: false,
128
205
  selectedItems: [],
129
206
  isSelected: () => false,
130
207
  selectItem: () => undefined,
131
208
  selectItems: () => undefined,
132
209
  registerSelectableItem: () => () => undefined,
210
+ registerMarqueeSelectableItem: () => () => undefined,
211
+ getMarqueeSelection: () => ({
212
+ lockedSelectionKind: null,
213
+ selectedItems: [],
214
+ }),
133
215
  containsSelection: () => false,
134
216
  clearSelection: () => undefined,
135
217
  };
@@ -197,6 +279,7 @@ const getTimelineSelectionKey = (item) => {
197
279
  throw new Error(`Unexpected timeline selection type: ${item}`);
198
280
  }
199
281
  };
282
+ exports.getTimelineSelectionKey = getTimelineSelectionKey;
200
283
  const nodePathDescendsFrom = (descendant, ancestor) => {
201
284
  if ((0, studio_shared_1.stringifySequenceExpandedRowKey)(descendant.sequenceSubscriptionKey) !==
202
285
  (0, studio_shared_1.stringifySequenceExpandedRowKey)(ancestor.sequenceSubscriptionKey)) {
@@ -258,28 +341,32 @@ const TimelineSelectAllKeybindings = ({ timeline }) => {
258
341
  exports.TimelineSelectAllKeybindings = TimelineSelectAllKeybindings;
259
342
  const TimelineSelectionProvider = ({ children }) => {
260
343
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
261
- const canSelect = (exports.SELECTION_ENABLED || exports.ENABLE_OUTLINES) &&
262
- previewServerState.type === 'connected' &&
344
+ const canSelect = previewServerState.type === 'connected' &&
345
+ !window.remotion_isReadOnlyStudio;
346
+ const canSelectEasing = previewServerState.type === 'connected' &&
263
347
  !window.remotion_isReadOnlyStudio;
264
348
  const [selectedItems, setSelectedItems] = (0, react_1.useState)([]);
265
349
  const selectionAnchor = (0, react_1.useRef)(null);
266
350
  const selectableItemsOrder = (0, react_1.useRef)(new Map());
267
351
  const selectableItems = (0, react_1.useRef)(new Map());
352
+ const marqueeSelectableItems = (0, react_1.useRef)(new Map());
268
353
  const registrationCounter = (0, react_1.useRef)(0);
354
+ const marqueeRegistrationCounter = (0, react_1.useRef)(0);
269
355
  (0, react_1.useEffect)(() => {
270
- if (!canSelect) {
356
+ if (!canSelect && !canSelectEasing) {
271
357
  setSelectedItems([]);
272
358
  }
273
- }, [canSelect]);
274
- const selectedKeys = (0, react_1.useMemo)(() => new Set(selectedItems.map(getTimelineSelectionKey)), [selectedItems]);
359
+ }, [canSelect, canSelectEasing]);
360
+ const canSelectItem = (0, react_1.useCallback)((item) => canSelect || (canSelectEasing && item.type === 'easing'), [canSelect, canSelectEasing]);
361
+ const selectedKeys = (0, react_1.useMemo)(() => new Set(selectedItems.map(exports.getTimelineSelectionKey)), [selectedItems]);
275
362
  const isSelected = (0, react_1.useCallback)((item) => {
276
- return selectedKeys.has(getTimelineSelectionKey(item));
363
+ return selectedKeys.has((0, exports.getTimelineSelectionKey)(item));
277
364
  }, [selectedKeys]);
278
365
  const selectItem = (0, react_1.useCallback)((item, interaction = {
279
366
  shiftKey: false,
280
367
  toggleKey: false,
281
368
  }) => {
282
- if (!canSelect) {
369
+ if (!canSelectItem(item)) {
283
370
  return;
284
371
  }
285
372
  setSelectedItems((currentSelectedItems) => {
@@ -287,8 +374,8 @@ const TimelineSelectionProvider = ({ children }) => {
287
374
  ...selectableItems.current.values(),
288
375
  ].sort((a, b) => {
289
376
  var _a, _b;
290
- return (((_a = selectableItemsOrder.current.get(getTimelineSelectionKey(a))) !== null && _a !== void 0 ? _a : 0) -
291
- ((_b = selectableItemsOrder.current.get(getTimelineSelectionKey(b))) !== null && _b !== void 0 ? _b : 0));
377
+ return (((_a = selectableItemsOrder.current.get((0, exports.getTimelineSelectionKey)(a))) !== null && _a !== void 0 ? _a : 0) -
378
+ ((_b = selectableItemsOrder.current.get((0, exports.getTimelineSelectionKey)(b))) !== null && _b !== void 0 ? _b : 0));
292
379
  });
293
380
  const nextState = (0, exports.getTimelineSelectionAfterInteraction)({
294
381
  currentState: {
@@ -302,17 +389,17 @@ const TimelineSelectionProvider = ({ children }) => {
302
389
  selectionAnchor.current = nextState.anchor;
303
390
  return nextState.selectedItems;
304
391
  });
305
- }, [canSelect]);
392
+ }, [canSelectItem]);
306
393
  const selectItems = (0, react_1.useCallback)((items) => {
307
- if (!canSelect) {
394
+ if (!items.every(canSelectItem)) {
308
395
  return;
309
396
  }
310
397
  selectionAnchor.current =
311
398
  items.length === 0 ? null : items[items.length - 1];
312
399
  setSelectedItems(items);
313
- }, [canSelect]);
400
+ }, [canSelectItem]);
314
401
  const registerSelectableItem = (0, react_1.useCallback)((item) => {
315
- const key = getTimelineSelectionKey(item);
402
+ const key = (0, exports.getTimelineSelectionKey)(item);
316
403
  const registrationOrder = registrationCounter.current;
317
404
  registrationCounter.current += 1;
318
405
  selectableItems.current.set(key, item);
@@ -322,6 +409,48 @@ const TimelineSelectionProvider = ({ children }) => {
322
409
  selectableItemsOrder.current.delete(key);
323
410
  };
324
411
  }, []);
412
+ const registerMarqueeSelectableItem = (0, react_1.useCallback)((item, getRect) => {
413
+ const key = (0, exports.getTimelineSelectionKey)(item);
414
+ const registrationOrder = marqueeRegistrationCounter.current;
415
+ marqueeRegistrationCounter.current += 1;
416
+ marqueeSelectableItems.current.set(key, {
417
+ getRect,
418
+ item,
419
+ order: registrationOrder,
420
+ });
421
+ return () => {
422
+ marqueeSelectableItems.current.delete(key);
423
+ };
424
+ }, []);
425
+ const getMarqueeSelectionForRect = (0, react_1.useCallback)((marqueeRect, lockedSelectionKind) => {
426
+ const candidates = [...marqueeSelectableItems.current.values()]
427
+ .sort((a, b) => a.order - b.order)
428
+ .flatMap((candidate) => {
429
+ if (!canSelectItem(candidate.item)) {
430
+ return [];
431
+ }
432
+ const rect = candidate.getRect();
433
+ if (rect === null) {
434
+ return [];
435
+ }
436
+ return [
437
+ {
438
+ item: candidate.item,
439
+ rect: {
440
+ bottom: rect.bottom,
441
+ left: rect.left,
442
+ right: rect.right,
443
+ top: rect.top,
444
+ },
445
+ },
446
+ ];
447
+ });
448
+ return (0, exports.getTimelineMarqueeSelection)({
449
+ candidates,
450
+ lockedSelectionKind,
451
+ marqueeRect,
452
+ });
453
+ }, [canSelectItem]);
325
454
  const clearSelection = (0, react_1.useCallback)(() => {
326
455
  selectionAnchor.current = null;
327
456
  setSelectedItems([]);
@@ -331,20 +460,26 @@ const TimelineSelectionProvider = ({ children }) => {
331
460
  }, [selectedItems]);
332
461
  const value = (0, react_1.useMemo)(() => ({
333
462
  canSelect,
463
+ canSelectEasing,
334
464
  selectedItems,
335
465
  isSelected,
336
466
  selectItem,
337
467
  selectItems,
338
468
  registerSelectableItem,
469
+ registerMarqueeSelectableItem,
470
+ getMarqueeSelection: getMarqueeSelectionForRect,
339
471
  containsSelection,
340
472
  clearSelection,
341
473
  }), [
342
474
  canSelect,
475
+ canSelectEasing,
343
476
  selectedItems,
344
477
  isSelected,
345
478
  selectItem,
346
479
  selectItems,
347
480
  registerSelectableItem,
481
+ registerMarqueeSelectableItem,
482
+ getMarqueeSelectionForRect,
348
483
  containsSelection,
349
484
  clearSelection,
350
485
  ]);
@@ -358,6 +493,8 @@ const useTimelineSelection = () => {
358
493
  return (0, react_1.useContext)(TimelineSelectionContext);
359
494
  };
360
495
  exports.useTimelineSelection = useTimelineSelection;
496
+ exports.TIMELINE_MARQUEE_ITEM_ATTR = 'data-timeline-marquee-item';
497
+ exports.TIMELINE_SCRUBBER_ATTR = 'data-timeline-scrubber';
361
498
  const useCurrentTimelineSelectionStateAsRef = () => {
362
499
  const currentSelection = (0, react_1.useContext)(CurrentTimelineSelectionContext);
363
500
  if (currentSelection === null) {
@@ -366,6 +503,123 @@ const useCurrentTimelineSelectionStateAsRef = () => {
366
503
  return currentSelection;
367
504
  };
368
505
  exports.useCurrentTimelineSelectionStateAsRef = useCurrentTimelineSelectionStateAsRef;
506
+ const useTimelineMarqueeSelection = () => {
507
+ const { canSelect, canSelectEasing, getMarqueeSelection, selectItems } = (0, exports.useTimelineSelection)();
508
+ const { isHighestContext } = (0, z_index_1.useZIndex)();
509
+ const [marqueeRect, setMarqueeRect] = (0, react_1.useState)(null);
510
+ const onPointerDownCapture = (0, react_1.useCallback)((event) => {
511
+ if (!isHighestContext) {
512
+ return;
513
+ }
514
+ if (event.button !== 0 || (!canSelect && !canSelectEasing)) {
515
+ return;
516
+ }
517
+ if (event.shiftKey || event.metaKey || event.ctrlKey) {
518
+ return;
519
+ }
520
+ if (!(event.target instanceof Element)) {
521
+ return;
522
+ }
523
+ if (event.target.closest(`[${exports.TIMELINE_MARQUEE_ITEM_ATTR}]`) ||
524
+ event.target.closest(`[${exports.TIMELINE_SCRUBBER_ATTR}]`)) {
525
+ return;
526
+ }
527
+ const { currentTarget: target, pointerId } = event;
528
+ if (target.setPointerCapture) {
529
+ target.setPointerCapture(pointerId);
530
+ }
531
+ const initialBounds = target.getBoundingClientRect();
532
+ const marqueeBounds = {
533
+ bottom: initialBounds.bottom,
534
+ left: initialBounds.left,
535
+ right: initialBounds.right,
536
+ top: initialBounds.top,
537
+ };
538
+ const start = (0, exports.getClampedTimelineMarqueePoint)({
539
+ bounds: marqueeBounds,
540
+ x: event.clientX,
541
+ y: event.clientY,
542
+ });
543
+ const startX = start.x;
544
+ const startY = start.y;
545
+ const previousUserSelect = document.body.style.userSelect;
546
+ const previousWebkitUserSelect = document.body.style.webkitUserSelect;
547
+ document.body.style.userSelect = 'none';
548
+ document.body.style.webkitUserSelect = 'none';
549
+ let hasDragged = false;
550
+ let lockedSelectionKind = null;
551
+ const cleanup = () => {
552
+ var _a;
553
+ window.removeEventListener('pointermove', onPointerMove);
554
+ window.removeEventListener('pointerup', onPointerUp);
555
+ window.removeEventListener('pointercancel', onPointerCancel);
556
+ if ((_a = target.hasPointerCapture) === null || _a === void 0 ? void 0 : _a.call(target, pointerId)) {
557
+ target.releasePointerCapture(pointerId);
558
+ }
559
+ document.body.style.userSelect = previousUserSelect;
560
+ document.body.style.webkitUserSelect = previousWebkitUserSelect;
561
+ setMarqueeRect(null);
562
+ };
563
+ const updateSelection = (clientX, clientY) => {
564
+ const current = (0, exports.getClampedTimelineMarqueePoint)({
565
+ bounds: marqueeBounds,
566
+ x: clientX,
567
+ y: clientY,
568
+ });
569
+ if (!hasDragged &&
570
+ Math.max(Math.abs(current.x - startX), Math.abs(current.y - startY)) <
571
+ 3) {
572
+ return;
573
+ }
574
+ hasDragged = true;
575
+ const rect = (0, exports.getNormalizedTimelineMarqueeRect)({
576
+ currentX: current.x,
577
+ currentY: current.y,
578
+ startX,
579
+ startY,
580
+ });
581
+ const nextSelection = getMarqueeSelection(rect, lockedSelectionKind);
582
+ lockedSelectionKind = nextSelection.lockedSelectionKind;
583
+ setMarqueeRect(rect);
584
+ selectItems(nextSelection.selectedItems);
585
+ };
586
+ const onPointerMove = (moveEvent) => {
587
+ updateSelection(moveEvent.clientX, moveEvent.clientY);
588
+ };
589
+ const onPointerUp = (upEvent) => {
590
+ updateSelection(upEvent.clientX, upEvent.clientY);
591
+ cleanup();
592
+ };
593
+ const onPointerCancel = () => {
594
+ cleanup();
595
+ };
596
+ window.addEventListener('pointermove', onPointerMove);
597
+ window.addEventListener('pointerup', onPointerUp);
598
+ window.addEventListener('pointercancel', onPointerCancel);
599
+ }, [
600
+ canSelect,
601
+ canSelectEasing,
602
+ getMarqueeSelection,
603
+ isHighestContext,
604
+ selectItems,
605
+ ]);
606
+ return { marqueeRect, onPointerDownCapture };
607
+ };
608
+ exports.useTimelineMarqueeSelection = useTimelineMarqueeSelection;
609
+ const useTimelineMarqueeSelectableItem = (item, ref) => {
610
+ const { registerMarqueeSelectableItem } = (0, exports.useTimelineSelection)();
611
+ (0, react_1.useEffect)(() => {
612
+ if (item === null) {
613
+ return;
614
+ }
615
+ return registerMarqueeSelectableItem(item, () => {
616
+ var _a;
617
+ var _b;
618
+ return (_b = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) !== null && _b !== void 0 ? _b : null;
619
+ });
620
+ }, [item, ref, registerMarqueeSelectableItem]);
621
+ };
622
+ exports.useTimelineMarqueeSelectableItem = useTimelineMarqueeSelectableItem;
369
623
  const useTimelineRowSelection = (nodePathInfo) => {
370
624
  const { canSelect, isSelected, selectItem, registerSelectableItem } = (0, exports.useTimelineSelection)();
371
625
  const selectionItem = (0, react_1.useMemo)(() => (0, exports.getTimelineSelectionFromNodePathInfo)(nodePathInfo), [nodePathInfo]);
@@ -385,6 +639,7 @@ const useTimelineRowSelection = (nodePathInfo) => {
385
639
  return {
386
640
  onSelect,
387
641
  selectable: canSelect && selectionItem !== null,
642
+ selectionItem,
388
643
  selected,
389
644
  };
390
645
  };
@@ -406,12 +661,13 @@ const useTimelineKeyframeSelection = (nodePathInfo, frame) => {
406
661
  return {
407
662
  onSelect,
408
663
  selectable: canSelect,
664
+ selectionItem,
409
665
  selected,
410
666
  };
411
667
  };
412
668
  exports.useTimelineKeyframeSelection = useTimelineKeyframeSelection;
413
669
  const useTimelineEasingSelection = ({ nodePathInfo, fromFrame, toFrame, segmentIndex, }) => {
414
- const { canSelect, isSelected, selectItem, registerSelectableItem } = (0, exports.useTimelineSelection)();
670
+ const { canSelectEasing, isSelected, selectItem, registerSelectableItem } = (0, exports.useTimelineSelection)();
415
671
  const selectionItem = (0, react_1.useMemo)(() => ({
416
672
  type: 'easing',
417
673
  nodePathInfo,
@@ -428,8 +684,9 @@ const useTimelineEasingSelection = ({ nodePathInfo, fromFrame, toFrame, segmentI
428
684
  }, [selectItem, selectionItem]);
429
685
  return {
430
686
  onSelect,
431
- selectable: canSelect,
687
+ selectable: canSelectEasing,
432
688
  selected,
689
+ selectionItem,
433
690
  };
434
691
  };
435
692
  exports.useTimelineEasingSelection = useTimelineEasingSelection;
@@ -62,19 +62,28 @@ const TimelineSequenceFn = ({ s, nodePathInfo, sequenceFrameOffset }) => {
62
62
  };
63
63
  const TimelineSequenceCurrentFrame = ({ s, displayDurationInFrames, premountWidth, postmountWidth, style, children, nodePathInfo, sequenceFrameOffset, fromCanUpdate, onMoveDragPointerDown, }) => {
64
64
  var _a, _b;
65
- const { onSelect, selectable } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
65
+ const ref = (0, react_1.useRef)(null);
66
+ const { onSelect, selectable, selected, selectionItem } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
67
+ (0, TimelineSelection_1.useTimelineMarqueeSelectableItem)(selectionItem, ref);
66
68
  const onPointerDown = (0, react_1.useCallback)((e) => {
67
69
  if (e.button === 0) {
68
70
  e.stopPropagation();
69
- onSelect({
71
+ if ((0, TimelineSelection_1.shouldSelectTimelineRowOnPointerDown)({
72
+ selected,
70
73
  shiftKey: e.shiftKey,
71
- toggleKey: e.metaKey || e.ctrlKey,
72
- });
73
- if (TimelineSelection_1.TIMELINE_TOP_DRAG && fromCanUpdate) {
74
+ metaKey: e.metaKey,
75
+ ctrlKey: e.ctrlKey,
76
+ })) {
77
+ onSelect({
78
+ shiftKey: e.shiftKey,
79
+ toggleKey: e.metaKey || e.ctrlKey,
80
+ });
81
+ }
82
+ if (fromCanUpdate) {
74
83
  onMoveDragPointerDown(e);
75
84
  }
76
85
  }
77
- }, [fromCanUpdate, onMoveDragPointerDown, onSelect]);
86
+ }, [fromCanUpdate, onMoveDragPointerDown, onSelect, selected]);
78
87
  const frame = (0, remotion_1.useCurrentFrame)();
79
88
  const relativeFrame = frame - s.from;
80
89
  const sequenceFrame = relativeFrame + sequenceFrameOffset;
@@ -94,7 +103,7 @@ const TimelineSequenceCurrentFrame = ({ s, displayDurationInFrames, premountWidt
94
103
  opacity: isInRange ? 1 : 0.5,
95
104
  };
96
105
  }, [isInRange, style]);
97
- return (jsx_runtime_1.jsxs("div", { style: actualStyle, title: s.displayName, onPointerDown: selectable ? onPointerDown : undefined, children: [premountWidth ? (jsx_runtime_1.jsx("div", { style: {
106
+ return (jsx_runtime_1.jsxs("div", { ref: ref, [TimelineSelection_1.TIMELINE_MARQUEE_ITEM_ATTR]: true, style: actualStyle, title: s.displayName, onPointerDown: selectable ? onPointerDown : undefined, children: [premountWidth ? (jsx_runtime_1.jsx("div", { style: {
98
107
  width: premountWidth,
99
108
  height: '100%',
100
109
  background: `repeating-linear-gradient(
@@ -208,8 +217,7 @@ const TimelineSequenceInner = ({ s, windowWidth, nodePathInfo, sequenceFrameOffs
208
217
  overflow: 'hidden',
209
218
  };
210
219
  }, [marginLeft, s.type, width]);
211
- const showRightEdgeDragHandle = TimelineSelection_1.TIMELINE_TOP_DRAG &&
212
- (s.type === 'sequence' || s.type === 'image') &&
220
+ const showRightEdgeDragHandle = (s.type === 'sequence' || s.type === 'image') &&
213
221
  !s.loopDisplay &&
214
222
  !s.isInsideSeries &&
215
223
  nodePath !== null &&