1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
import { useCallback, useSyncExternalStore } from "react";
import { useEditor } from "@/hooks/use-editor";
type ElementRef = { trackId: string; elementId: string };
export function useElementSelection() {
const editor = useEditor();
const selectedElements = useSyncExternalStore(
(listener) => editor.selection.subscribe(listener),
() => editor.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],
);
/**
* 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,
addElementToSelection,
removeElementFromSelection,
toggleElementSelection,
clearElementSelection,
handleElementClick,
};
}
|