mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
chore: normalize line endings
This commit is contained in:
@@ -1,137 +1,137 @@
|
||||
import { useCallback } from "react";
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
import type { ElementRef } from "@/lib/timeline/types";
|
||||
|
||||
export function useElementSelection() {
|
||||
const editor = useEditor();
|
||||
const selectedElements = useEditor((e) => e.selection.getSelectedElements());
|
||||
|
||||
const isElementSelected = useCallback(
|
||||
({ trackId, elementId }: ElementRef) =>
|
||||
selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
),
|
||||
[selectedElements],
|
||||
);
|
||||
|
||||
const selectElement = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
editor.selection.setSelectedElements({
|
||||
elements: [{ trackId, elementId }],
|
||||
});
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
const addElementToSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
const alreadySelected = selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
);
|
||||
if (alreadySelected) return;
|
||||
|
||||
editor.selection.setSelectedElements({
|
||||
elements: [...selectedElements, { trackId, elementId }],
|
||||
});
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
const removeElementFromSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
editor.selection.setSelectedElements({
|
||||
elements: selectedElements.filter(
|
||||
(element) =>
|
||||
!(element.trackId === trackId && element.elementId === elementId),
|
||||
),
|
||||
});
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
const toggleElementSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
const alreadySelected = selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
);
|
||||
|
||||
if (alreadySelected) {
|
||||
removeElementFromSelection({ trackId, elementId });
|
||||
} else {
|
||||
addElementToSelection({ trackId, elementId });
|
||||
}
|
||||
},
|
||||
[selectedElements, addElementToSelection, removeElementFromSelection],
|
||||
);
|
||||
|
||||
const clearElementSelection = useCallback(() => {
|
||||
editor.selection.clearSelection();
|
||||
}, [editor]);
|
||||
|
||||
const setElementSelection = useCallback(
|
||||
({ elements }: { elements: ElementRef[] }) => {
|
||||
editor.selection.setSelectedElements({ elements });
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Merges elements into the current selection, deduplicating by identity.
|
||||
* Used for additive box-select where the pre-drag selection is preserved.
|
||||
*/
|
||||
const mergeElementsIntoSelection = useCallback(
|
||||
({ elements }: { elements: ElementRef[] }) => {
|
||||
const merged = [
|
||||
...selectedElements.filter(
|
||||
(selectedElement) =>
|
||||
!elements.some(
|
||||
(element) =>
|
||||
element.trackId === selectedElement.trackId &&
|
||||
element.elementId === selectedElement.elementId,
|
||||
),
|
||||
),
|
||||
...elements,
|
||||
];
|
||||
editor.selection.setSelectedElements({ elements: merged });
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Handles click interaction on an element.
|
||||
* - Regular click: select only this element
|
||||
* - Multi-key click (Ctrl/Cmd): toggle this element in selection
|
||||
*/
|
||||
const handleElementClick = useCallback(
|
||||
({
|
||||
trackId,
|
||||
elementId,
|
||||
isMultiKey,
|
||||
}: ElementRef & { isMultiKey: boolean }) => {
|
||||
if (isMultiKey) {
|
||||
toggleElementSelection({ trackId, elementId });
|
||||
} else {
|
||||
selectElement({ trackId, elementId });
|
||||
}
|
||||
},
|
||||
[toggleElementSelection, selectElement],
|
||||
);
|
||||
|
||||
return {
|
||||
selectedElements,
|
||||
isElementSelected,
|
||||
selectElement,
|
||||
setElementSelection,
|
||||
mergeElementsIntoSelection,
|
||||
addElementToSelection,
|
||||
removeElementFromSelection,
|
||||
toggleElementSelection,
|
||||
clearElementSelection,
|
||||
handleElementClick,
|
||||
};
|
||||
}
|
||||
import { useCallback } from "react";
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
import type { ElementRef } from "@/lib/timeline/types";
|
||||
|
||||
export function useElementSelection() {
|
||||
const editor = useEditor();
|
||||
const selectedElements = useEditor((e) => e.selection.getSelectedElements());
|
||||
|
||||
const isElementSelected = useCallback(
|
||||
({ trackId, elementId }: ElementRef) =>
|
||||
selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
),
|
||||
[selectedElements],
|
||||
);
|
||||
|
||||
const selectElement = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
editor.selection.setSelectedElements({
|
||||
elements: [{ trackId, elementId }],
|
||||
});
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
const addElementToSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
const alreadySelected = selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
);
|
||||
if (alreadySelected) return;
|
||||
|
||||
editor.selection.setSelectedElements({
|
||||
elements: [...selectedElements, { trackId, elementId }],
|
||||
});
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
const removeElementFromSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
editor.selection.setSelectedElements({
|
||||
elements: selectedElements.filter(
|
||||
(element) =>
|
||||
!(element.trackId === trackId && element.elementId === elementId),
|
||||
),
|
||||
});
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
const toggleElementSelection = useCallback(
|
||||
({ trackId, elementId }: ElementRef) => {
|
||||
const alreadySelected = selectedElements.some(
|
||||
(element) =>
|
||||
element.trackId === trackId && element.elementId === elementId,
|
||||
);
|
||||
|
||||
if (alreadySelected) {
|
||||
removeElementFromSelection({ trackId, elementId });
|
||||
} else {
|
||||
addElementToSelection({ trackId, elementId });
|
||||
}
|
||||
},
|
||||
[selectedElements, addElementToSelection, removeElementFromSelection],
|
||||
);
|
||||
|
||||
const clearElementSelection = useCallback(() => {
|
||||
editor.selection.clearSelection();
|
||||
}, [editor]);
|
||||
|
||||
const setElementSelection = useCallback(
|
||||
({ elements }: { elements: ElementRef[] }) => {
|
||||
editor.selection.setSelectedElements({ elements });
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Merges elements into the current selection, deduplicating by identity.
|
||||
* Used for additive box-select where the pre-drag selection is preserved.
|
||||
*/
|
||||
const mergeElementsIntoSelection = useCallback(
|
||||
({ elements }: { elements: ElementRef[] }) => {
|
||||
const merged = [
|
||||
...selectedElements.filter(
|
||||
(selectedElement) =>
|
||||
!elements.some(
|
||||
(element) =>
|
||||
element.trackId === selectedElement.trackId &&
|
||||
element.elementId === selectedElement.elementId,
|
||||
),
|
||||
),
|
||||
...elements,
|
||||
];
|
||||
editor.selection.setSelectedElements({ elements: merged });
|
||||
},
|
||||
[selectedElements, editor],
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Handles click interaction on an element.
|
||||
* - Regular click: select only this element
|
||||
* - Multi-key click (Ctrl/Cmd): toggle this element in selection
|
||||
*/
|
||||
const handleElementClick = useCallback(
|
||||
({
|
||||
trackId,
|
||||
elementId,
|
||||
isMultiKey,
|
||||
}: ElementRef & { isMultiKey: boolean }) => {
|
||||
if (isMultiKey) {
|
||||
toggleElementSelection({ trackId, elementId });
|
||||
} else {
|
||||
selectElement({ trackId, elementId });
|
||||
}
|
||||
},
|
||||
[toggleElementSelection, selectElement],
|
||||
);
|
||||
|
||||
return {
|
||||
selectedElements,
|
||||
isElementSelected,
|
||||
selectElement,
|
||||
setElementSelection,
|
||||
mergeElementsIntoSelection,
|
||||
addElementToSelection,
|
||||
removeElementFromSelection,
|
||||
toggleElementSelection,
|
||||
clearElementSelection,
|
||||
handleElementClick,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,229 +1,229 @@
|
||||
import { useCallback, useSyncExternalStore } from "react";
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
import type { SelectedKeyframeRef } from "@/lib/animation/types";
|
||||
|
||||
function getSelectedKeyframeId({
|
||||
keyframe,
|
||||
}: {
|
||||
keyframe: SelectedKeyframeRef;
|
||||
}): string {
|
||||
return `${keyframe.trackId}:${keyframe.elementId}:${keyframe.propertyPath}:${keyframe.keyframeId}`;
|
||||
}
|
||||
|
||||
function mergeUniqueKeyframes({
|
||||
keyframes,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
}): SelectedKeyframeRef[] {
|
||||
const keyframesById = new Map<string, SelectedKeyframeRef>();
|
||||
for (const keyframe of keyframes) {
|
||||
keyframesById.set(getSelectedKeyframeId({ keyframe }), keyframe);
|
||||
}
|
||||
return [...keyframesById.values()];
|
||||
}
|
||||
|
||||
export function useKeyframeSelection() {
|
||||
const editor = useEditor();
|
||||
const selectedKeyframes = useSyncExternalStore(
|
||||
(listener) => editor.selection.subscribe(listener),
|
||||
() => editor.selection.getSelectedKeyframes(),
|
||||
);
|
||||
const keyframeSelectionAnchor = useSyncExternalStore(
|
||||
(listener) => editor.selection.subscribe(listener),
|
||||
() => editor.selection.getKeyframeSelectionAnchor(),
|
||||
);
|
||||
|
||||
const isKeyframeSelected = useCallback(
|
||||
({ keyframe }: { keyframe: SelectedKeyframeRef }) => {
|
||||
const keyframeId = getSelectedKeyframeId({ keyframe });
|
||||
return selectedKeyframes.some(
|
||||
(selectedKeyframe) =>
|
||||
getSelectedKeyframeId({ keyframe: selectedKeyframe }) === keyframeId,
|
||||
);
|
||||
},
|
||||
[selectedKeyframes],
|
||||
);
|
||||
|
||||
const setKeyframeSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const uniqueKeyframes = mergeUniqueKeyframes({ keyframes });
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: uniqueKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? uniqueKeyframes[uniqueKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
const addKeyframesToSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const mergedKeyframes = mergeUniqueKeyframes({
|
||||
keyframes: [...selectedKeyframes, ...keyframes],
|
||||
});
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: mergedKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? mergedKeyframes[mergedKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[selectedKeyframes, editor],
|
||||
);
|
||||
|
||||
const removeKeyframesFromSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const keyframeIdsToRemove = new Set(
|
||||
keyframes.map((keyframe) => getSelectedKeyframeId({ keyframe })),
|
||||
);
|
||||
const nextKeyframes = selectedKeyframes.filter(
|
||||
(selectedKeyframe) =>
|
||||
!keyframeIdsToRemove.has(
|
||||
getSelectedKeyframeId({ keyframe: selectedKeyframe }),
|
||||
),
|
||||
);
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: nextKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? nextKeyframes[nextKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[selectedKeyframes, editor],
|
||||
);
|
||||
|
||||
const clearKeyframeSelection = useCallback(() => {
|
||||
editor.selection.clearKeyframeSelection();
|
||||
}, [editor]);
|
||||
|
||||
const toggleKeyframeSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
isMultiKey,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
isMultiKey: boolean;
|
||||
}) => {
|
||||
const anchorKeyframe = keyframes[0];
|
||||
const areAllKeyframesSelected = keyframes.every((keyframe) =>
|
||||
isKeyframeSelected({ keyframe }),
|
||||
);
|
||||
if (!isMultiKey) {
|
||||
setKeyframeSelection({ keyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
if (areAllKeyframesSelected) {
|
||||
removeKeyframesFromSelection({ keyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
addKeyframesToSelection({ keyframes, anchorKeyframe });
|
||||
},
|
||||
[
|
||||
setKeyframeSelection,
|
||||
isKeyframeSelected,
|
||||
removeKeyframesFromSelection,
|
||||
addKeyframesToSelection,
|
||||
],
|
||||
);
|
||||
|
||||
const selectKeyframeRange = useCallback(
|
||||
({
|
||||
orderedKeyframes,
|
||||
targetKeyframes,
|
||||
isAdditive,
|
||||
}: {
|
||||
orderedKeyframes: SelectedKeyframeRef[];
|
||||
targetKeyframes: SelectedKeyframeRef[];
|
||||
isAdditive: boolean;
|
||||
}) => {
|
||||
if (orderedKeyframes.length === 0 || targetKeyframes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorKeyframe =
|
||||
keyframeSelectionAnchor ??
|
||||
selectedKeyframes[selectedKeyframes.length - 1] ??
|
||||
targetKeyframes[0];
|
||||
if (!anchorKeyframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetKeyframeIds = new Set(
|
||||
targetKeyframes.map((keyframe) => getSelectedKeyframeId({ keyframe })),
|
||||
);
|
||||
const anchorId = getSelectedKeyframeId({ keyframe: anchorKeyframe });
|
||||
const anchorIndex = orderedKeyframes.findIndex(
|
||||
(keyframe) => getSelectedKeyframeId({ keyframe }) === anchorId,
|
||||
);
|
||||
if (anchorIndex === -1) {
|
||||
if (isAdditive) {
|
||||
addKeyframesToSelection({
|
||||
keyframes: targetKeyframes,
|
||||
anchorKeyframe,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setKeyframeSelection({ keyframes: targetKeyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
const targetIndexes = orderedKeyframes
|
||||
.map((keyframe, index) => ({
|
||||
keyframeId: getSelectedKeyframeId({ keyframe }),
|
||||
index,
|
||||
}))
|
||||
.filter(({ keyframeId }) => targetKeyframeIds.has(keyframeId))
|
||||
.map(({ index }) => index);
|
||||
if (targetIndexes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeStart = Math.min(anchorIndex, ...targetIndexes);
|
||||
const rangeEnd = Math.max(anchorIndex, ...targetIndexes);
|
||||
const rangeKeyframes = orderedKeyframes.slice(rangeStart, rangeEnd + 1);
|
||||
|
||||
if (isAdditive) {
|
||||
addKeyframesToSelection({ keyframes: rangeKeyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
setKeyframeSelection({ keyframes: rangeKeyframes, anchorKeyframe });
|
||||
},
|
||||
[
|
||||
keyframeSelectionAnchor,
|
||||
selectedKeyframes,
|
||||
addKeyframesToSelection,
|
||||
setKeyframeSelection,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
selectedKeyframes,
|
||||
keyframeSelectionAnchor,
|
||||
isKeyframeSelected,
|
||||
setKeyframeSelection,
|
||||
addKeyframesToSelection,
|
||||
removeKeyframesFromSelection,
|
||||
clearKeyframeSelection,
|
||||
toggleKeyframeSelection,
|
||||
selectKeyframeRange,
|
||||
};
|
||||
}
|
||||
import { useCallback, useSyncExternalStore } from "react";
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
import type { SelectedKeyframeRef } from "@/lib/animation/types";
|
||||
|
||||
function getSelectedKeyframeId({
|
||||
keyframe,
|
||||
}: {
|
||||
keyframe: SelectedKeyframeRef;
|
||||
}): string {
|
||||
return `${keyframe.trackId}:${keyframe.elementId}:${keyframe.propertyPath}:${keyframe.keyframeId}`;
|
||||
}
|
||||
|
||||
function mergeUniqueKeyframes({
|
||||
keyframes,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
}): SelectedKeyframeRef[] {
|
||||
const keyframesById = new Map<string, SelectedKeyframeRef>();
|
||||
for (const keyframe of keyframes) {
|
||||
keyframesById.set(getSelectedKeyframeId({ keyframe }), keyframe);
|
||||
}
|
||||
return [...keyframesById.values()];
|
||||
}
|
||||
|
||||
export function useKeyframeSelection() {
|
||||
const editor = useEditor();
|
||||
const selectedKeyframes = useSyncExternalStore(
|
||||
(listener) => editor.selection.subscribe(listener),
|
||||
() => editor.selection.getSelectedKeyframes(),
|
||||
);
|
||||
const keyframeSelectionAnchor = useSyncExternalStore(
|
||||
(listener) => editor.selection.subscribe(listener),
|
||||
() => editor.selection.getKeyframeSelectionAnchor(),
|
||||
);
|
||||
|
||||
const isKeyframeSelected = useCallback(
|
||||
({ keyframe }: { keyframe: SelectedKeyframeRef }) => {
|
||||
const keyframeId = getSelectedKeyframeId({ keyframe });
|
||||
return selectedKeyframes.some(
|
||||
(selectedKeyframe) =>
|
||||
getSelectedKeyframeId({ keyframe: selectedKeyframe }) === keyframeId,
|
||||
);
|
||||
},
|
||||
[selectedKeyframes],
|
||||
);
|
||||
|
||||
const setKeyframeSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const uniqueKeyframes = mergeUniqueKeyframes({ keyframes });
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: uniqueKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? uniqueKeyframes[uniqueKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[editor],
|
||||
);
|
||||
|
||||
const addKeyframesToSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const mergedKeyframes = mergeUniqueKeyframes({
|
||||
keyframes: [...selectedKeyframes, ...keyframes],
|
||||
});
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: mergedKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? mergedKeyframes[mergedKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[selectedKeyframes, editor],
|
||||
);
|
||||
|
||||
const removeKeyframesFromSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
anchorKeyframe,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
anchorKeyframe?: SelectedKeyframeRef;
|
||||
}) => {
|
||||
const keyframeIdsToRemove = new Set(
|
||||
keyframes.map((keyframe) => getSelectedKeyframeId({ keyframe })),
|
||||
);
|
||||
const nextKeyframes = selectedKeyframes.filter(
|
||||
(selectedKeyframe) =>
|
||||
!keyframeIdsToRemove.has(
|
||||
getSelectedKeyframeId({ keyframe: selectedKeyframe }),
|
||||
),
|
||||
);
|
||||
editor.selection.setSelectedKeyframes({
|
||||
keyframes: nextKeyframes,
|
||||
anchorKeyframe:
|
||||
anchorKeyframe ?? nextKeyframes[nextKeyframes.length - 1] ?? null,
|
||||
});
|
||||
},
|
||||
[selectedKeyframes, editor],
|
||||
);
|
||||
|
||||
const clearKeyframeSelection = useCallback(() => {
|
||||
editor.selection.clearKeyframeSelection();
|
||||
}, [editor]);
|
||||
|
||||
const toggleKeyframeSelection = useCallback(
|
||||
({
|
||||
keyframes,
|
||||
isMultiKey,
|
||||
}: {
|
||||
keyframes: SelectedKeyframeRef[];
|
||||
isMultiKey: boolean;
|
||||
}) => {
|
||||
const anchorKeyframe = keyframes[0];
|
||||
const areAllKeyframesSelected = keyframes.every((keyframe) =>
|
||||
isKeyframeSelected({ keyframe }),
|
||||
);
|
||||
if (!isMultiKey) {
|
||||
setKeyframeSelection({ keyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
if (areAllKeyframesSelected) {
|
||||
removeKeyframesFromSelection({ keyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
addKeyframesToSelection({ keyframes, anchorKeyframe });
|
||||
},
|
||||
[
|
||||
setKeyframeSelection,
|
||||
isKeyframeSelected,
|
||||
removeKeyframesFromSelection,
|
||||
addKeyframesToSelection,
|
||||
],
|
||||
);
|
||||
|
||||
const selectKeyframeRange = useCallback(
|
||||
({
|
||||
orderedKeyframes,
|
||||
targetKeyframes,
|
||||
isAdditive,
|
||||
}: {
|
||||
orderedKeyframes: SelectedKeyframeRef[];
|
||||
targetKeyframes: SelectedKeyframeRef[];
|
||||
isAdditive: boolean;
|
||||
}) => {
|
||||
if (orderedKeyframes.length === 0 || targetKeyframes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorKeyframe =
|
||||
keyframeSelectionAnchor ??
|
||||
selectedKeyframes[selectedKeyframes.length - 1] ??
|
||||
targetKeyframes[0];
|
||||
if (!anchorKeyframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetKeyframeIds = new Set(
|
||||
targetKeyframes.map((keyframe) => getSelectedKeyframeId({ keyframe })),
|
||||
);
|
||||
const anchorId = getSelectedKeyframeId({ keyframe: anchorKeyframe });
|
||||
const anchorIndex = orderedKeyframes.findIndex(
|
||||
(keyframe) => getSelectedKeyframeId({ keyframe }) === anchorId,
|
||||
);
|
||||
if (anchorIndex === -1) {
|
||||
if (isAdditive) {
|
||||
addKeyframesToSelection({
|
||||
keyframes: targetKeyframes,
|
||||
anchorKeyframe,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setKeyframeSelection({ keyframes: targetKeyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
const targetIndexes = orderedKeyframes
|
||||
.map((keyframe, index) => ({
|
||||
keyframeId: getSelectedKeyframeId({ keyframe }),
|
||||
index,
|
||||
}))
|
||||
.filter(({ keyframeId }) => targetKeyframeIds.has(keyframeId))
|
||||
.map(({ index }) => index);
|
||||
if (targetIndexes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeStart = Math.min(anchorIndex, ...targetIndexes);
|
||||
const rangeEnd = Math.max(anchorIndex, ...targetIndexes);
|
||||
const rangeKeyframes = orderedKeyframes.slice(rangeStart, rangeEnd + 1);
|
||||
|
||||
if (isAdditive) {
|
||||
addKeyframesToSelection({ keyframes: rangeKeyframes, anchorKeyframe });
|
||||
return;
|
||||
}
|
||||
|
||||
setKeyframeSelection({ keyframes: rangeKeyframes, anchorKeyframe });
|
||||
},
|
||||
[
|
||||
keyframeSelectionAnchor,
|
||||
selectedKeyframes,
|
||||
addKeyframesToSelection,
|
||||
setKeyframeSelection,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
selectedKeyframes,
|
||||
keyframeSelectionAnchor,
|
||||
isKeyframeSelected,
|
||||
setKeyframeSelection,
|
||||
addKeyframesToSelection,
|
||||
removeKeyframesFromSelection,
|
||||
clearKeyframeSelection,
|
||||
toggleKeyframeSelection,
|
||||
selectKeyframeRange,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user