@strapi/upload 5.56.0 → 5.57.0

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 (208) hide show
  1. package/dist/admin/hooks/useTracking.js +2 -8
  2. package/dist/admin/hooks/useTracking.js.map +1 -1
  3. package/dist/admin/hooks/useTracking.mjs +3 -8
  4. package/dist/admin/hooks/useTracking.mjs.map +1 -1
  5. package/dist/admin/legacy/hooks/useTracking.js +3 -1
  6. package/dist/admin/legacy/hooks/useTracking.js.map +1 -1
  7. package/dist/admin/legacy/hooks/useTracking.mjs +3 -1
  8. package/dist/admin/legacy/hooks/useTracking.mjs.map +1 -1
  9. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js +2 -1
  10. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  11. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs +2 -1
  12. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
  13. package/dist/admin/legacy/pages/App/MediaLibrary.js +2 -1
  14. package/dist/admin/legacy/pages/App/MediaLibrary.js.map +1 -1
  15. package/dist/admin/legacy/pages/App/MediaLibrary.mjs +2 -1
  16. package/dist/admin/legacy/pages/App/MediaLibrary.mjs.map +1 -1
  17. package/dist/admin/pages/Assets/AssetsPage.js +24 -12
  18. package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
  19. package/dist/admin/pages/Assets/AssetsPage.mjs +25 -13
  20. package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
  21. package/dist/admin/pages/Assets/components/AssetActions.js +326 -0
  22. package/dist/admin/pages/Assets/components/AssetActions.js.map +1 -0
  23. package/dist/admin/pages/Assets/components/AssetActions.mjs +324 -0
  24. package/dist/admin/pages/Assets/components/AssetActions.mjs.map +1 -0
  25. package/dist/admin/pages/Assets/components/AssetActionsMenu.js +28 -309
  26. package/dist/admin/pages/Assets/components/AssetActionsMenu.js.map +1 -1
  27. package/dist/admin/pages/Assets/components/AssetActionsMenu.mjs +31 -312
  28. package/dist/admin/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
  29. package/dist/admin/pages/Assets/components/AssetContextMenu.js +79 -0
  30. package/dist/admin/pages/Assets/components/AssetContextMenu.js.map +1 -0
  31. package/dist/admin/pages/Assets/components/AssetContextMenu.mjs +77 -0
  32. package/dist/admin/pages/Assets/components/AssetContextMenu.mjs.map +1 -0
  33. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.js +87 -5
  34. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  35. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +89 -7
  36. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  37. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +3 -3
  38. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  39. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +3 -3
  40. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  41. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.js +62 -5
  42. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.js.map +1 -1
  43. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.mjs +60 -6
  44. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.mjs.map +1 -1
  45. package/dist/admin/pages/Assets/components/AssetsGrid.js +27 -4
  46. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  47. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +27 -4
  48. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  49. package/dist/admin/pages/Assets/components/AssetsTable.js +27 -4
  50. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  51. package/dist/admin/pages/Assets/components/AssetsTable.mjs +27 -4
  52. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  53. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.js +77 -0
  54. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.js.map +1 -0
  55. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.mjs +75 -0
  56. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.mjs.map +1 -0
  57. package/dist/admin/pages/Assets/components/FolderActions.js +139 -0
  58. package/dist/admin/pages/Assets/components/FolderActions.js.map +1 -0
  59. package/dist/admin/pages/Assets/components/FolderActions.mjs +137 -0
  60. package/dist/admin/pages/Assets/components/FolderActions.mjs.map +1 -0
  61. package/dist/admin/pages/Assets/components/FolderActionsMenu.js +25 -119
  62. package/dist/admin/pages/Assets/components/FolderActionsMenu.js.map +1 -1
  63. package/dist/admin/pages/Assets/components/FolderActionsMenu.mjs +27 -121
  64. package/dist/admin/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
  65. package/dist/admin/pages/Assets/components/FolderContextMenu.js +67 -0
  66. package/dist/admin/pages/Assets/components/FolderContextMenu.js.map +1 -0
  67. package/dist/admin/pages/Assets/components/FolderContextMenu.mjs +65 -0
  68. package/dist/admin/pages/Assets/components/FolderContextMenu.mjs.map +1 -0
  69. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js +139 -45
  70. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  71. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs +140 -47
  72. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  73. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.js +115 -0
  74. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.js.map +1 -0
  75. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.mjs +113 -0
  76. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.mjs.map +1 -0
  77. package/dist/admin/pages/Assets/components/ItemContextMenu.js +125 -0
  78. package/dist/admin/pages/Assets/components/ItemContextMenu.js.map +1 -0
  79. package/dist/admin/pages/Assets/components/ItemContextMenu.mjs +122 -0
  80. package/dist/admin/pages/Assets/components/ItemContextMenu.mjs.map +1 -0
  81. package/dist/admin/pages/Assets/components/MainAreaContextMenu.js +88 -63
  82. package/dist/admin/pages/Assets/components/MainAreaContextMenu.js.map +1 -1
  83. package/dist/admin/pages/Assets/components/MainAreaContextMenu.mjs +88 -63
  84. package/dist/admin/pages/Assets/components/MainAreaContextMenu.mjs.map +1 -1
  85. package/dist/admin/pages/Assets/components/SelectionActions.js +111 -0
  86. package/dist/admin/pages/Assets/components/SelectionActions.js.map +1 -0
  87. package/dist/admin/pages/Assets/components/SelectionActions.mjs +109 -0
  88. package/dist/admin/pages/Assets/components/SelectionActions.mjs.map +1 -0
  89. package/dist/admin/pages/Assets/components/SelectionContextMenu.js +82 -0
  90. package/dist/admin/pages/Assets/components/SelectionContextMenu.js.map +1 -0
  91. package/dist/admin/pages/Assets/components/SelectionContextMenu.mjs +80 -0
  92. package/dist/admin/pages/Assets/components/SelectionContextMenu.mjs.map +1 -0
  93. package/dist/admin/pages/Assets/hooks/useAssetSelection.js +10 -0
  94. package/dist/admin/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  95. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs +10 -0
  96. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  97. package/dist/admin/pages/SettingsPage/SettingsPage.js +8 -1
  98. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  99. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +8 -1
  100. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  101. package/dist/admin/src/hooks/useTracking.d.ts +0 -7
  102. package/dist/admin/src/pages/Assets/components/AssetActions.d.ts +70 -0
  103. package/dist/admin/src/pages/Assets/components/AssetActionsMenu.d.ts +5 -14
  104. package/dist/admin/src/pages/Assets/components/AssetContextMenu.d.ts +27 -0
  105. package/dist/admin/src/pages/Assets/components/AssetDetails/useCropImg.d.ts +16 -0
  106. package/dist/admin/src/pages/Assets/components/CursorAnchoredMenu.d.ts +32 -0
  107. package/dist/admin/src/pages/Assets/components/FolderActions.d.ts +48 -0
  108. package/dist/admin/src/pages/Assets/components/FolderActionsMenu.d.ts +4 -8
  109. package/dist/admin/src/pages/Assets/components/FolderContextMenu.d.ts +21 -0
  110. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTree.d.ts +5 -1
  111. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTreeRowMenu.d.ts +25 -0
  112. package/dist/admin/src/pages/Assets/components/ItemContextMenu.d.ts +53 -0
  113. package/dist/admin/src/pages/Assets/components/MainAreaContextMenu.d.ts +15 -1
  114. package/dist/admin/src/pages/Assets/components/SelectionActions.d.ts +40 -0
  115. package/dist/admin/src/pages/Assets/components/SelectionContextMenu.d.ts +25 -0
  116. package/dist/admin/src/pages/Assets/hooks/useAssetSelection.d.ts +5 -0
  117. package/dist/admin/src/utils/mediaLibraryVersion.d.ts +18 -0
  118. package/dist/admin/translations/en.json.js +8 -3
  119. package/dist/admin/translations/en.json.js.map +1 -1
  120. package/dist/admin/translations/en.json.mjs +8 -3
  121. package/dist/admin/translations/en.json.mjs.map +1 -1
  122. package/dist/admin/utils/mediaLibraryVersion.js +24 -0
  123. package/dist/admin/utils/mediaLibraryVersion.js.map +1 -0
  124. package/dist/admin/utils/mediaLibraryVersion.mjs +20 -0
  125. package/dist/admin/utils/mediaLibraryVersion.mjs.map +1 -0
  126. package/dist/server/controllers/admin-file.js +2 -2
  127. package/dist/server/controllers/admin-file.js.map +1 -1
  128. package/dist/server/controllers/admin-file.mjs +2 -2
  129. package/dist/server/controllers/admin-file.mjs.map +1 -1
  130. package/dist/server/controllers/admin-folder.js +5 -5
  131. package/dist/server/controllers/admin-folder.js.map +1 -1
  132. package/dist/server/controllers/admin-folder.mjs +5 -5
  133. package/dist/server/controllers/admin-folder.mjs.map +1 -1
  134. package/dist/server/controllers/content-api.js +30 -7
  135. package/dist/server/controllers/content-api.js.map +1 -1
  136. package/dist/server/controllers/content-api.mjs +30 -7
  137. package/dist/server/controllers/content-api.mjs.map +1 -1
  138. package/dist/server/controllers/validation/admin/folder-file.js +4 -4
  139. package/dist/server/controllers/validation/admin/folder-file.js.map +1 -1
  140. package/dist/server/controllers/validation/admin/folder-file.mjs +2 -2
  141. package/dist/server/controllers/validation/admin/folder-file.mjs.map +1 -1
  142. package/dist/server/controllers/validation/admin/folder.js +3 -4
  143. package/dist/server/controllers/validation/admin/folder.js.map +1 -1
  144. package/dist/server/controllers/validation/admin/folder.mjs +3 -4
  145. package/dist/server/controllers/validation/admin/folder.mjs.map +1 -1
  146. package/dist/server/controllers/validation/admin/upload.js +1 -2
  147. package/dist/server/controllers/validation/admin/upload.js.map +1 -1
  148. package/dist/server/controllers/validation/admin/upload.mjs +1 -2
  149. package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
  150. package/dist/server/controllers/validation/admin/utils.js +1 -2
  151. package/dist/server/controllers/validation/admin/utils.js.map +1 -1
  152. package/dist/server/controllers/validation/admin/utils.mjs +1 -2
  153. package/dist/server/controllers/validation/admin/utils.mjs.map +1 -1
  154. package/dist/server/migrations/unsign-richtext-and-blocks-urls.js +2 -2
  155. package/dist/server/migrations/unsign-richtext-and-blocks-urls.js.map +1 -1
  156. package/dist/server/migrations/unsign-richtext-and-blocks-urls.mjs +1 -1
  157. package/dist/server/migrations/unsign-richtext-and-blocks-urls.mjs.map +1 -1
  158. package/dist/server/routes/content-api.js +3 -3
  159. package/dist/server/routes/content-api.js.map +1 -1
  160. package/dist/server/routes/content-api.mjs +3 -3
  161. package/dist/server/routes/content-api.mjs.map +1 -1
  162. package/dist/server/routes/validation/upload.js +8 -0
  163. package/dist/server/routes/validation/upload.js.map +1 -1
  164. package/dist/server/routes/validation/upload.mjs +8 -0
  165. package/dist/server/routes/validation/upload.mjs.map +1 -1
  166. package/dist/server/services/api-upload-folder.js +3 -3
  167. package/dist/server/services/api-upload-folder.js.map +1 -1
  168. package/dist/server/services/api-upload-folder.mjs +3 -3
  169. package/dist/server/services/api-upload-folder.mjs.map +1 -1
  170. package/dist/server/services/extensions/utils.js +19 -15
  171. package/dist/server/services/extensions/utils.js.map +1 -1
  172. package/dist/server/services/extensions/utils.mjs +19 -15
  173. package/dist/server/services/extensions/utils.mjs.map +1 -1
  174. package/dist/server/services/file.js +2 -2
  175. package/dist/server/services/file.js.map +1 -1
  176. package/dist/server/services/file.mjs +1 -1
  177. package/dist/server/services/file.mjs.map +1 -1
  178. package/dist/server/services/folder.js +5 -5
  179. package/dist/server/services/folder.js.map +1 -1
  180. package/dist/server/services/folder.mjs +5 -5
  181. package/dist/server/services/folder.mjs.map +1 -1
  182. package/dist/server/services/provider.js +3 -4
  183. package/dist/server/services/provider.js.map +1 -1
  184. package/dist/server/services/provider.mjs +3 -4
  185. package/dist/server/services/provider.mjs.map +1 -1
  186. package/dist/server/services/upload.js +5 -6
  187. package/dist/server/services/upload.js.map +1 -1
  188. package/dist/server/services/upload.mjs +4 -5
  189. package/dist/server/services/upload.mjs.map +1 -1
  190. package/dist/server/services/weekly-metrics.js +2 -2
  191. package/dist/server/services/weekly-metrics.js.map +1 -1
  192. package/dist/server/services/weekly-metrics.mjs +2 -2
  193. package/dist/server/services/weekly-metrics.mjs.map +1 -1
  194. package/dist/server/src/controllers/admin-folder.d.ts.map +1 -1
  195. package/dist/server/src/controllers/content-api.d.ts.map +1 -1
  196. package/dist/server/src/controllers/validation/admin/folder.d.ts.map +1 -1
  197. package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
  198. package/dist/server/src/controllers/validation/admin/utils.d.ts.map +1 -1
  199. package/dist/server/src/index.d.ts.map +1 -1
  200. package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
  201. package/dist/server/src/routes/validation/upload.d.ts +4 -0
  202. package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
  203. package/dist/server/src/services/extensions/utils.d.ts +33 -1
  204. package/dist/server/src/services/extensions/utils.d.ts.map +1 -1
  205. package/dist/server/src/services/index.d.ts.map +1 -1
  206. package/dist/server/src/services/provider.d.ts.map +1 -1
  207. package/dist/server/src/services/upload.d.ts.map +1 -1
  208. package/package.json +6 -6
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+ var reactIntl = require('react-intl');
6
+ var translations = require('../../../utils/translations.js');
7
+ var CursorAnchoredMenu = require('./CursorAnchoredMenu.js');
8
+ var FolderActions = require('./FolderActions.js');
9
+
10
+ /**
11
+ * The right-click twin of `FolderActionsMenu`: same actions, opened at the
12
+ * cursor. Mirrors `AssetContextMenu`, including keeping "the menu is shut" and
13
+ * "this is unmounted" as separate things — a dialog opened from an item is
14
+ * rendered here and would go with an early unmount.
15
+ */ const FolderContextMenu = ({ folder, dragData, showRename, position, returnFocusTo, onClose })=>{
16
+ const { formatMessage } = reactIntl.useIntl();
17
+ const [isMenuOpen, setIsMenuOpen] = React.useState(true);
18
+ return /*#__PURE__*/ jsxRuntime.jsx(FolderActions.FolderActions, {
19
+ folder: folder,
20
+ dragData: dragData,
21
+ showRename: showRename,
22
+ children: ({ items, dialogs, isBusy })=>/*#__PURE__*/ jsxRuntime.jsx(FolderContextMenuBody, {
23
+ isBusy: isBusy,
24
+ isMenuOpen: isMenuOpen,
25
+ onMenuClose: ()=>setIsMenuOpen(false),
26
+ onClose: onClose,
27
+ position: position,
28
+ returnFocusTo: returnFocusTo,
29
+ label: formatMessage({
30
+ id: translations.getTranslationKey('list.folder.context-menu.label'),
31
+ defaultMessage: 'Folder actions'
32
+ }),
33
+ items: items,
34
+ dialogs: dialogs
35
+ })
36
+ });
37
+ };
38
+ /**
39
+ * Split out because the "nothing left on screen" effect can't run inside the
40
+ * render prop above — hooks don't belong in a callback.
41
+ */ const FolderContextMenuBody = ({ isBusy, isMenuOpen, onMenuClose, onClose, position, returnFocusTo, label, items, dialogs })=>{
42
+ React.useEffect(()=>{
43
+ if (!isMenuOpen && !isBusy) {
44
+ onClose();
45
+ }
46
+ }, [
47
+ isMenuOpen,
48
+ isBusy,
49
+ onClose
50
+ ]);
51
+ return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
52
+ children: [
53
+ /*#__PURE__*/ jsxRuntime.jsx(CursorAnchoredMenu.CursorAnchoredMenu, {
54
+ position: position,
55
+ open: isMenuOpen,
56
+ label: label,
57
+ returnFocusTo: returnFocusTo,
58
+ onClose: onMenuClose,
59
+ children: items
60
+ }),
61
+ dialogs
62
+ ]
63
+ });
64
+ };
65
+
66
+ exports.FolderContextMenu = FolderContextMenu;
67
+ //# sourceMappingURL=FolderContextMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderContextMenu.js","sources":["../../../../../admin/src/pages/Assets/components/FolderContextMenu.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\n\nimport { CursorAnchoredMenu, type CursorPosition } from './CursorAnchoredMenu';\nimport { FolderActions } from './FolderActions';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\nimport type { DragFolderData } from '../../../types/dnd';\n\ninterface FolderContextMenuProps {\n folder: Pick<Folder, 'id' | 'name'>;\n dragData: DragFolderData;\n /** Passed through — the folder tree offers the menu without Rename. */\n showRename?: boolean;\n position: CursorPosition;\n returnFocusTo: HTMLElement | null;\n /** Mounted only while it has something on screen, so the parent drops it on this. */\n onClose: () => void;\n}\n\n/**\n * The right-click twin of `FolderActionsMenu`: same actions, opened at the\n * cursor. Mirrors `AssetContextMenu`, including keeping \"the menu is shut\" and\n * \"this is unmounted\" as separate things — a dialog opened from an item is\n * rendered here and would go with an early unmount.\n */\nexport const FolderContextMenu = ({\n folder,\n dragData,\n showRename,\n position,\n returnFocusTo,\n onClose,\n}: FolderContextMenuProps) => {\n const { formatMessage } = useIntl();\n const [isMenuOpen, setIsMenuOpen] = useState(true);\n\n return (\n <FolderActions folder={folder} dragData={dragData} showRename={showRename}>\n {({ items, dialogs, isBusy }) => (\n <FolderContextMenuBody\n isBusy={isBusy}\n isMenuOpen={isMenuOpen}\n onMenuClose={() => setIsMenuOpen(false)}\n onClose={onClose}\n position={position}\n returnFocusTo={returnFocusTo}\n label={formatMessage({\n id: getTranslationKey('list.folder.context-menu.label'),\n defaultMessage: 'Folder actions',\n })}\n items={items}\n dialogs={dialogs}\n />\n )}\n </FolderActions>\n );\n};\n\ninterface FolderContextMenuBodyProps {\n isBusy: boolean;\n isMenuOpen: boolean;\n onMenuClose: () => void;\n onClose: () => void;\n position: CursorPosition;\n returnFocusTo: HTMLElement | null;\n label: string;\n items: ReactNode;\n dialogs: ReactNode;\n}\n\n/**\n * Split out because the \"nothing left on screen\" effect can't run inside the\n * render prop above — hooks don't belong in a callback.\n */\nconst FolderContextMenuBody = ({\n isBusy,\n isMenuOpen,\n onMenuClose,\n onClose,\n position,\n returnFocusTo,\n label,\n items,\n dialogs,\n}: FolderContextMenuBodyProps) => {\n useEffect(() => {\n if (!isMenuOpen && !isBusy) {\n onClose();\n }\n }, [isMenuOpen, isBusy, onClose]);\n\n return (\n <>\n <CursorAnchoredMenu\n position={position}\n open={isMenuOpen}\n label={label}\n returnFocusTo={returnFocusTo}\n onClose={onMenuClose}\n >\n {items}\n </CursorAnchoredMenu>\n {dialogs}\n </>\n );\n};\n"],"names":["FolderContextMenu","folder","dragData","showRename","position","returnFocusTo","onClose","formatMessage","useIntl","isMenuOpen","setIsMenuOpen","useState","_jsx","FolderActions","items","dialogs","isBusy","FolderContextMenuBody","onMenuClose","label","id","getTranslationKey","defaultMessage","useEffect","_jsxs","_Fragment","CursorAnchoredMenu","open"],"mappings":";;;;;;;;;AAuBA;;;;;AAKC,IACM,MAAMA,iBAAAA,GAAoB,CAAC,EAChCC,MAAM,EACNC,QAAQ,EACRC,UAAU,EACVC,QAAQ,EACRC,aAAa,EACbC,OAAO,EACgB,GAAA;IACvB,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAC1B,IAAA,MAAM,CAACC,UAAAA,EAAYC,aAAAA,CAAc,GAAGC,cAAAA,CAAS,IAAA,CAAA;AAE7C,IAAA,qBACEC,cAAA,CAACC,2BAAAA,EAAAA;QAAcZ,MAAAA,EAAQA,MAAAA;QAAQC,QAAAA,EAAUA,QAAAA;QAAUC,UAAAA,EAAYA,UAAAA;kBAC5D,CAAC,EAAEW,KAAK,EAAEC,OAAO,EAAEC,MAAM,EAAE,iBAC1BJ,cAAA,CAACK,qBAAAA,EAAAA;gBACCD,MAAAA,EAAQA,MAAAA;gBACRP,UAAAA,EAAYA,UAAAA;AACZS,gBAAAA,WAAAA,EAAa,IAAMR,aAAAA,CAAc,KAAA,CAAA;gBACjCJ,OAAAA,EAASA,OAAAA;gBACTF,QAAAA,EAAUA,QAAAA;gBACVC,aAAAA,EAAeA,aAAAA;AACfc,gBAAAA,KAAAA,EAAOZ,aAAAA,CAAc;AACnBa,oBAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,gCAAA,CAAA;oBACtBC,cAAAA,EAAgB;AAClB,iBAAA,CAAA;gBACAR,KAAAA,EAAOA,KAAAA;gBACPC,OAAAA,EAASA;;;AAKnB;AAcA;;;IAIA,MAAME,wBAAwB,CAAC,EAC7BD,MAAM,EACNP,UAAU,EACVS,WAAW,EACXZ,OAAO,EACPF,QAAQ,EACRC,aAAa,EACbc,KAAK,EACLL,KAAK,EACLC,OAAO,EACoB,GAAA;IAC3BQ,eAAAA,CAAU,IAAA;QACR,IAAI,CAACd,UAAAA,IAAc,CAACO,MAAAA,EAAQ;AAC1BV,YAAAA,OAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;AAACG,QAAAA,UAAAA;AAAYO,QAAAA,MAAAA;AAAQV,QAAAA;AAAQ,KAAA,CAAA;IAEhC,qBACEkB,eAAA,CAAAC,mBAAA,EAAA;;0BACEb,cAAA,CAACc,qCAAAA,EAAAA;gBACCtB,QAAAA,EAAUA,QAAAA;gBACVuB,IAAAA,EAAMlB,UAAAA;gBACNU,KAAAA,EAAOA,KAAAA;gBACPd,aAAAA,EAAeA,aAAAA;gBACfC,OAAAA,EAASY,WAAAA;AAERJ,gBAAAA,QAAAA,EAAAA;;AAEFC,YAAAA;;;AAGP,CAAA;;;;"}
@@ -0,0 +1,65 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { useIntl } from 'react-intl';
4
+ import { getTranslationKey } from '../../../utils/translations.mjs';
5
+ import { CursorAnchoredMenu } from './CursorAnchoredMenu.mjs';
6
+ import { FolderActions } from './FolderActions.mjs';
7
+
8
+ /**
9
+ * The right-click twin of `FolderActionsMenu`: same actions, opened at the
10
+ * cursor. Mirrors `AssetContextMenu`, including keeping "the menu is shut" and
11
+ * "this is unmounted" as separate things — a dialog opened from an item is
12
+ * rendered here and would go with an early unmount.
13
+ */ const FolderContextMenu = ({ folder, dragData, showRename, position, returnFocusTo, onClose })=>{
14
+ const { formatMessage } = useIntl();
15
+ const [isMenuOpen, setIsMenuOpen] = useState(true);
16
+ return /*#__PURE__*/ jsx(FolderActions, {
17
+ folder: folder,
18
+ dragData: dragData,
19
+ showRename: showRename,
20
+ children: ({ items, dialogs, isBusy })=>/*#__PURE__*/ jsx(FolderContextMenuBody, {
21
+ isBusy: isBusy,
22
+ isMenuOpen: isMenuOpen,
23
+ onMenuClose: ()=>setIsMenuOpen(false),
24
+ onClose: onClose,
25
+ position: position,
26
+ returnFocusTo: returnFocusTo,
27
+ label: formatMessage({
28
+ id: getTranslationKey('list.folder.context-menu.label'),
29
+ defaultMessage: 'Folder actions'
30
+ }),
31
+ items: items,
32
+ dialogs: dialogs
33
+ })
34
+ });
35
+ };
36
+ /**
37
+ * Split out because the "nothing left on screen" effect can't run inside the
38
+ * render prop above — hooks don't belong in a callback.
39
+ */ const FolderContextMenuBody = ({ isBusy, isMenuOpen, onMenuClose, onClose, position, returnFocusTo, label, items, dialogs })=>{
40
+ useEffect(()=>{
41
+ if (!isMenuOpen && !isBusy) {
42
+ onClose();
43
+ }
44
+ }, [
45
+ isMenuOpen,
46
+ isBusy,
47
+ onClose
48
+ ]);
49
+ return /*#__PURE__*/ jsxs(Fragment, {
50
+ children: [
51
+ /*#__PURE__*/ jsx(CursorAnchoredMenu, {
52
+ position: position,
53
+ open: isMenuOpen,
54
+ label: label,
55
+ returnFocusTo: returnFocusTo,
56
+ onClose: onMenuClose,
57
+ children: items
58
+ }),
59
+ dialogs
60
+ ]
61
+ });
62
+ };
63
+
64
+ export { FolderContextMenu };
65
+ //# sourceMappingURL=FolderContextMenu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderContextMenu.mjs","sources":["../../../../../admin/src/pages/Assets/components/FolderContextMenu.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\n\nimport { CursorAnchoredMenu, type CursorPosition } from './CursorAnchoredMenu';\nimport { FolderActions } from './FolderActions';\n\nimport type { Folder } from '../../../../../shared/contracts/folders';\nimport type { DragFolderData } from '../../../types/dnd';\n\ninterface FolderContextMenuProps {\n folder: Pick<Folder, 'id' | 'name'>;\n dragData: DragFolderData;\n /** Passed through — the folder tree offers the menu without Rename. */\n showRename?: boolean;\n position: CursorPosition;\n returnFocusTo: HTMLElement | null;\n /** Mounted only while it has something on screen, so the parent drops it on this. */\n onClose: () => void;\n}\n\n/**\n * The right-click twin of `FolderActionsMenu`: same actions, opened at the\n * cursor. Mirrors `AssetContextMenu`, including keeping \"the menu is shut\" and\n * \"this is unmounted\" as separate things — a dialog opened from an item is\n * rendered here and would go with an early unmount.\n */\nexport const FolderContextMenu = ({\n folder,\n dragData,\n showRename,\n position,\n returnFocusTo,\n onClose,\n}: FolderContextMenuProps) => {\n const { formatMessage } = useIntl();\n const [isMenuOpen, setIsMenuOpen] = useState(true);\n\n return (\n <FolderActions folder={folder} dragData={dragData} showRename={showRename}>\n {({ items, dialogs, isBusy }) => (\n <FolderContextMenuBody\n isBusy={isBusy}\n isMenuOpen={isMenuOpen}\n onMenuClose={() => setIsMenuOpen(false)}\n onClose={onClose}\n position={position}\n returnFocusTo={returnFocusTo}\n label={formatMessage({\n id: getTranslationKey('list.folder.context-menu.label'),\n defaultMessage: 'Folder actions',\n })}\n items={items}\n dialogs={dialogs}\n />\n )}\n </FolderActions>\n );\n};\n\ninterface FolderContextMenuBodyProps {\n isBusy: boolean;\n isMenuOpen: boolean;\n onMenuClose: () => void;\n onClose: () => void;\n position: CursorPosition;\n returnFocusTo: HTMLElement | null;\n label: string;\n items: ReactNode;\n dialogs: ReactNode;\n}\n\n/**\n * Split out because the \"nothing left on screen\" effect can't run inside the\n * render prop above — hooks don't belong in a callback.\n */\nconst FolderContextMenuBody = ({\n isBusy,\n isMenuOpen,\n onMenuClose,\n onClose,\n position,\n returnFocusTo,\n label,\n items,\n dialogs,\n}: FolderContextMenuBodyProps) => {\n useEffect(() => {\n if (!isMenuOpen && !isBusy) {\n onClose();\n }\n }, [isMenuOpen, isBusy, onClose]);\n\n return (\n <>\n <CursorAnchoredMenu\n position={position}\n open={isMenuOpen}\n label={label}\n returnFocusTo={returnFocusTo}\n onClose={onMenuClose}\n >\n {items}\n </CursorAnchoredMenu>\n {dialogs}\n </>\n );\n};\n"],"names":["FolderContextMenu","folder","dragData","showRename","position","returnFocusTo","onClose","formatMessage","useIntl","isMenuOpen","setIsMenuOpen","useState","_jsx","FolderActions","items","dialogs","isBusy","FolderContextMenuBody","onMenuClose","label","id","getTranslationKey","defaultMessage","useEffect","_jsxs","_Fragment","CursorAnchoredMenu","open"],"mappings":";;;;;;;AAuBA;;;;;AAKC,IACM,MAAMA,iBAAAA,GAAoB,CAAC,EAChCC,MAAM,EACNC,QAAQ,EACRC,UAAU,EACVC,QAAQ,EACRC,aAAa,EACbC,OAAO,EACgB,GAAA;IACvB,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAC1B,IAAA,MAAM,CAACC,UAAAA,EAAYC,aAAAA,CAAc,GAAGC,QAAAA,CAAS,IAAA,CAAA;AAE7C,IAAA,qBACEC,GAAA,CAACC,aAAAA,EAAAA;QAAcZ,MAAAA,EAAQA,MAAAA;QAAQC,QAAAA,EAAUA,QAAAA;QAAUC,UAAAA,EAAYA,UAAAA;kBAC5D,CAAC,EAAEW,KAAK,EAAEC,OAAO,EAAEC,MAAM,EAAE,iBAC1BJ,GAAA,CAACK,qBAAAA,EAAAA;gBACCD,MAAAA,EAAQA,MAAAA;gBACRP,UAAAA,EAAYA,UAAAA;AACZS,gBAAAA,WAAAA,EAAa,IAAMR,aAAAA,CAAc,KAAA,CAAA;gBACjCJ,OAAAA,EAASA,OAAAA;gBACTF,QAAAA,EAAUA,QAAAA;gBACVC,aAAAA,EAAeA,aAAAA;AACfc,gBAAAA,KAAAA,EAAOZ,aAAAA,CAAc;AACnBa,oBAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,gCAAA,CAAA;oBACtBC,cAAAA,EAAgB;AAClB,iBAAA,CAAA;gBACAR,KAAAA,EAAOA,KAAAA;gBACPC,OAAAA,EAASA;;;AAKnB;AAcA;;;IAIA,MAAME,wBAAwB,CAAC,EAC7BD,MAAM,EACNP,UAAU,EACVS,WAAW,EACXZ,OAAO,EACPF,QAAQ,EACRC,aAAa,EACbc,KAAK,EACLL,KAAK,EACLC,OAAO,EACoB,GAAA;IAC3BQ,SAAAA,CAAU,IAAA;QACR,IAAI,CAACd,UAAAA,IAAc,CAACO,MAAAA,EAAQ;AAC1BV,YAAAA,OAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EAAG;AAACG,QAAAA,UAAAA;AAAYO,QAAAA,MAAAA;AAAQV,QAAAA;AAAQ,KAAA,CAAA;IAEhC,qBACEkB,IAAA,CAAAC,QAAA,EAAA;;0BACEb,GAAA,CAACc,kBAAAA,EAAAA;gBACCtB,QAAAA,EAAUA,QAAAA;gBACVuB,IAAAA,EAAMlB,UAAAA;gBACNU,KAAAA,EAAOA,KAAAA;gBACPd,aAAAA,EAAeA,aAAAA;gBACfC,OAAAA,EAASY,WAAAA;AAERJ,gBAAAA,QAAAA,EAAAA;;AAEFC,YAAAA;;;AAGP,CAAA;;;;"}
@@ -9,9 +9,11 @@ var reactIntl = require('react-intl');
9
9
  var styledComponents = require('styled-components');
10
10
  var TruncatedText = require('../../../../components/TruncatedText.js');
11
11
  var folders = require('../../../../services/folders.js');
12
+ var isEventFromWithin = require('../../../../utils/isEventFromWithin.js');
12
13
  var translations = require('../../../../utils/translations.js');
13
14
  var AssetsDndProvider = require('../Dnd/AssetsDndProvider.js');
14
15
  var useFolderTreeDroppable = require('../Dnd/useFolderTreeDroppable.js');
16
+ var FolderTreeRowMenu = require('./FolderTreeRowMenu.js');
15
17
  var useSpringLoadedExpand = require('./useSpringLoadedExpand.js');
16
18
 
17
19
  /* -------------------------------------------------------------------------------------------------
@@ -19,17 +21,19 @@ var useSpringLoadedExpand = require('./useSpringLoadedExpand.js');
19
21
  * -----------------------------------------------------------------------------------------------*/ const RowButton = styledComponents.styled.button`
20
22
  display: flex;
21
23
  align-items: center;
22
- gap: ${({ theme })=>theme.spaces[2]};
24
+ // Matches the row's own gap, so Home — the one row whose icon sits inside
25
+ // this button rather than beside it — puts its label on the same line as a
26
+ // folder's.
27
+ gap: ${({ theme })=>theme.spaces[1]};
23
28
  width: 100%;
24
29
  min-height: 3.2rem;
25
- padding: ${({ theme })=>`${theme.spaces[1]} ${theme.spaces[2]}`};
30
+ // No padding of its own: the row owns the inset, so the label lines up with
31
+ // the icon boxes instead of being pushed in by a second layer of spacing.
32
+ padding: 0;
26
33
  border: 0;
27
- background: ${({ $isActive, $isValidDropTarget, theme })=>{
28
- if ($isValidDropTarget) {
29
- return theme.colors.primary100;
30
- }
31
- return $isActive ? theme.colors.primary100 : 'transparent';
32
- }};
34
+ // The surface — hover, active, drop target — is painted by the row behind
35
+ // this, so it spans the chevron and the actions menu too, not just the label.
36
+ background: transparent;
33
37
  color: ${({ $isActive, theme })=>$isActive ? theme.colors.primary700 : theme.colors.neutral800};
34
38
  border-radius: ${({ theme })=>theme.borderRadius};
35
39
  cursor: ${({ $isMovePending, $isInvalidDropCursor })=>{
@@ -47,15 +51,6 @@ var useSpringLoadedExpand = require('./useSpringLoadedExpand.js');
47
51
  outline-offset: -1px;
48
52
  `}
49
53
 
50
- &:hover {
51
- background: ${({ $isActive, $isValidDropTarget, theme })=>{
52
- if ($isValidDropTarget) {
53
- return theme.colors.primary100;
54
- }
55
- return $isActive ? theme.colors.primary100 : theme.colors.neutral100;
56
- }};
57
- }
58
-
59
54
  &:focus-visible {
60
55
  outline: 2px solid ${({ theme })=>theme.colors.primary600};
61
56
  outline-offset: -2px;
@@ -70,11 +65,22 @@ const TreeRow = styledComponents.styled(designSystem.Flex)`
70
65
  }};
71
66
  pointer-events: ${({ $isMovePending })=>$isMovePending ? 'none' : 'auto'};
72
67
  border-radius: ${({ theme })=>theme.borderRadius};
68
+ background: ${({ $isActive, theme })=>$isActive ? theme.colors.primary100 : 'transparent'};
69
+
70
+ // The whole row lights up, so pointing anywhere along it — chevron, label or
71
+ // the actions trigger — reads as one target.
72
+ &:hover {
73
+ background: ${({ $isActive, theme })=>$isActive ? theme.colors.primary100 : theme.colors.neutral100};
74
+ }
73
75
 
74
76
  ${({ $isValidDropTarget, theme })=>$isValidDropTarget && styledComponents.css`
75
77
  background: ${theme.colors.primary100};
76
78
  outline: 1px dashed ${theme.colors.primary600};
77
79
  outline-offset: -1px;
80
+
81
+ &:hover {
82
+ background: ${theme.colors.primary100};
83
+ }
78
84
  `}
79
85
  `;
80
86
  /* -------------------------------------------------------------------------------------------------
@@ -178,12 +184,46 @@ const useExpandedFolders = (folderStructure, currentFolderId)=>{
178
184
  /* -------------------------------------------------------------------------------------------------
179
185
  * FolderTreeItem — single tree row (internal)
180
186
  * -----------------------------------------------------------------------------------------------*/ const INDENT_PER_LEVEL_REM = 1.6;
187
+ /**
188
+ * Breathing room between the row's highlight and the controls at either end.
189
+ * Asymmetric on purpose: the chevron reads as part of the indent, while the
190
+ * actions trigger sits closer to the edge so it stays out of the name's way.
191
+ */ const ROW_INSET_LEFT_REM = 0.8;
192
+ const ROW_INSET_RIGHT_REM = 0.4;
193
+ /**
194
+ * Every icon in the rail occupies the same 24px box, whether or not it is a
195
+ * control: the chevron and the actions trigger are buttons, the home and folder
196
+ * marks are not. Sizing the box rather than the glyph is what keeps the labels
197
+ * on one vertical line across rows that mix the two.
198
+ */ const IconSlot = styledComponents.styled(designSystem.Flex)`
199
+ width: 2.4rem;
200
+ height: 2.4rem;
201
+ min-width: 2.4rem;
202
+ flex-shrink: 0;
203
+ align-items: center;
204
+ justify-content: center;
205
+ `;
181
206
  /**
182
207
  * A leaf's chevron is present only to keep the folder names aligned, so it
183
208
  * should read as absent. The design system's disabled state is built for real
184
209
  * controls — a filled, bordered pill — which draws more attention than the
185
210
  * enabled chevron next to it. Doubled selector to outrank that rule.
186
211
  */ const ChevronButton = styledComponents.styled(designSystem.IconButton)`
212
+ // Square, so it and the actions trigger read as one pair of controls.
213
+ && {
214
+ width: 2.4rem;
215
+ height: 2.4rem;
216
+ min-width: 2.4rem;
217
+ min-height: 2.4rem;
218
+ padding: 0.4rem;
219
+ }
220
+
221
+ // The row paints its own hover, so the control needs a stronger one of its own
222
+ // to read as a separate target sitting on top of it.
223
+ &&:hover:not([aria-disabled='true']) {
224
+ background: ${({ theme })=>theme.colors.primary200};
225
+ }
226
+
187
227
  &&[aria-disabled='true'] {
188
228
  background: transparent;
189
229
  border-color: transparent;
@@ -194,10 +234,13 @@ const RotatingChevron = styledComponents.styled(icons.ChevronDown)`
194
234
  transform: rotate(${({ $expanded })=>$expanded ? '0deg' : '-90deg'});
195
235
  transition: transform 0.2s ease;
196
236
  `;
197
- const FolderTreeItemInner = ({ id, name, folderChildren, level, currentFolderId, showActiveFolder, isExpanded, onToggle, onExpand, onSelect, isMovePending })=>{
237
+ const FolderTreeItemInner = ({ id, name, parentId, folderChildren, level, currentFolderId, showActiveFolder, isExpanded, onToggle, onExpand, onSelect, isMovePending })=>{
198
238
  const { formatMessage } = reactIntl.useIntl();
199
239
  const hasChildren = folderChildren.length > 0;
200
- const isFolderExpanded = isExpanded(id);
240
+ // A folder keeps its entry in the expanded set after its last subfolder is
241
+ // moved away, so "expanded" has to mean "expanded *and* still has something to
242
+ // show" — otherwise the chevron stays rotated on what is now a leaf.
243
+ const isFolderExpanded = isExpanded(id) && hasChildren;
201
244
  const isActive = showActiveFolder && currentFolderId === id;
202
245
  const { droppable: { setNodeRef }, isOver, showValidDropHighlight, showInvalidDropCursor } = useFolderTreeDroppable.useFolderTreeDroppable({
203
246
  id,
@@ -207,6 +250,10 @@ const FolderTreeItemInner = ({ id, name, folderChildren, level, currentFolderId,
207
250
  id,
208
251
  onExpand
209
252
  ]);
253
+ // Tree rows carry no selection, so a right-click always means "this folder" —
254
+ // none of the list's selection rules apply here.
255
+ const [menuPosition, setMenuPosition] = React.useState(null);
256
+ const rowButtonRef = React.useRef(null);
210
257
  useSpringLoadedExpand.useSpringLoadedExpand({
211
258
  isOver,
212
259
  canExpand: hasChildren && !isFolderExpanded,
@@ -218,12 +265,27 @@ const FolderTreeItemInner = ({ id, name, folderChildren, level, currentFolderId,
218
265
  children: [
219
266
  /*#__PURE__*/ jsxRuntime.jsxs(TreeRow, {
220
267
  ref: setNodeRef,
268
+ "data-native-context-menu": true,
221
269
  alignItems: "center",
222
- paddingLeft: `${level * INDENT_PER_LEVEL_REM}rem`,
270
+ // Indent plus the row's own inset, so the chevron never sits flush
271
+ // against the edge of the highlight at any depth.
272
+ paddingLeft: `${level * INDENT_PER_LEVEL_REM + ROW_INSET_LEFT_REM}rem`,
273
+ paddingRight: `${ROW_INSET_RIGHT_REM}rem`,
223
274
  gap: 1,
275
+ $isActive: isActive,
224
276
  $isValidDropTarget: showValidDropHighlight,
225
277
  $isInvalidDropCursor: showInvalidDropCursor,
226
278
  $isMovePending: isMovePending,
279
+ onContextMenu: (event)=>{
280
+ if (!isEventFromWithin.isEventFromWithin(event)) {
281
+ return;
282
+ }
283
+ event.preventDefault();
284
+ setMenuPosition({
285
+ x: event.clientX,
286
+ y: event.clientY
287
+ });
288
+ },
227
289
  children: [
228
290
  /*#__PURE__*/ jsxRuntime.jsx(ChevronButton, {
229
291
  label: hasChildren ? formatMessage({
@@ -254,6 +316,7 @@ const FolderTreeItemInner = ({ id, name, folderChildren, level, currentFolderId,
254
316
  flex: "1",
255
317
  minWidth: 0,
256
318
  children: /*#__PURE__*/ jsxRuntime.jsx(RowButton, {
319
+ ref: rowButtonRef,
257
320
  type: "button",
258
321
  $isActive: isActive,
259
322
  $isValidDropTarget: showValidDropHighlight,
@@ -269,12 +332,23 @@ const FolderTreeItemInner = ({ id, name, folderChildren, level, currentFolderId,
269
332
  children: name
270
333
  })
271
334
  })
335
+ }),
336
+ /*#__PURE__*/ jsxRuntime.jsx(FolderTreeRowMenu.FolderTreeRowMenu, {
337
+ folder: {
338
+ id,
339
+ name
340
+ },
341
+ parentId: parentId,
342
+ menuPosition: menuPosition,
343
+ returnFocusTo: rowButtonRef.current,
344
+ onCloseMenu: ()=>setMenuPosition(null)
272
345
  })
273
346
  ]
274
347
  }),
275
348
  hasChildren && isFolderExpanded && /*#__PURE__*/ jsxRuntime.jsx(NavList, {
276
349
  children: folderChildren.map((child)=>/*#__PURE__*/ jsxRuntime.jsx(FolderTreeItem, {
277
350
  node: child,
351
+ parentId: id,
278
352
  level: level + 1,
279
353
  currentFolderId: currentFolderId,
280
354
  showActiveFolder: showActiveFolder,
@@ -299,6 +373,7 @@ const FolderTreeItem = ({ node, ...props })=>{
299
373
  folderChildren: node.children ?? []
300
374
  });
301
375
  };
376
+ const FOLDER_TREE_ROOT_SELECTOR = '[data-folder-tree-root]';
302
377
  /**
303
378
  * Left-rail navigation for the Media Library. Fetches folder structure internally
304
379
  * and renders:
@@ -315,7 +390,7 @@ const FolderTreeItem = ({ node, ...props })=>{
315
390
  * Presentational with respect to routing — navigation is delegated to the parent
316
391
  * via `onSelectFolder` so the URL stays the single source of truth (see
317
392
  * `useFolderNavigation`).
318
- */ const FolderTree = ({ currentFolderId, showActiveFolder = true, onSelectFolder })=>{
393
+ */ const FolderTree = ({ currentFolderId, showActiveFolder = true, onSelectFolder, backgroundContextMenu })=>{
319
394
  const { formatMessage } = reactIntl.useIntl();
320
395
  const { data: folderStructure = [], isLoading, isError } = folders.useGetFolderStructureQuery();
321
396
  const { isExpanded, toggleExpanded, expandFolder } = useExpandedFolders(folderStructure, currentFolderId);
@@ -332,11 +407,13 @@ const FolderTreeItem = ({ node, ...props })=>{
332
407
  name: homeLabel
333
408
  });
334
409
  return /*#__PURE__*/ jsxRuntime.jsxs(strapiAdmin.SubNav.Main, {
410
+ "data-folder-tree-root": true,
335
411
  "aria-label": formatMessage({
336
412
  id: translations.getTranslationKey('sidebar.tree.aria-label'),
337
413
  defaultMessage: 'Media library folders'
338
414
  }),
339
415
  children: [
416
+ backgroundContextMenu,
340
417
  /*#__PURE__*/ jsxRuntime.jsx(strapiAdmin.SubNav.Header, {
341
418
  label: formatMessage({
342
419
  id: translations.getTranslationKey('sidebar.title'),
@@ -347,31 +424,44 @@ const FolderTreeItem = ({ node, ...props })=>{
347
424
  children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
348
425
  direction: "column",
349
426
  alignItems: "stretch",
350
- gap: 1,
351
427
  padding: 3,
352
428
  children: [
353
- /*#__PURE__*/ jsxRuntime.jsxs(RowButton, {
429
+ /*#__PURE__*/ jsxRuntime.jsx(TreeRow, {
354
430
  ref: setHomeDropRef,
355
- type: "button",
431
+ "data-native-context-menu": true,
432
+ alignItems: "center",
433
+ // Level 0, so the indent contributes nothing — but the row's own
434
+ // inset still applies, exactly as it does for a top-level folder.
435
+ paddingLeft: `${ROW_INSET_LEFT_REM}rem`,
436
+ paddingRight: `${ROW_INSET_RIGHT_REM}rem`,
356
437
  $isActive: isHomeActive,
357
438
  $isValidDropTarget: showHomeValidDropHighlight,
358
439
  $isInvalidDropCursor: showHomeInvalidDropCursor,
359
440
  $isMovePending: isMovePending,
360
- "aria-current": isHomeActive ? 'page' : undefined,
361
- onClick: ()=>onSelectFolder(null),
362
- "data-testid": "folder-tree-home",
363
- children: [
364
- /*#__PURE__*/ jsxRuntime.jsx(icons.House, {
365
- "aria-hidden": true,
366
- width: "1.6rem",
367
- height: "1.6rem"
368
- }),
369
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
370
- variant: "omega",
371
- fontWeight: isHomeActive ? 'semiBold' : 'regular',
372
- children: homeLabel
373
- })
374
- ]
441
+ children: /*#__PURE__*/ jsxRuntime.jsxs(RowButton, {
442
+ type: "button",
443
+ $isActive: isHomeActive,
444
+ $isValidDropTarget: showHomeValidDropHighlight,
445
+ $isInvalidDropCursor: showHomeInvalidDropCursor,
446
+ $isMovePending: isMovePending,
447
+ "aria-current": isHomeActive ? 'page' : undefined,
448
+ onClick: ()=>onSelectFolder(null),
449
+ "data-testid": "folder-tree-home",
450
+ children: [
451
+ /*#__PURE__*/ jsxRuntime.jsx(IconSlot, {
452
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.House, {
453
+ "aria-hidden": true,
454
+ width: "1.6rem",
455
+ height: "1.6rem"
456
+ })
457
+ }),
458
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
459
+ variant: "omega",
460
+ fontWeight: isHomeActive ? 'semiBold' : 'regular',
461
+ children: homeLabel
462
+ })
463
+ ]
464
+ })
375
465
  }),
376
466
  /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
377
467
  marginTop: 4,
@@ -383,13 +473,14 @@ const FolderTreeItem = ({ node, ...props })=>{
383
473
  paddingBottom: 1,
384
474
  paddingLeft: 2,
385
475
  paddingRight: 2,
386
- marginBottom: 2,
387
476
  children: [
388
- /*#__PURE__*/ jsxRuntime.jsx(icons.Folder, {
389
- "aria-hidden": true,
390
- width: "1.6rem",
391
- height: "1.6rem",
392
- fill: "neutral500"
477
+ /*#__PURE__*/ jsxRuntime.jsx(IconSlot, {
478
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.Folder, {
479
+ "aria-hidden": true,
480
+ width: "1.6rem",
481
+ height: "1.6rem",
482
+ fill: "neutral500"
483
+ })
393
484
  }),
394
485
  /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
395
486
  variant: "sigma",
@@ -442,6 +533,8 @@ const FolderTreeItem = ({ node, ...props })=>{
442
533
  }) : /*#__PURE__*/ jsxRuntime.jsx(NavList, {
443
534
  children: folderStructure.map((node)=>/*#__PURE__*/ jsxRuntime.jsx(FolderTreeItem, {
444
535
  node: node,
536
+ // Top of the tree — these sit at the library root.
537
+ parentId: null,
445
538
  level: 0,
446
539
  currentFolderId: currentFolderId,
447
540
  showActiveFolder: showActiveFolder,
@@ -461,5 +554,6 @@ const FolderTreeItem = ({ node, ...props })=>{
461
554
  });
462
555
  };
463
556
 
557
+ exports.FOLDER_TREE_ROOT_SELECTOR = FOLDER_TREE_ROOT_SELECTOR;
464
558
  exports.FolderTree = FolderTree;
465
559
  //# sourceMappingURL=FolderTree.js.map