@strapi/upload 5.50.2 → 5.51.1
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.
- package/dist/admin/future/pages/Assets/AssetsPage.js +201 -137
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +202 -138
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +161 -30
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +163 -32
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +222 -59
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +223 -60
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +252 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +250 -0
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +209 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +207 -0
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +111 -36
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +113 -38
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js +120 -13
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs +120 -13
- package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +71 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +69 -0
- package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js +34 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs +32 -0
- package/dist/admin/future/pages/Assets/components/Dnd/computeValidDropTargets.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js +15 -0
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs +13 -1
- package/dist/admin/future/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +19 -25
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +19 -25
- package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js +35 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs +33 -0
- package/dist/admin/future/pages/Assets/components/Dnd/useFolderTreeDroppable.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/EmptyState.js +63 -0
- package/dist/admin/future/pages/Assets/components/EmptyState.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/EmptyState.mjs +61 -0
- package/dist/admin/future/pages/Assets/components/EmptyState.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +120 -22
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +121 -23
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js +22 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs +19 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js +165 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +163 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +59 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +55 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.js +124 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.mjs +120 -0
- package/dist/admin/future/pages/Assets/hooks/useListSort.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.js +29 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs +27 -0
- package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.js +84 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs +81 -0
- package/dist/admin/future/pages/Assets/utils/mergeMixedList.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.js +104 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.mjs +94 -0
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -0
- package/dist/admin/future/services/assets.js +33 -1
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +33 -2
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +3 -3
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +3 -3
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.js +23 -2
- package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.mjs +23 -2
- package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -1
- package/dist/admin/future/utils/buildDragSetFromSelection.js +33 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs +31 -0
- package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -0
- package/dist/admin/future/utils/canDropItemOnFolder.js +4 -0
- package/dist/admin/future/utils/canDropItemOnFolder.js.map +1 -1
- package/dist/admin/future/utils/canDropItemOnFolder.mjs +4 -0
- package/dist/admin/future/utils/canDropItemOnFolder.mjs.map +1 -1
- package/dist/admin/future/utils/flattenFolderStructure.js +28 -0
- package/dist/admin/future/utils/flattenFolderStructure.js.map +1 -0
- package/dist/admin/future/utils/flattenFolderStructure.mjs +26 -0
- package/dist/admin/future/utils/flattenFolderStructure.mjs.map +1 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.js +19 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +17 -0
- package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -0
- package/dist/admin/future/utils/getFolderLabel.js +31 -0
- package/dist/admin/future/utils/getFolderLabel.js.map +1 -0
- package/dist/admin/future/utils/getFolderLabel.mjs +29 -0
- package/dist/admin/future/utils/getFolderLabel.mjs.map +1 -0
- package/dist/admin/hooks/useUpload.js +15 -9
- package/dist/admin/hooks/useUpload.js.map +1 -1
- package/dist/admin/hooks/useUpload.mjs +17 -11
- package/dist/admin/hooks/useUpload.mjs.map +1 -1
- package/dist/admin/src/future/pages/Assets/components/AssetsGrid.d.ts +1 -1
- package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +7 -1
- package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +1 -0
- package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +13 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/DragOverlayChip.d.ts +2 -2
- package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +17 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/computeValidDropTargets.d.ts +7 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/dndIds.d.ts +3 -0
- package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +3 -1
- package/dist/admin/src/future/pages/Assets/components/Dnd/useFolderTreeDroppable.d.ts +19 -0
- package/dist/admin/src/future/pages/Assets/components/EmptyState.d.ts +11 -0
- package/dist/admin/src/future/pages/Assets/components/FolderTree/useSpringLoadedExpand.d.ts +6 -0
- package/dist/admin/src/future/pages/Assets/components/SortMenu.d.ts +17 -0
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +39 -0
- package/dist/admin/src/future/pages/Assets/hooks/useListSort.d.ts +47 -0
- package/dist/admin/src/future/pages/Assets/utils/listQueryKey.d.ts +30 -0
- package/dist/admin/src/future/pages/Assets/utils/mergeMixedList.d.ts +40 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +50 -0
- package/dist/admin/src/future/services/assets.d.ts +4 -1
- package/dist/admin/src/future/services/folders.d.ts +4 -1
- package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +1 -17
- package/dist/admin/src/future/types/dnd.d.ts +5 -0
- package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +11 -0
- package/dist/admin/src/future/utils/canDropItemOnFolder.d.ts +1 -1
- package/dist/admin/src/future/utils/flattenFolderStructure.d.ts +18 -0
- package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +14 -0
- package/dist/admin/src/future/utils/getFolderLabel.d.ts +11 -0
- package/dist/admin/translations/en.json.js +36 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +36 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/shared/contracts/folders.d.ts +1 -1
- package/package.json +8 -8
|
@@ -9,29 +9,57 @@ var reactIntl = require('react-intl');
|
|
|
9
9
|
var folders = require('../../../../services/folders.js');
|
|
10
10
|
var buildBulkMovePayload = require('../../../../utils/buildBulkMovePayload.js');
|
|
11
11
|
var canDropItemOnFolder = require('../../../../utils/canDropItemOnFolder.js');
|
|
12
|
+
var formatMoveSuccessMessage = require('../../../../utils/formatMoveSuccessMessage.js');
|
|
12
13
|
var getBulkMoveErrorMessage = require('../../../../utils/getBulkMoveErrorMessage.js');
|
|
14
|
+
var getFolderLabel = require('../../../../utils/getFolderLabel.js');
|
|
13
15
|
var translations = require('../../../../utils/translations.js');
|
|
16
|
+
var useAssetSelection = require('../../hooks/useAssetSelection.js');
|
|
17
|
+
var useFolderNavigation = require('../../hooks/useFolderNavigation.js');
|
|
18
|
+
var buildDragSet = require('./buildDragSet.js');
|
|
19
|
+
var computeValidDropTargets = require('./computeValidDropTargets.js');
|
|
14
20
|
var dndIds = require('./dndIds.js');
|
|
15
21
|
var DragOverlayChip = require('./DragOverlayChip.js');
|
|
16
22
|
|
|
17
23
|
const AssetsDndContext = /*#__PURE__*/ React.createContext(null);
|
|
18
24
|
const useAssetsDndOptional = ()=>React.useContext(AssetsDndContext);
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const resolveDestination = (overId)=>{
|
|
26
|
+
const inView = dndIds.parseFolderTargetId(overId);
|
|
27
|
+
if (inView != null) {
|
|
28
|
+
return {
|
|
29
|
+
destinationFolderId: inView
|
|
30
|
+
};
|
|
22
31
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
const tree = dndIds.parseFolderTreeTargetId(overId);
|
|
33
|
+
if (tree === 'root') {
|
|
34
|
+
return {
|
|
35
|
+
destinationFolderId: null
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (typeof tree === 'number') {
|
|
39
|
+
return {
|
|
40
|
+
destinationFolderId: tree
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
27
44
|
};
|
|
28
45
|
const AssetsDndProvider = ({ children })=>{
|
|
29
46
|
const { formatMessage } = reactIntl.useIntl();
|
|
30
47
|
const { toggleNotification } = strapiAdmin.useNotification();
|
|
48
|
+
const selection = useAssetSelection.useAssetSelectionOptional();
|
|
49
|
+
const { currentFolderId } = useFolderNavigation.useFolderNavigation();
|
|
31
50
|
const { data: folderStructure = [] } = folders.useGetFolderStructureQuery();
|
|
51
|
+
const rootLabel = formatMessage({
|
|
52
|
+
id: translations.getTranslationKey('plugin.name'),
|
|
53
|
+
defaultMessage: 'Media Library'
|
|
54
|
+
});
|
|
32
55
|
const [bulkMove, { isLoading: isMovePending }] = folders.useBulkMoveMutation();
|
|
33
|
-
const [
|
|
56
|
+
const [dragItems, setDragItems] = React.useState([]);
|
|
34
57
|
const [liveAnnouncement, setLiveAnnouncement] = React.useState('');
|
|
58
|
+
// Sync session for drag-end — state alone can lag one render behind dragStart.
|
|
59
|
+
const dragSessionRef = React.useRef({
|
|
60
|
+
items: [],
|
|
61
|
+
fromSelection: false
|
|
62
|
+
});
|
|
35
63
|
const announceToLiveRegion = React.useCallback((message)=>{
|
|
36
64
|
setLiveAnnouncement('');
|
|
37
65
|
requestAnimationFrame(()=>setLiveAnnouncement(message));
|
|
@@ -41,29 +69,58 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
41
69
|
distance: 8
|
|
42
70
|
}
|
|
43
71
|
}));
|
|
72
|
+
const validDropTargets = React.useMemo(()=>computeValidDropTargets.computeValidDropTargets(dragItems, folderStructure), [
|
|
73
|
+
dragItems,
|
|
74
|
+
folderStructure
|
|
75
|
+
]);
|
|
76
|
+
const isValidDropTarget = React.useCallback((targetFolderId)=>validDropTargets.has(targetFolderId), [
|
|
77
|
+
validDropTargets
|
|
78
|
+
]);
|
|
44
79
|
const contextValue = React.useMemo(()=>({
|
|
45
|
-
isInternalDragActive:
|
|
46
|
-
isMovePending
|
|
80
|
+
isInternalDragActive: dragItems.length > 0,
|
|
81
|
+
isMovePending,
|
|
82
|
+
isValidDropTarget
|
|
47
83
|
}), [
|
|
48
|
-
|
|
49
|
-
isMovePending
|
|
84
|
+
dragItems.length,
|
|
85
|
+
isMovePending,
|
|
86
|
+
isValidDropTarget
|
|
50
87
|
]);
|
|
88
|
+
const clearDragState = React.useCallback(()=>{
|
|
89
|
+
dragSessionRef.current = {
|
|
90
|
+
items: [],
|
|
91
|
+
fromSelection: false
|
|
92
|
+
};
|
|
93
|
+
setDragItems([]);
|
|
94
|
+
}, []);
|
|
51
95
|
const handleDragStart = React.useCallback((event)=>{
|
|
52
96
|
const data = event.active.data.current;
|
|
53
|
-
|
|
54
|
-
|
|
97
|
+
if (!data) {
|
|
98
|
+
clearDragState();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const { items, fromSelection } = buildDragSet.buildDragSet(data, selection?.selectedKeys, currentFolderId);
|
|
102
|
+
dragSessionRef.current = {
|
|
103
|
+
items,
|
|
104
|
+
fromSelection
|
|
105
|
+
};
|
|
106
|
+
setDragItems(items);
|
|
107
|
+
}, [
|
|
108
|
+
clearDragState,
|
|
109
|
+
currentFolderId,
|
|
110
|
+
selection?.selectedKeys
|
|
111
|
+
]);
|
|
55
112
|
const handleDragEnd = React.useCallback(async (event)=>{
|
|
56
|
-
const {
|
|
57
|
-
|
|
58
|
-
|
|
113
|
+
const { over } = event;
|
|
114
|
+
const { items, fromSelection } = dragSessionRef.current;
|
|
115
|
+
clearDragState();
|
|
116
|
+
if (isMovePending || !over || items.length === 0) {
|
|
59
117
|
return;
|
|
60
118
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
if (targetFolderId == null || !activeData) {
|
|
119
|
+
const destination = resolveDestination(over.id);
|
|
120
|
+
if (!destination) {
|
|
64
121
|
return;
|
|
65
122
|
}
|
|
66
|
-
const
|
|
123
|
+
const { destinationFolderId: targetFolderId } = destination;
|
|
67
124
|
if (!canDropItemOnFolder.canDropItemOnFolder({
|
|
68
125
|
items,
|
|
69
126
|
targetFolderId,
|
|
@@ -72,19 +129,27 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
72
129
|
return;
|
|
73
130
|
}
|
|
74
131
|
const payload = buildBulkMovePayload.buildBulkMovePayload(items);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
132
|
+
// Source is always the current folder — dragged items are, by definition,
|
|
133
|
+
// visible in the current view. Destination is the drop target. Both use
|
|
134
|
+
// leaf names so the DnD toast reads identically to the dialog's.
|
|
135
|
+
const successMessage = formatMoveSuccessMessage.formatMoveSuccessMessage({
|
|
136
|
+
formatMessage,
|
|
137
|
+
count: items.length,
|
|
138
|
+
source: getFolderLabel.getFolderLabel(folderStructure, currentFolderId, rootLabel),
|
|
139
|
+
destination: getFolderLabel.getFolderLabel(folderStructure, targetFolderId, rootLabel)
|
|
78
140
|
});
|
|
79
141
|
const errorFallback = formatMessage({
|
|
80
|
-
id: translations.getTranslationKey('
|
|
81
|
-
defaultMessage: 'An error occurred while moving the
|
|
142
|
+
id: translations.getTranslationKey('list.bulk-actions.move.error'),
|
|
143
|
+
defaultMessage: 'An error occurred while moving the items.'
|
|
82
144
|
});
|
|
83
145
|
try {
|
|
84
146
|
await bulkMove({
|
|
85
147
|
...payload,
|
|
86
148
|
destinationFolderId: targetFolderId
|
|
87
149
|
}).unwrap();
|
|
150
|
+
if (fromSelection) {
|
|
151
|
+
selection?.clear();
|
|
152
|
+
}
|
|
88
153
|
announceToLiveRegion(successMessage);
|
|
89
154
|
toggleNotification({
|
|
90
155
|
type: 'success',
|
|
@@ -106,14 +171,20 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
106
171
|
}, [
|
|
107
172
|
announceToLiveRegion,
|
|
108
173
|
bulkMove,
|
|
174
|
+
clearDragState,
|
|
175
|
+
currentFolderId,
|
|
109
176
|
folderStructure,
|
|
110
177
|
formatMessage,
|
|
111
178
|
isMovePending,
|
|
179
|
+
rootLabel,
|
|
180
|
+
selection,
|
|
112
181
|
toggleNotification
|
|
113
182
|
]);
|
|
114
183
|
const handleDragCancel = React.useCallback(()=>{
|
|
115
|
-
|
|
116
|
-
}, [
|
|
184
|
+
clearDragState();
|
|
185
|
+
}, [
|
|
186
|
+
clearDragState
|
|
187
|
+
]);
|
|
117
188
|
const announcements = React.useMemo(()=>({
|
|
118
189
|
onDragStart: ({ active })=>{
|
|
119
190
|
const data = active.data.current;
|
|
@@ -132,15 +203,15 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
132
203
|
defaultMessage: 'Drag cancelled.'
|
|
133
204
|
});
|
|
134
205
|
}
|
|
135
|
-
const
|
|
206
|
+
const destination = resolveDestination(over.id);
|
|
136
207
|
const activeData = active.data.current;
|
|
137
|
-
if (
|
|
208
|
+
if (!destination || !activeData) {
|
|
138
209
|
return '';
|
|
139
210
|
}
|
|
140
|
-
const items =
|
|
211
|
+
const { items } = buildDragSet.buildDragSet(activeData, selection?.selectedKeys, currentFolderId);
|
|
141
212
|
if (!canDropItemOnFolder.canDropItemOnFolder({
|
|
142
213
|
items,
|
|
143
|
-
targetFolderId,
|
|
214
|
+
targetFolderId: destination.destinationFolderId,
|
|
144
215
|
folderStructure
|
|
145
216
|
})) {
|
|
146
217
|
return formatMessage({
|
|
@@ -155,8 +226,10 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
155
226
|
defaultMessage: 'Drag cancelled.'
|
|
156
227
|
})
|
|
157
228
|
}), [
|
|
229
|
+
currentFolderId,
|
|
158
230
|
folderStructure,
|
|
159
|
-
formatMessage
|
|
231
|
+
formatMessage,
|
|
232
|
+
selection?.selectedKeys
|
|
160
233
|
]);
|
|
161
234
|
return /*#__PURE__*/ jsxRuntime.jsx(AssetsDndContext.Provider, {
|
|
162
235
|
value: contextValue,
|
|
@@ -181,14 +254,16 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
181
254
|
}),
|
|
182
255
|
/*#__PURE__*/ jsxRuntime.jsx(core.DragOverlay, {
|
|
183
256
|
dropAnimation: null,
|
|
184
|
-
children:
|
|
185
|
-
|
|
257
|
+
children: dragItems.length > 0 ? /*#__PURE__*/ jsxRuntime.jsx(DragOverlayChip.DragOverlayChip, {
|
|
258
|
+
items: dragItems
|
|
186
259
|
}) : null
|
|
187
260
|
})
|
|
188
261
|
]
|
|
189
262
|
})
|
|
190
263
|
});
|
|
191
|
-
}; //
|
|
264
|
+
}; // Keyboard-accessible moves are handled by `BulkMoveDialog` (reachable from the
|
|
265
|
+
// bulk-actions bar): pointer drag is a mouse-only enhancement, the dialog is the
|
|
266
|
+
// a11y path. No `KeyboardSensor` by design.
|
|
192
267
|
|
|
193
268
|
exports.AssetsDndProvider = AssetsDndProvider;
|
|
194
269
|
exports.useAssetsDndOptional = useAssetsDndOptional;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetsDndProvider.js","sources":["../../../../../../../admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.tsx"],"sourcesContent":["import { createContext, useCallback, useContext, useMemo, useState, type ReactNode } from 'react';\n\nimport {\n DndContext,\n DragOverlay,\n PointerSensor,\n pointerWithin,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragStartEvent,\n} from '@dnd-kit/core';\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, VisuallyHidden } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { useBulkMoveMutation, useGetFolderStructureQuery } from '../../../../services/folders';\nimport { buildBulkMovePayload } from '../../../../utils/buildBulkMovePayload';\nimport { canDropItemOnFolder } from '../../../../utils/canDropItemOnFolder';\nimport { getBulkMoveErrorMessage } from '../../../../utils/getBulkMoveErrorMessage';\nimport { getTranslationKey } from '../../../../utils/translations';\n\nimport { parseFolderTargetId } from './dndIds';\nimport { DragOverlayChip } from './DragOverlayChip';\n\nimport type { DragItemData } from '../../../../types/dnd';\n\n/* -------------------------------------------------------------------------------------------------\n * Context — shared with UploadDropZoneProvider for bidirectional drag guard.\n * See UploadDropZoneContext.tsx TODO linking both providers.\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsDndContextValue {\n isInternalDragActive: boolean;\n isMovePending: boolean;\n}\n\nconst AssetsDndContext = createContext<AssetsDndContextValue | null>(null);\n\nexport const useAssetsDnd = () => {\n const context = useContext(AssetsDndContext);\n\n if (!context) {\n throw new Error('useAssetsDnd must be used within AssetsDndProvider');\n }\n\n return context;\n};\n\nexport const useAssetsDndOptional = () => useContext(AssetsDndContext);\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsDndProviderProps {\n children: ReactNode;\n}\n\nconst getDragItems = (activeData: DragItemData | undefined): DragItemData[] => {\n if (!activeData) {\n return [];\n }\n\n // TODO(CMS-433): include selectedItems from active data for multi-drag payload members.\n return [activeData];\n};\n\nexport const AssetsDndProvider = ({ children }: AssetsDndProviderProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { data: folderStructure = [] } = useGetFolderStructureQuery();\n const [bulkMove, { isLoading: isMovePending }] = useBulkMoveMutation();\n const [activeItem, setActiveItem] = useState<DragItemData | null>(null);\n const [liveAnnouncement, setLiveAnnouncement] = useState('');\n\n const announceToLiveRegion = useCallback((message: string) => {\n setLiveAnnouncement('');\n requestAnimationFrame(() => setLiveAnnouncement(message));\n }, []);\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: 8 },\n })\n );\n\n const contextValue = useMemo<AssetsDndContextValue>(\n () => ({\n isInternalDragActive: activeItem !== null,\n isMovePending,\n }),\n [activeItem, isMovePending]\n );\n\n const handleDragStart = useCallback((event: DragStartEvent) => {\n const data = event.active.data.current as DragItemData | undefined;\n setActiveItem(data ?? null);\n }, []);\n\n const handleDragEnd = useCallback(\n async (event: DragEndEvent) => {\n const { active, over } = event;\n setActiveItem(null);\n\n if (isMovePending || !over) {\n return;\n }\n\n const targetFolderId = parseFolderTargetId(over.id);\n const activeData = active.data.current as DragItemData | undefined;\n\n if (targetFolderId == null || !activeData) {\n return;\n }\n\n const items = getDragItems(activeData);\n\n if (\n !canDropItemOnFolder({\n items,\n targetFolderId,\n folderStructure,\n })\n ) {\n return;\n }\n\n const payload = buildBulkMovePayload(items);\n const successMessage = formatMessage({\n id: getTranslationKey('modal.move.success-label'),\n defaultMessage: 'Elements have been moved successfully.',\n });\n const errorFallback = formatMessage({\n id: getTranslationKey('modal.move.error-label'),\n defaultMessage: 'An error occurred while moving the elements.',\n });\n\n try {\n await bulkMove({ ...payload, destinationFolderId: targetFolderId }).unwrap();\n\n announceToLiveRegion(successMessage);\n\n toggleNotification({\n type: 'success',\n message: successMessage,\n });\n } catch (error) {\n const errorMessage = getBulkMoveErrorMessage(error, errorFallback);\n\n announceToLiveRegion(\n formatMessage(\n {\n id: getTranslationKey('dnd.announce.move-failure'),\n defaultMessage: 'Move failed. {message}',\n },\n { message: errorMessage }\n )\n );\n\n toggleNotification({\n type: 'danger',\n message: errorMessage,\n });\n }\n },\n [\n announceToLiveRegion,\n bulkMove,\n folderStructure,\n formatMessage,\n isMovePending,\n toggleNotification,\n ]\n );\n\n const handleDragCancel = useCallback(() => {\n setActiveItem(null);\n }, []);\n\n const announcements = useMemo(\n () => ({\n onDragStart: ({ active }: DragStartEvent) => {\n const data = active.data.current as DragItemData | undefined;\n return data\n ? formatMessage(\n {\n id: getTranslationKey('dnd.announce.drag-start'),\n defaultMessage: 'Picked up {name}. Drop on a folder to move.',\n },\n { name: data.name }\n )\n : '';\n },\n onDragOver: () => '',\n onDragEnd: ({ active, over }: DragEndEvent) => {\n if (!over) {\n return formatMessage({\n id: getTranslationKey('dnd.announce.cancel'),\n defaultMessage: 'Drag cancelled.',\n });\n }\n\n const targetFolderId = parseFolderTargetId(over.id);\n const activeData = active.data.current as DragItemData | undefined;\n\n if (targetFolderId == null || !activeData) {\n return '';\n }\n\n const items = getDragItems(activeData);\n\n if (\n !canDropItemOnFolder({\n items,\n targetFolderId,\n folderStructure,\n })\n ) {\n return formatMessage({\n id: getTranslationKey('dnd.announce.invalid-drop'),\n defaultMessage: 'Cannot move item to this folder.',\n });\n }\n\n return '';\n },\n onDragCancel: () =>\n formatMessage({\n id: getTranslationKey('dnd.announce.cancel'),\n defaultMessage: 'Drag cancelled.',\n }),\n }),\n [folderStructure, formatMessage]\n );\n\n return (\n <AssetsDndContext.Provider value={contextValue}>\n <DndContext\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n accessibility={{ announcements }}\n >\n <VisuallyHidden aria-live=\"polite\" aria-atomic=\"true\">\n {liveAnnouncement}\n </VisuallyHidden>\n <Box position=\"relative\">{children}</Box>\n <DragOverlay dropAnimation={null}>\n {activeItem ? <DragOverlayChip item={activeItem} /> : null}\n </DragOverlay>\n </DndContext>\n </AssetsDndContext.Provider>\n );\n};\n\n// TODO(CMS-229): FolderTree droppables + keyboard move path.\n"],"names":["AssetsDndContext","createContext","useAssetsDndOptional","useContext","getDragItems","activeData","AssetsDndProvider","children","formatMessage","useIntl","toggleNotification","useNotification","data","folderStructure","useGetFolderStructureQuery","bulkMove","isLoading","isMovePending","useBulkMoveMutation","activeItem","setActiveItem","useState","liveAnnouncement","setLiveAnnouncement","announceToLiveRegion","useCallback","message","requestAnimationFrame","sensors","useSensors","useSensor","PointerSensor","activationConstraint","distance","contextValue","useMemo","isInternalDragActive","handleDragStart","event","active","current","handleDragEnd","over","targetFolderId","parseFolderTargetId","id","items","canDropItemOnFolder","payload","buildBulkMovePayload","successMessage","getTranslationKey","defaultMessage","errorFallback","destinationFolderId","unwrap","type","error","errorMessage","getBulkMoveErrorMessage","handleDragCancel","announcements","onDragStart","name","onDragOver","onDragEnd","onDragCancel","_jsx","Provider","value","_jsxs","DndContext","collisionDetection","pointerWithin","accessibility","VisuallyHidden","aria-live","aria-atomic","Box","position","DragOverlay","dropAnimation","DragOverlayChip","item"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetsDndProvider.js","sources":["../../../../../../../admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\n\nimport {\n DndContext,\n DragOverlay,\n PointerSensor,\n pointerWithin,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragStartEvent,\n} from '@dnd-kit/core';\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, VisuallyHidden } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { useBulkMoveMutation, useGetFolderStructureQuery } from '../../../../services/folders';\nimport { buildBulkMovePayload } from '../../../../utils/buildBulkMovePayload';\nimport { canDropItemOnFolder } from '../../../../utils/canDropItemOnFolder';\nimport { formatMoveSuccessMessage } from '../../../../utils/formatMoveSuccessMessage';\nimport { getBulkMoveErrorMessage } from '../../../../utils/getBulkMoveErrorMessage';\nimport { getFolderLabel } from '../../../../utils/getFolderLabel';\nimport { getTranslationKey } from '../../../../utils/translations';\nimport { useAssetSelectionOptional } from '../../hooks/useAssetSelection';\nimport { useFolderNavigation } from '../../hooks/useFolderNavigation';\n\nimport { buildDragSet } from './buildDragSet';\nimport { computeValidDropTargets } from './computeValidDropTargets';\nimport { parseFolderTargetId, parseFolderTreeTargetId } from './dndIds';\nimport { DragOverlayChip } from './DragOverlayChip';\n\nimport type { DragItemData } from '../../../../types/dnd';\n\n/* -------------------------------------------------------------------------------------------------\n * Context — shared with UploadDropZoneProvider for bidirectional drag guard.\n * See UploadDropZoneContext.tsx TODO linking both providers.\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsDndContextValue {\n isInternalDragActive: boolean;\n isMovePending: boolean;\n /** O(1) lookup of whether the current drag set may drop on this destination. */\n isValidDropTarget: (targetFolderId: number | null) => boolean;\n}\n\nconst AssetsDndContext = createContext<AssetsDndContextValue | null>(null);\n\nexport const useAssetsDnd = () => {\n const context = useContext(AssetsDndContext);\n\n if (!context) {\n throw new Error('useAssetsDnd must be used within AssetsDndProvider');\n }\n\n return context;\n};\n\nexport const useAssetsDndOptional = () => useContext(AssetsDndContext);\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsDndProviderProps {\n children: ReactNode;\n}\n\ninterface DragSession {\n items: DragItemData[];\n fromSelection: boolean;\n}\n\nconst resolveDestination = (\n overId: string | number\n): { destinationFolderId: number | null } | null => {\n const inView = parseFolderTargetId(overId);\n\n if (inView != null) {\n return { destinationFolderId: inView };\n }\n\n const tree = parseFolderTreeTargetId(overId);\n\n if (tree === 'root') {\n return { destinationFolderId: null };\n }\n\n if (typeof tree === 'number') {\n return { destinationFolderId: tree };\n }\n\n return null;\n};\n\nexport const AssetsDndProvider = ({ children }: AssetsDndProviderProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const selection = useAssetSelectionOptional();\n const { currentFolderId } = useFolderNavigation();\n const { data: folderStructure = [] } = useGetFolderStructureQuery();\n const rootLabel = formatMessage({\n id: getTranslationKey('plugin.name'),\n defaultMessage: 'Media Library',\n });\n const [bulkMove, { isLoading: isMovePending }] = useBulkMoveMutation();\n const [dragItems, setDragItems] = useState<DragItemData[]>([]);\n const [liveAnnouncement, setLiveAnnouncement] = useState('');\n // Sync session for drag-end — state alone can lag one render behind dragStart.\n const dragSessionRef = useRef<DragSession>({ items: [], fromSelection: false });\n\n const announceToLiveRegion = useCallback((message: string) => {\n setLiveAnnouncement('');\n requestAnimationFrame(() => setLiveAnnouncement(message));\n }, []);\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: 8 },\n })\n );\n\n const validDropTargets = useMemo(\n () => computeValidDropTargets(dragItems, folderStructure),\n [dragItems, folderStructure]\n );\n\n const isValidDropTarget = useCallback(\n (targetFolderId: number | null) => validDropTargets.has(targetFolderId),\n [validDropTargets]\n );\n\n const contextValue = useMemo<AssetsDndContextValue>(\n () => ({\n isInternalDragActive: dragItems.length > 0,\n isMovePending,\n isValidDropTarget,\n }),\n [dragItems.length, isMovePending, isValidDropTarget]\n );\n\n const clearDragState = useCallback(() => {\n dragSessionRef.current = { items: [], fromSelection: false };\n setDragItems([]);\n }, []);\n\n const handleDragStart = useCallback(\n (event: DragStartEvent) => {\n const data = event.active.data.current as DragItemData | undefined;\n\n if (!data) {\n clearDragState();\n return;\n }\n\n const { items, fromSelection } = buildDragSet(data, selection?.selectedKeys, currentFolderId);\n dragSessionRef.current = { items, fromSelection };\n setDragItems(items);\n },\n [clearDragState, currentFolderId, selection?.selectedKeys]\n );\n\n const handleDragEnd = useCallback(\n async (event: DragEndEvent) => {\n const { over } = event;\n const { items, fromSelection } = dragSessionRef.current;\n clearDragState();\n\n if (isMovePending || !over || items.length === 0) {\n return;\n }\n\n const destination = resolveDestination(over.id);\n\n if (!destination) {\n return;\n }\n\n const { destinationFolderId: targetFolderId } = destination;\n\n if (\n !canDropItemOnFolder({\n items,\n targetFolderId,\n folderStructure,\n })\n ) {\n return;\n }\n\n const payload = buildBulkMovePayload(items);\n // Source is always the current folder — dragged items are, by definition,\n // visible in the current view. Destination is the drop target. Both use\n // leaf names so the DnD toast reads identically to the dialog's.\n const successMessage = formatMoveSuccessMessage({\n formatMessage,\n count: items.length,\n source: getFolderLabel(folderStructure, currentFolderId, rootLabel),\n destination: getFolderLabel(folderStructure, targetFolderId, rootLabel),\n });\n const errorFallback = formatMessage({\n id: getTranslationKey('list.bulk-actions.move.error'),\n defaultMessage: 'An error occurred while moving the items.',\n });\n\n try {\n await bulkMove({ ...payload, destinationFolderId: targetFolderId }).unwrap();\n\n if (fromSelection) {\n selection?.clear();\n }\n\n announceToLiveRegion(successMessage);\n\n toggleNotification({\n type: 'success',\n message: successMessage,\n });\n } catch (error) {\n const errorMessage = getBulkMoveErrorMessage(error, errorFallback);\n\n announceToLiveRegion(\n formatMessage(\n {\n id: getTranslationKey('dnd.announce.move-failure'),\n defaultMessage: 'Move failed. {message}',\n },\n { message: errorMessage }\n )\n );\n\n toggleNotification({\n type: 'danger',\n message: errorMessage,\n });\n }\n },\n [\n announceToLiveRegion,\n bulkMove,\n clearDragState,\n currentFolderId,\n folderStructure,\n formatMessage,\n isMovePending,\n rootLabel,\n selection,\n toggleNotification,\n ]\n );\n\n const handleDragCancel = useCallback(() => {\n clearDragState();\n }, [clearDragState]);\n\n const announcements = useMemo(\n () => ({\n onDragStart: ({ active }: DragStartEvent) => {\n const data = active.data.current as DragItemData | undefined;\n return data\n ? formatMessage(\n {\n id: getTranslationKey('dnd.announce.drag-start'),\n defaultMessage: 'Picked up {name}. Drop on a folder to move.',\n },\n { name: data.name }\n )\n : '';\n },\n onDragOver: () => '',\n onDragEnd: ({ active, over }: DragEndEvent) => {\n if (!over) {\n return formatMessage({\n id: getTranslationKey('dnd.announce.cancel'),\n defaultMessage: 'Drag cancelled.',\n });\n }\n\n const destination = resolveDestination(over.id);\n const activeData = active.data.current as DragItemData | undefined;\n\n if (!destination || !activeData) {\n return '';\n }\n\n const { items } = buildDragSet(activeData, selection?.selectedKeys, currentFolderId);\n\n if (\n !canDropItemOnFolder({\n items,\n targetFolderId: destination.destinationFolderId,\n folderStructure,\n })\n ) {\n return formatMessage({\n id: getTranslationKey('dnd.announce.invalid-drop'),\n defaultMessage: 'Cannot move item to this folder.',\n });\n }\n\n return '';\n },\n onDragCancel: () =>\n formatMessage({\n id: getTranslationKey('dnd.announce.cancel'),\n defaultMessage: 'Drag cancelled.',\n }),\n }),\n [currentFolderId, folderStructure, formatMessage, selection?.selectedKeys]\n );\n\n return (\n <AssetsDndContext.Provider value={contextValue}>\n <DndContext\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragCancel={handleDragCancel}\n accessibility={{ announcements }}\n >\n <VisuallyHidden aria-live=\"polite\" aria-atomic=\"true\">\n {liveAnnouncement}\n </VisuallyHidden>\n <Box position=\"relative\">{children}</Box>\n <DragOverlay dropAnimation={null}>\n {dragItems.length > 0 ? <DragOverlayChip items={dragItems} /> : null}\n </DragOverlay>\n </DndContext>\n </AssetsDndContext.Provider>\n );\n};\n\n// Keyboard-accessible moves are handled by `BulkMoveDialog` (reachable from the\n// bulk-actions bar): pointer drag is a mouse-only enhancement, the dialog is the\n// a11y path. No `KeyboardSensor` by design.\n"],"names":["AssetsDndContext","createContext","useAssetsDndOptional","useContext","resolveDestination","overId","inView","parseFolderTargetId","destinationFolderId","tree","parseFolderTreeTargetId","AssetsDndProvider","children","formatMessage","useIntl","toggleNotification","useNotification","selection","useAssetSelectionOptional","currentFolderId","useFolderNavigation","data","folderStructure","useGetFolderStructureQuery","rootLabel","id","getTranslationKey","defaultMessage","bulkMove","isLoading","isMovePending","useBulkMoveMutation","dragItems","setDragItems","useState","liveAnnouncement","setLiveAnnouncement","dragSessionRef","useRef","items","fromSelection","announceToLiveRegion","useCallback","message","requestAnimationFrame","sensors","useSensors","useSensor","PointerSensor","activationConstraint","distance","validDropTargets","useMemo","computeValidDropTargets","isValidDropTarget","targetFolderId","has","contextValue","isInternalDragActive","length","clearDragState","current","handleDragStart","event","active","buildDragSet","selectedKeys","handleDragEnd","over","destination","canDropItemOnFolder","payload","buildBulkMovePayload","successMessage","formatMoveSuccessMessage","count","source","getFolderLabel","errorFallback","unwrap","clear","type","error","errorMessage","getBulkMoveErrorMessage","handleDragCancel","announcements","onDragStart","name","onDragOver","onDragEnd","activeData","onDragCancel","_jsx","Provider","value","_jsxs","DndContext","collisionDetection","pointerWithin","accessibility","VisuallyHidden","aria-live","aria-atomic","Box","position","DragOverlay","dropAnimation","DragOverlayChip"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useCallback, useMemo, createContext, useContext } from 'react';
|
|
2
|
+
import { useState, useRef, useCallback, useMemo, createContext, useContext } from 'react';
|
|
3
3
|
import { useSensors, useSensor, PointerSensor, DndContext, pointerWithin, DragOverlay } from '@dnd-kit/core';
|
|
4
4
|
import { useNotification } from '@strapi/admin/strapi-admin';
|
|
5
5
|
import { VisuallyHidden, Box } from '@strapi/design-system';
|
|
@@ -7,29 +7,57 @@ import { useIntl } from 'react-intl';
|
|
|
7
7
|
import { useGetFolderStructureQuery, useBulkMoveMutation } from '../../../../services/folders.mjs';
|
|
8
8
|
import { buildBulkMovePayload } from '../../../../utils/buildBulkMovePayload.mjs';
|
|
9
9
|
import { canDropItemOnFolder } from '../../../../utils/canDropItemOnFolder.mjs';
|
|
10
|
+
import { formatMoveSuccessMessage } from '../../../../utils/formatMoveSuccessMessage.mjs';
|
|
10
11
|
import { getBulkMoveErrorMessage } from '../../../../utils/getBulkMoveErrorMessage.mjs';
|
|
12
|
+
import { getFolderLabel } from '../../../../utils/getFolderLabel.mjs';
|
|
11
13
|
import { getTranslationKey } from '../../../../utils/translations.mjs';
|
|
12
|
-
import {
|
|
14
|
+
import { useAssetSelectionOptional } from '../../hooks/useAssetSelection.mjs';
|
|
15
|
+
import { useFolderNavigation } from '../../hooks/useFolderNavigation.mjs';
|
|
16
|
+
import { buildDragSet } from './buildDragSet.mjs';
|
|
17
|
+
import { computeValidDropTargets } from './computeValidDropTargets.mjs';
|
|
18
|
+
import { parseFolderTargetId, parseFolderTreeTargetId } from './dndIds.mjs';
|
|
13
19
|
import { DragOverlayChip } from './DragOverlayChip.mjs';
|
|
14
20
|
|
|
15
21
|
const AssetsDndContext = /*#__PURE__*/ createContext(null);
|
|
16
22
|
const useAssetsDndOptional = ()=>useContext(AssetsDndContext);
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
const resolveDestination = (overId)=>{
|
|
24
|
+
const inView = parseFolderTargetId(overId);
|
|
25
|
+
if (inView != null) {
|
|
26
|
+
return {
|
|
27
|
+
destinationFolderId: inView
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
const tree = parseFolderTreeTargetId(overId);
|
|
31
|
+
if (tree === 'root') {
|
|
32
|
+
return {
|
|
33
|
+
destinationFolderId: null
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (typeof tree === 'number') {
|
|
37
|
+
return {
|
|
38
|
+
destinationFolderId: tree
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
25
42
|
};
|
|
26
43
|
const AssetsDndProvider = ({ children })=>{
|
|
27
44
|
const { formatMessage } = useIntl();
|
|
28
45
|
const { toggleNotification } = useNotification();
|
|
46
|
+
const selection = useAssetSelectionOptional();
|
|
47
|
+
const { currentFolderId } = useFolderNavigation();
|
|
29
48
|
const { data: folderStructure = [] } = useGetFolderStructureQuery();
|
|
49
|
+
const rootLabel = formatMessage({
|
|
50
|
+
id: getTranslationKey('plugin.name'),
|
|
51
|
+
defaultMessage: 'Media Library'
|
|
52
|
+
});
|
|
30
53
|
const [bulkMove, { isLoading: isMovePending }] = useBulkMoveMutation();
|
|
31
|
-
const [
|
|
54
|
+
const [dragItems, setDragItems] = useState([]);
|
|
32
55
|
const [liveAnnouncement, setLiveAnnouncement] = useState('');
|
|
56
|
+
// Sync session for drag-end — state alone can lag one render behind dragStart.
|
|
57
|
+
const dragSessionRef = useRef({
|
|
58
|
+
items: [],
|
|
59
|
+
fromSelection: false
|
|
60
|
+
});
|
|
33
61
|
const announceToLiveRegion = useCallback((message)=>{
|
|
34
62
|
setLiveAnnouncement('');
|
|
35
63
|
requestAnimationFrame(()=>setLiveAnnouncement(message));
|
|
@@ -39,29 +67,58 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
39
67
|
distance: 8
|
|
40
68
|
}
|
|
41
69
|
}));
|
|
70
|
+
const validDropTargets = useMemo(()=>computeValidDropTargets(dragItems, folderStructure), [
|
|
71
|
+
dragItems,
|
|
72
|
+
folderStructure
|
|
73
|
+
]);
|
|
74
|
+
const isValidDropTarget = useCallback((targetFolderId)=>validDropTargets.has(targetFolderId), [
|
|
75
|
+
validDropTargets
|
|
76
|
+
]);
|
|
42
77
|
const contextValue = useMemo(()=>({
|
|
43
|
-
isInternalDragActive:
|
|
44
|
-
isMovePending
|
|
78
|
+
isInternalDragActive: dragItems.length > 0,
|
|
79
|
+
isMovePending,
|
|
80
|
+
isValidDropTarget
|
|
45
81
|
}), [
|
|
46
|
-
|
|
47
|
-
isMovePending
|
|
82
|
+
dragItems.length,
|
|
83
|
+
isMovePending,
|
|
84
|
+
isValidDropTarget
|
|
48
85
|
]);
|
|
86
|
+
const clearDragState = useCallback(()=>{
|
|
87
|
+
dragSessionRef.current = {
|
|
88
|
+
items: [],
|
|
89
|
+
fromSelection: false
|
|
90
|
+
};
|
|
91
|
+
setDragItems([]);
|
|
92
|
+
}, []);
|
|
49
93
|
const handleDragStart = useCallback((event)=>{
|
|
50
94
|
const data = event.active.data.current;
|
|
51
|
-
|
|
52
|
-
|
|
95
|
+
if (!data) {
|
|
96
|
+
clearDragState();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const { items, fromSelection } = buildDragSet(data, selection?.selectedKeys, currentFolderId);
|
|
100
|
+
dragSessionRef.current = {
|
|
101
|
+
items,
|
|
102
|
+
fromSelection
|
|
103
|
+
};
|
|
104
|
+
setDragItems(items);
|
|
105
|
+
}, [
|
|
106
|
+
clearDragState,
|
|
107
|
+
currentFolderId,
|
|
108
|
+
selection?.selectedKeys
|
|
109
|
+
]);
|
|
53
110
|
const handleDragEnd = useCallback(async (event)=>{
|
|
54
|
-
const {
|
|
55
|
-
|
|
56
|
-
|
|
111
|
+
const { over } = event;
|
|
112
|
+
const { items, fromSelection } = dragSessionRef.current;
|
|
113
|
+
clearDragState();
|
|
114
|
+
if (isMovePending || !over || items.length === 0) {
|
|
57
115
|
return;
|
|
58
116
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (targetFolderId == null || !activeData) {
|
|
117
|
+
const destination = resolveDestination(over.id);
|
|
118
|
+
if (!destination) {
|
|
62
119
|
return;
|
|
63
120
|
}
|
|
64
|
-
const
|
|
121
|
+
const { destinationFolderId: targetFolderId } = destination;
|
|
65
122
|
if (!canDropItemOnFolder({
|
|
66
123
|
items,
|
|
67
124
|
targetFolderId,
|
|
@@ -70,19 +127,27 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
70
127
|
return;
|
|
71
128
|
}
|
|
72
129
|
const payload = buildBulkMovePayload(items);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
130
|
+
// Source is always the current folder — dragged items are, by definition,
|
|
131
|
+
// visible in the current view. Destination is the drop target. Both use
|
|
132
|
+
// leaf names so the DnD toast reads identically to the dialog's.
|
|
133
|
+
const successMessage = formatMoveSuccessMessage({
|
|
134
|
+
formatMessage,
|
|
135
|
+
count: items.length,
|
|
136
|
+
source: getFolderLabel(folderStructure, currentFolderId, rootLabel),
|
|
137
|
+
destination: getFolderLabel(folderStructure, targetFolderId, rootLabel)
|
|
76
138
|
});
|
|
77
139
|
const errorFallback = formatMessage({
|
|
78
|
-
id: getTranslationKey('
|
|
79
|
-
defaultMessage: 'An error occurred while moving the
|
|
140
|
+
id: getTranslationKey('list.bulk-actions.move.error'),
|
|
141
|
+
defaultMessage: 'An error occurred while moving the items.'
|
|
80
142
|
});
|
|
81
143
|
try {
|
|
82
144
|
await bulkMove({
|
|
83
145
|
...payload,
|
|
84
146
|
destinationFolderId: targetFolderId
|
|
85
147
|
}).unwrap();
|
|
148
|
+
if (fromSelection) {
|
|
149
|
+
selection?.clear();
|
|
150
|
+
}
|
|
86
151
|
announceToLiveRegion(successMessage);
|
|
87
152
|
toggleNotification({
|
|
88
153
|
type: 'success',
|
|
@@ -104,14 +169,20 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
104
169
|
}, [
|
|
105
170
|
announceToLiveRegion,
|
|
106
171
|
bulkMove,
|
|
172
|
+
clearDragState,
|
|
173
|
+
currentFolderId,
|
|
107
174
|
folderStructure,
|
|
108
175
|
formatMessage,
|
|
109
176
|
isMovePending,
|
|
177
|
+
rootLabel,
|
|
178
|
+
selection,
|
|
110
179
|
toggleNotification
|
|
111
180
|
]);
|
|
112
181
|
const handleDragCancel = useCallback(()=>{
|
|
113
|
-
|
|
114
|
-
}, [
|
|
182
|
+
clearDragState();
|
|
183
|
+
}, [
|
|
184
|
+
clearDragState
|
|
185
|
+
]);
|
|
115
186
|
const announcements = useMemo(()=>({
|
|
116
187
|
onDragStart: ({ active })=>{
|
|
117
188
|
const data = active.data.current;
|
|
@@ -130,15 +201,15 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
130
201
|
defaultMessage: 'Drag cancelled.'
|
|
131
202
|
});
|
|
132
203
|
}
|
|
133
|
-
const
|
|
204
|
+
const destination = resolveDestination(over.id);
|
|
134
205
|
const activeData = active.data.current;
|
|
135
|
-
if (
|
|
206
|
+
if (!destination || !activeData) {
|
|
136
207
|
return '';
|
|
137
208
|
}
|
|
138
|
-
const items =
|
|
209
|
+
const { items } = buildDragSet(activeData, selection?.selectedKeys, currentFolderId);
|
|
139
210
|
if (!canDropItemOnFolder({
|
|
140
211
|
items,
|
|
141
|
-
targetFolderId,
|
|
212
|
+
targetFolderId: destination.destinationFolderId,
|
|
142
213
|
folderStructure
|
|
143
214
|
})) {
|
|
144
215
|
return formatMessage({
|
|
@@ -153,8 +224,10 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
153
224
|
defaultMessage: 'Drag cancelled.'
|
|
154
225
|
})
|
|
155
226
|
}), [
|
|
227
|
+
currentFolderId,
|
|
156
228
|
folderStructure,
|
|
157
|
-
formatMessage
|
|
229
|
+
formatMessage,
|
|
230
|
+
selection?.selectedKeys
|
|
158
231
|
]);
|
|
159
232
|
return /*#__PURE__*/ jsx(AssetsDndContext.Provider, {
|
|
160
233
|
value: contextValue,
|
|
@@ -179,14 +252,16 @@ const AssetsDndProvider = ({ children })=>{
|
|
|
179
252
|
}),
|
|
180
253
|
/*#__PURE__*/ jsx(DragOverlay, {
|
|
181
254
|
dropAnimation: null,
|
|
182
|
-
children:
|
|
183
|
-
|
|
255
|
+
children: dragItems.length > 0 ? /*#__PURE__*/ jsx(DragOverlayChip, {
|
|
256
|
+
items: dragItems
|
|
184
257
|
}) : null
|
|
185
258
|
})
|
|
186
259
|
]
|
|
187
260
|
})
|
|
188
261
|
});
|
|
189
|
-
}; //
|
|
262
|
+
}; // Keyboard-accessible moves are handled by `BulkMoveDialog` (reachable from the
|
|
263
|
+
// bulk-actions bar): pointer drag is a mouse-only enhancement, the dialog is the
|
|
264
|
+
// a11y path. No `KeyboardSensor` by design.
|
|
190
265
|
|
|
191
266
|
export { AssetsDndProvider, useAssetsDndOptional };
|
|
192
267
|
//# sourceMappingURL=AssetsDndProvider.mjs.map
|