@strapi/upload 5.55.1 → 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 (304) hide show
  1. package/dist/admin/hooks/useAIMetadataAvailability.js +14 -0
  2. package/dist/admin/hooks/useAIMetadataAvailability.js.map +1 -0
  3. package/dist/admin/hooks/useAIMetadataAvailability.mjs +12 -0
  4. package/dist/admin/hooks/useAIMetadataAvailability.mjs.map +1 -0
  5. package/dist/admin/hooks/useAIMetadataEnabled.js +7 -5
  6. package/dist/admin/hooks/useAIMetadataEnabled.js.map +1 -1
  7. package/dist/admin/hooks/useAIMetadataEnabled.mjs +7 -5
  8. package/dist/admin/hooks/useAIMetadataEnabled.mjs.map +1 -1
  9. package/dist/admin/hooks/useTracking.js +4 -10
  10. package/dist/admin/hooks/useTracking.js.map +1 -1
  11. package/dist/admin/hooks/useTracking.mjs +5 -10
  12. package/dist/admin/hooks/useTracking.mjs.map +1 -1
  13. package/dist/admin/legacy/hooks/useAIMetadataAvailability.js +14 -0
  14. package/dist/admin/legacy/hooks/useAIMetadataAvailability.js.map +1 -0
  15. package/dist/admin/legacy/hooks/useAIMetadataAvailability.mjs +12 -0
  16. package/dist/admin/legacy/hooks/useAIMetadataAvailability.mjs.map +1 -0
  17. package/dist/admin/legacy/hooks/useAIMetadataEnabled.js +23 -0
  18. package/dist/admin/legacy/hooks/useAIMetadataEnabled.js.map +1 -0
  19. package/dist/admin/legacy/hooks/useAIMetadataEnabled.mjs +21 -0
  20. package/dist/admin/legacy/hooks/useAIMetadataEnabled.mjs.map +1 -0
  21. package/dist/admin/legacy/hooks/useTracking.js +5 -3
  22. package/dist/admin/legacy/hooks/useTracking.js.map +1 -1
  23. package/dist/admin/legacy/hooks/useTracking.mjs +5 -3
  24. package/dist/admin/legacy/hooks/useTracking.mjs.map +1 -1
  25. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js +2 -1
  26. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  27. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs +2 -1
  28. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
  29. package/dist/admin/legacy/pages/App/MediaLibrary.js +6 -5
  30. package/dist/admin/legacy/pages/App/MediaLibrary.js.map +1 -1
  31. package/dist/admin/legacy/pages/App/MediaLibrary.mjs +6 -5
  32. package/dist/admin/legacy/pages/App/MediaLibrary.mjs.map +1 -1
  33. package/dist/admin/pages/Assets/AssetsPage.js +24 -12
  34. package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
  35. package/dist/admin/pages/Assets/AssetsPage.mjs +25 -13
  36. package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
  37. package/dist/admin/pages/Assets/components/AssetActions.js +326 -0
  38. package/dist/admin/pages/Assets/components/AssetActions.js.map +1 -0
  39. package/dist/admin/pages/Assets/components/AssetActions.mjs +324 -0
  40. package/dist/admin/pages/Assets/components/AssetActions.mjs.map +1 -0
  41. package/dist/admin/pages/Assets/components/AssetActionsMenu.js +28 -309
  42. package/dist/admin/pages/Assets/components/AssetActionsMenu.js.map +1 -1
  43. package/dist/admin/pages/Assets/components/AssetActionsMenu.mjs +31 -312
  44. package/dist/admin/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
  45. package/dist/admin/pages/Assets/components/AssetContextMenu.js +79 -0
  46. package/dist/admin/pages/Assets/components/AssetContextMenu.js.map +1 -0
  47. package/dist/admin/pages/Assets/components/AssetContextMenu.mjs +77 -0
  48. package/dist/admin/pages/Assets/components/AssetContextMenu.mjs.map +1 -0
  49. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.js +87 -5
  50. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  51. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +89 -7
  52. package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  53. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +3 -3
  54. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  55. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +3 -3
  56. package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  57. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.js +62 -5
  58. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.js.map +1 -1
  59. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.mjs +60 -6
  60. package/dist/admin/pages/Assets/components/AssetDetails/useCropImg.mjs.map +1 -1
  61. package/dist/admin/pages/Assets/components/AssetsGrid.js +27 -4
  62. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  63. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +27 -4
  64. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  65. package/dist/admin/pages/Assets/components/AssetsTable.js +27 -4
  66. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  67. package/dist/admin/pages/Assets/components/AssetsTable.mjs +27 -4
  68. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  69. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.js +77 -0
  70. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.js.map +1 -0
  71. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.mjs +75 -0
  72. package/dist/admin/pages/Assets/components/CursorAnchoredMenu.mjs.map +1 -0
  73. package/dist/admin/pages/Assets/components/DeleteItemsDialog.js +4 -2
  74. package/dist/admin/pages/Assets/components/DeleteItemsDialog.js.map +1 -1
  75. package/dist/admin/pages/Assets/components/DeleteItemsDialog.mjs +4 -2
  76. package/dist/admin/pages/Assets/components/DeleteItemsDialog.mjs.map +1 -1
  77. package/dist/admin/pages/Assets/components/FolderActions.js +139 -0
  78. package/dist/admin/pages/Assets/components/FolderActions.js.map +1 -0
  79. package/dist/admin/pages/Assets/components/FolderActions.mjs +137 -0
  80. package/dist/admin/pages/Assets/components/FolderActions.mjs.map +1 -0
  81. package/dist/admin/pages/Assets/components/FolderActionsMenu.js +25 -119
  82. package/dist/admin/pages/Assets/components/FolderActionsMenu.js.map +1 -1
  83. package/dist/admin/pages/Assets/components/FolderActionsMenu.mjs +27 -121
  84. package/dist/admin/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
  85. package/dist/admin/pages/Assets/components/FolderContextMenu.js +67 -0
  86. package/dist/admin/pages/Assets/components/FolderContextMenu.js.map +1 -0
  87. package/dist/admin/pages/Assets/components/FolderContextMenu.mjs +65 -0
  88. package/dist/admin/pages/Assets/components/FolderContextMenu.mjs.map +1 -0
  89. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js +139 -45
  90. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  91. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs +140 -47
  92. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  93. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.js +115 -0
  94. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.js.map +1 -0
  95. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.mjs +113 -0
  96. package/dist/admin/pages/Assets/components/FolderTree/FolderTreeRowMenu.mjs.map +1 -0
  97. package/dist/admin/pages/Assets/components/ItemContextMenu.js +125 -0
  98. package/dist/admin/pages/Assets/components/ItemContextMenu.js.map +1 -0
  99. package/dist/admin/pages/Assets/components/ItemContextMenu.mjs +122 -0
  100. package/dist/admin/pages/Assets/components/ItemContextMenu.mjs.map +1 -0
  101. package/dist/admin/pages/Assets/components/MainAreaContextMenu.js +88 -63
  102. package/dist/admin/pages/Assets/components/MainAreaContextMenu.js.map +1 -1
  103. package/dist/admin/pages/Assets/components/MainAreaContextMenu.mjs +88 -63
  104. package/dist/admin/pages/Assets/components/MainAreaContextMenu.mjs.map +1 -1
  105. package/dist/admin/pages/Assets/components/SelectionActions.js +111 -0
  106. package/dist/admin/pages/Assets/components/SelectionActions.js.map +1 -0
  107. package/dist/admin/pages/Assets/components/SelectionActions.mjs +109 -0
  108. package/dist/admin/pages/Assets/components/SelectionActions.mjs.map +1 -0
  109. package/dist/admin/pages/Assets/components/SelectionContextMenu.js +82 -0
  110. package/dist/admin/pages/Assets/components/SelectionContextMenu.js.map +1 -0
  111. package/dist/admin/pages/Assets/components/SelectionContextMenu.mjs +80 -0
  112. package/dist/admin/pages/Assets/components/SelectionContextMenu.mjs.map +1 -0
  113. package/dist/admin/pages/Assets/hooks/useAssetSelection.js +10 -0
  114. package/dist/admin/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  115. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs +10 -0
  116. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  117. package/dist/admin/pages/SettingsPage/SettingsPage.js +10 -3
  118. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  119. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +10 -3
  120. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  121. package/dist/admin/services/api.js.map +1 -1
  122. package/dist/admin/services/api.mjs.map +1 -1
  123. package/dist/admin/src/hooks/useAIMetadataAvailability.d.ts +5 -0
  124. package/dist/admin/src/hooks/useAIMetadataEnabled.d.ts +5 -3
  125. package/dist/admin/src/hooks/useTracking.d.ts +0 -7
  126. package/dist/admin/src/legacy/components/EditAssetDialog/PreviewBox/PreviewComponents.d.ts +2 -2
  127. package/dist/admin/src/legacy/hooks/useAIMetadataAvailability.d.ts +5 -0
  128. package/dist/admin/src/legacy/hooks/useAIMetadataEnabled.d.ts +12 -0
  129. package/dist/admin/src/legacy/hooks/useSettings.d.ts +1 -0
  130. package/dist/admin/src/pages/Assets/components/ActionsMenuContent.d.ts +2 -2
  131. package/dist/admin/src/pages/Assets/components/AssetActions.d.ts +70 -0
  132. package/dist/admin/src/pages/Assets/components/AssetActionsMenu.d.ts +5 -14
  133. package/dist/admin/src/pages/Assets/components/AssetContextMenu.d.ts +27 -0
  134. package/dist/admin/src/pages/Assets/components/AssetDetails/useCropImg.d.ts +16 -0
  135. package/dist/admin/src/pages/Assets/components/CursorAnchoredMenu.d.ts +32 -0
  136. package/dist/admin/src/pages/Assets/components/FolderActions.d.ts +48 -0
  137. package/dist/admin/src/pages/Assets/components/FolderActionsMenu.d.ts +4 -8
  138. package/dist/admin/src/pages/Assets/components/FolderContextMenu.d.ts +21 -0
  139. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTree.d.ts +5 -1
  140. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTreeRowMenu.d.ts +25 -0
  141. package/dist/admin/src/pages/Assets/components/ItemContextMenu.d.ts +53 -0
  142. package/dist/admin/src/pages/Assets/components/MainAreaContextMenu.d.ts +15 -1
  143. package/dist/admin/src/pages/Assets/components/SelectionActions.d.ts +40 -0
  144. package/dist/admin/src/pages/Assets/components/SelectionContextMenu.d.ts +25 -0
  145. package/dist/admin/src/pages/Assets/hooks/useAssetSelection.d.ts +5 -0
  146. package/dist/admin/src/utils/mediaLibraryVersion.d.ts +18 -0
  147. package/dist/admin/translations/en.json.js +9 -3
  148. package/dist/admin/translations/en.json.js.map +1 -1
  149. package/dist/admin/translations/en.json.mjs +9 -3
  150. package/dist/admin/translations/en.json.mjs.map +1 -1
  151. package/dist/admin/utils/mediaLibraryVersion.js +24 -0
  152. package/dist/admin/utils/mediaLibraryVersion.js.map +1 -0
  153. package/dist/admin/utils/mediaLibraryVersion.mjs +20 -0
  154. package/dist/admin/utils/mediaLibraryVersion.mjs.map +1 -0
  155. package/dist/server/bootstrap.js +7 -0
  156. package/dist/server/bootstrap.js.map +1 -1
  157. package/dist/server/bootstrap.mjs +7 -0
  158. package/dist/server/bootstrap.mjs.map +1 -1
  159. package/dist/server/controllers/admin-file.js +2 -2
  160. package/dist/server/controllers/admin-file.js.map +1 -1
  161. package/dist/server/controllers/admin-file.mjs +2 -2
  162. package/dist/server/controllers/admin-file.mjs.map +1 -1
  163. package/dist/server/controllers/admin-folder-file.js +51 -4
  164. package/dist/server/controllers/admin-folder-file.js.map +1 -1
  165. package/dist/server/controllers/admin-folder-file.mjs +52 -5
  166. package/dist/server/controllers/admin-folder-file.mjs.map +1 -1
  167. package/dist/server/controllers/admin-folder.js +5 -5
  168. package/dist/server/controllers/admin-folder.js.map +1 -1
  169. package/dist/server/controllers/admin-folder.mjs +5 -5
  170. package/dist/server/controllers/admin-folder.mjs.map +1 -1
  171. package/dist/server/controllers/admin-settings.js +2 -1
  172. package/dist/server/controllers/admin-settings.js.map +1 -1
  173. package/dist/server/controllers/admin-settings.mjs +2 -1
  174. package/dist/server/controllers/admin-settings.mjs.map +1 -1
  175. package/dist/server/controllers/content-api.js +30 -7
  176. package/dist/server/controllers/content-api.js.map +1 -1
  177. package/dist/server/controllers/content-api.mjs +30 -7
  178. package/dist/server/controllers/content-api.mjs.map +1 -1
  179. package/dist/server/controllers/validation/admin/folder-file.js +4 -4
  180. package/dist/server/controllers/validation/admin/folder-file.js.map +1 -1
  181. package/dist/server/controllers/validation/admin/folder-file.mjs +2 -2
  182. package/dist/server/controllers/validation/admin/folder-file.mjs.map +1 -1
  183. package/dist/server/controllers/validation/admin/folder.js +3 -4
  184. package/dist/server/controllers/validation/admin/folder.js.map +1 -1
  185. package/dist/server/controllers/validation/admin/folder.mjs +3 -4
  186. package/dist/server/controllers/validation/admin/folder.mjs.map +1 -1
  187. package/dist/server/controllers/validation/admin/upload.js +1 -2
  188. package/dist/server/controllers/validation/admin/upload.js.map +1 -1
  189. package/dist/server/controllers/validation/admin/upload.mjs +1 -2
  190. package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
  191. package/dist/server/controllers/validation/admin/utils.js +1 -2
  192. package/dist/server/controllers/validation/admin/utils.js.map +1 -1
  193. package/dist/server/controllers/validation/admin/utils.mjs +1 -2
  194. package/dist/server/controllers/validation/admin/utils.mjs.map +1 -1
  195. package/dist/server/errors.js +12 -0
  196. package/dist/server/errors.js.map +1 -0
  197. package/dist/server/errors.mjs +10 -0
  198. package/dist/server/errors.mjs.map +1 -0
  199. package/dist/server/migrations/unsign-richtext-and-blocks-urls.js +2 -2
  200. package/dist/server/migrations/unsign-richtext-and-blocks-urls.js.map +1 -1
  201. package/dist/server/migrations/unsign-richtext-and-blocks-urls.mjs +1 -1
  202. package/dist/server/migrations/unsign-richtext-and-blocks-urls.mjs.map +1 -1
  203. package/dist/server/routes/content-api.js +3 -3
  204. package/dist/server/routes/content-api.js.map +1 -1
  205. package/dist/server/routes/content-api.mjs +3 -3
  206. package/dist/server/routes/content-api.mjs.map +1 -1
  207. package/dist/server/routes/validation/upload.js +8 -0
  208. package/dist/server/routes/validation/upload.js.map +1 -1
  209. package/dist/server/routes/validation/upload.mjs +8 -0
  210. package/dist/server/routes/validation/upload.mjs.map +1 -1
  211. package/dist/server/services/ai-metadata-provider.js +83 -0
  212. package/dist/server/services/ai-metadata-provider.js.map +1 -0
  213. package/dist/server/services/ai-metadata-provider.mjs +61 -0
  214. package/dist/server/services/ai-metadata-provider.mjs.map +1 -0
  215. package/dist/server/services/ai-metadata-strapi-managed.js +48 -0
  216. package/dist/server/services/ai-metadata-strapi-managed.js.map +1 -0
  217. package/dist/server/services/ai-metadata-strapi-managed.mjs +46 -0
  218. package/dist/server/services/ai-metadata-strapi-managed.mjs.map +1 -0
  219. package/dist/server/services/ai-metadata.js +5 -58
  220. package/dist/server/services/ai-metadata.js.map +1 -1
  221. package/dist/server/services/ai-metadata.mjs +6 -39
  222. package/dist/server/services/ai-metadata.mjs.map +1 -1
  223. package/dist/server/services/api-upload-folder.js +3 -3
  224. package/dist/server/services/api-upload-folder.js.map +1 -1
  225. package/dist/server/services/api-upload-folder.mjs +3 -3
  226. package/dist/server/services/api-upload-folder.mjs.map +1 -1
  227. package/dist/server/services/extensions/utils.js +19 -15
  228. package/dist/server/services/extensions/utils.js.map +1 -1
  229. package/dist/server/services/extensions/utils.mjs +19 -15
  230. package/dist/server/services/extensions/utils.mjs.map +1 -1
  231. package/dist/server/services/file.js +2 -2
  232. package/dist/server/services/file.js.map +1 -1
  233. package/dist/server/services/file.mjs +1 -1
  234. package/dist/server/services/file.mjs.map +1 -1
  235. package/dist/server/services/folder.js +9 -6
  236. package/dist/server/services/folder.js.map +1 -1
  237. package/dist/server/services/folder.mjs +9 -6
  238. package/dist/server/services/folder.mjs.map +1 -1
  239. package/dist/server/services/index.js +3 -1
  240. package/dist/server/services/index.js.map +1 -1
  241. package/dist/server/services/index.mjs +3 -1
  242. package/dist/server/services/index.mjs.map +1 -1
  243. package/dist/server/services/metrics.js +1 -1
  244. package/dist/server/services/metrics.js.map +1 -1
  245. package/dist/server/services/metrics.mjs +1 -1
  246. package/dist/server/services/metrics.mjs.map +1 -1
  247. package/dist/server/services/provider.js +3 -4
  248. package/dist/server/services/provider.js.map +1 -1
  249. package/dist/server/services/provider.mjs +3 -4
  250. package/dist/server/services/provider.mjs.map +1 -1
  251. package/dist/server/services/upload.js +5 -6
  252. package/dist/server/services/upload.js.map +1 -1
  253. package/dist/server/services/upload.mjs +4 -5
  254. package/dist/server/services/upload.mjs.map +1 -1
  255. package/dist/server/services/weekly-metrics.js +2 -2
  256. package/dist/server/services/weekly-metrics.js.map +1 -1
  257. package/dist/server/services/weekly-metrics.mjs +2 -2
  258. package/dist/server/services/weekly-metrics.mjs.map +1 -1
  259. package/dist/server/src/bootstrap.d.ts.map +1 -1
  260. package/dist/server/src/controllers/admin-folder-file.d.ts.map +1 -1
  261. package/dist/server/src/controllers/admin-folder.d.ts.map +1 -1
  262. package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
  263. package/dist/server/src/controllers/content-api.d.ts.map +1 -1
  264. package/dist/server/src/controllers/validation/admin/folder.d.ts.map +1 -1
  265. package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
  266. package/dist/server/src/controllers/validation/admin/utils.d.ts.map +1 -1
  267. package/dist/server/src/errors.d.ts +6 -0
  268. package/dist/server/src/errors.d.ts.map +1 -0
  269. package/dist/server/src/index.d.ts +6 -1
  270. package/dist/server/src/index.d.ts.map +1 -1
  271. package/dist/server/src/mcp/ambient-instance.d.ts +3 -1
  272. package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
  273. package/dist/server/src/routes/validation/upload.d.ts +4 -0
  274. package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
  275. package/dist/server/src/services/ai-metadata-provider.d.ts +26 -0
  276. package/dist/server/src/services/ai-metadata-provider.d.ts.map +1 -0
  277. package/dist/server/src/services/ai-metadata-strapi-managed.d.ts +7 -0
  278. package/dist/server/src/services/ai-metadata-strapi-managed.d.ts.map +1 -0
  279. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  280. package/dist/server/src/services/extensions/utils.d.ts +33 -1
  281. package/dist/server/src/services/extensions/utils.d.ts.map +1 -1
  282. package/dist/server/src/services/folder.d.ts +5 -2
  283. package/dist/server/src/services/folder.d.ts.map +1 -1
  284. package/dist/server/src/services/index.d.ts +6 -1
  285. package/dist/server/src/services/index.d.ts.map +1 -1
  286. package/dist/server/src/services/provider.d.ts.map +1 -1
  287. package/dist/server/src/services/upload.d.ts.map +1 -1
  288. package/dist/server/src/utils/images.d.ts +2 -2
  289. package/dist/server/src/utils/images.d.ts.map +1 -1
  290. package/dist/server/src/utils/index.d.ts +2 -0
  291. package/dist/server/src/utils/index.d.ts.map +1 -1
  292. package/dist/server/utils/images.js +6 -7
  293. package/dist/server/utils/images.js.map +1 -1
  294. package/dist/server/utils/images.mjs +6 -7
  295. package/dist/server/utils/images.mjs.map +1 -1
  296. package/dist/server/utils/index.js.map +1 -1
  297. package/dist/server/utils/index.mjs.map +1 -1
  298. package/dist/shared/contracts/settings.d.ts +6 -0
  299. package/package.json +11 -11
  300. package/dist/admin/legacy/hooks/useAiAvailability.js +0 -22
  301. package/dist/admin/legacy/hooks/useAiAvailability.js.map +0 -1
  302. package/dist/admin/legacy/hooks/useAiAvailability.mjs +0 -20
  303. package/dist/admin/legacy/hooks/useAiAvailability.mjs.map +0 -1
  304. package/dist/admin/src/legacy/hooks/useAiAvailability.d.ts +0 -4
@@ -1 +1 @@
1
- {"version":3,"file":"useCropImg.js","sources":["../../../../../../admin/src/pages/Assets/components/AssetDetails/useCropImg.ts"],"sourcesContent":["import * as React from 'react';\n\nconst QUALITY = 1;\n\ninterface NaturalSize {\n width: number;\n height: number;\n}\n\nexport interface CropRect {\n /** Origin in natural-px from the image top-left. */\n x: number;\n y: number;\n /** Crop area dimensions in natural px. */\n width: number;\n height: number;\n}\n\n/**\n * Resolve a corner-resize drag into a crop rect, keeping the opposite corner\n * (`anchor`) fixed. When `aspectRatio` is set, one dimension is snapped to the\n * ratio first (driven by whichever axis the pointer pushed furthest), then the\n * position is derived from the anchor — so a locked resize never drifts the\n * anchored corner. Pure (no clamping to image bounds; the caller clamps).\n */\nexport const resolveCornerResize = ({\n anchorX,\n anchorY,\n point,\n aspectRatio,\n}: {\n anchorX: number;\n anchorY: number;\n point: { x: number; y: number };\n aspectRatio: number | null;\n}): CropRect => {\n let width = Math.abs(point.x - anchorX);\n let height = Math.abs(point.y - anchorY);\n\n if (aspectRatio) {\n if (width / aspectRatio >= height) {\n height = width / aspectRatio;\n } else {\n width = height * aspectRatio;\n }\n }\n\n const x = point.x < anchorX ? anchorX - width : anchorX;\n const y = point.y < anchorY ? anchorY - height : anchorY;\n\n return { x, y, width, height };\n};\n\n/**\n * Custom crop state + file producer. Replaces a cropperjs-based version: the\n * crop rectangle is stored in natural-image pixels (so it stays locked across\n * window resizes), and `AssetCropEditor` overlays a div sized by\n * (cropNatural × displayRatio). produceFile draws the natural-px crop region\n * straight to a canvas.\n */\nexport const useCropImg = () => {\n const [naturalSize, setNaturalSize] = React.useState<NaturalSize>({ width: 0, height: 0 });\n const [crop, setCrop] = React.useState<CropRect>({ x: 0, y: 0, width: 0, height: 0 });\n const [aspectRatio, setAspectRatioState] = React.useState<number | null>(null);\n const imageRef = React.useRef<HTMLImageElement | null>(null);\n\n /**\n * Call from the <img> onLoad handler. Captures the natural dimensions and\n * seeds the crop to the full image (auto-crop area = 1).\n */\n const init = React.useCallback((image: HTMLImageElement) => {\n imageRef.current = image;\n const next: NaturalSize = { width: image.naturalWidth, height: image.naturalHeight };\n setNaturalSize(next);\n setCrop({ x: 0, y: 0, width: next.width, height: next.height });\n }, []);\n\n const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\n /** Update crop dimensions, clamping to remain inside the image bounds. */\n const setCropSize = React.useCallback(\n (next: Partial<Pick<CropRect, 'width' | 'height'>>) => {\n setCrop((prev) => {\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = next.width !== undefined ? clamp(next.width, 1, maxW) : prev.width;\n let height = next.height !== undefined ? clamp(next.height, 1, maxH) : prev.height;\n\n if (aspectRatio) {\n // When aspect locked, the axis the user is editing wins; the other\n // axis follows. If both changed in one call, prefer width.\n if (next.width !== undefined) {\n height = clamp(width / aspectRatio, 1, maxH);\n } else if (next.height !== undefined) {\n width = clamp(height * aspectRatio, 1, maxW);\n }\n }\n\n return { ...prev, width, height };\n });\n },\n [naturalSize.width, naturalSize.height, aspectRatio]\n );\n\n /** Update crop origin, clamping so the crop stays inside the image. */\n const setCropPosition = React.useCallback(\n (next: Partial<Pick<CropRect, 'x' | 'y'>>) => {\n setCrop((prev) => {\n const x = next.x !== undefined ? clamp(next.x, 0, naturalSize.width - prev.width) : prev.x;\n const y =\n next.y !== undefined ? clamp(next.y, 0, naturalSize.height - prev.height) : prev.y;\n return { ...prev, x, y };\n });\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /** Lock or release the crop aspect ratio. Pass `null` to free it. */\n const setAspectRatio = React.useCallback(\n (ratio: number | null) => {\n setAspectRatioState(ratio);\n if (ratio) {\n setCrop((prev) => {\n // Bring the current rect into the requested ratio without escaping\n // the image bounds.\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = prev.width;\n let height = width / ratio;\n if (height > maxH) {\n height = maxH;\n width = height * ratio;\n }\n if (width > maxW) {\n width = maxW;\n height = width / ratio;\n }\n return { ...prev, width: Math.round(width), height: Math.round(height) };\n });\n }\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /**\n * Draw the crop region from the loaded image element straight to a canvas\n * and produce a File. The image must be CORS-clean (set crossOrigin on the\n * <img>); otherwise canvas.toBlob throws on tainted canvas.\n */\n const produceFile = React.useCallback(\n (name: string, mimeType: string, lastModifiedDate?: string): Promise<globalThis.File> =>\n new Promise((resolve, reject) => {\n const image = imageRef.current;\n if (!image) {\n reject(new Error('Image not ready: call init() before produceFile().'));\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(crop.width));\n canvas.height = Math.max(1, Math.round(crop.height));\n const context = canvas.getContext('2d');\n if (!context) {\n reject(new Error('Could not get a 2D canvas context to crop the image.'));\n return;\n }\n context.drawImage(\n image,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n 0,\n 0,\n canvas.width,\n canvas.height\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Could not export the cropped image to a blob.'));\n return;\n }\n resolve(\n new File([blob], name, {\n type: mimeType,\n lastModified: lastModifiedDate ? new Date(lastModifiedDate).getTime() : Date.now(),\n })\n );\n },\n mimeType,\n QUALITY\n );\n }),\n [crop.x, crop.y, crop.width, crop.height]\n );\n\n return {\n init,\n crop,\n naturalSize,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n // Round-aware getters for the px inputs.\n width: Math.round(crop.width),\n height: Math.round(crop.height),\n };\n};\n"],"names":["QUALITY","resolveCornerResize","anchorX","anchorY","point","aspectRatio","width","Math","abs","x","height","y","useCropImg","naturalSize","setNaturalSize","React","useState","crop","setCrop","setAspectRatioState","imageRef","useRef","init","useCallback","image","current","next","naturalWidth","naturalHeight","clamp","value","min","max","setCropSize","prev","maxW","maxH","undefined","setCropPosition","setAspectRatio","ratio","round","produceFile","name","mimeType","lastModifiedDate","Promise","resolve","reject","Error","canvas","document","createElement","context","getContext","drawImage","toBlob","blob","File","type","lastModified","Date","getTime","now"],"mappings":"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"}
1
+ {"version":3,"file":"useCropImg.js","sources":["../../../../../../admin/src/pages/Assets/components/AssetDetails/useCropImg.ts"],"sourcesContent":["import * as React from 'react';\n\nconst QUALITY = 1;\n\ninterface NaturalSize {\n width: number;\n height: number;\n}\n\nexport interface CropRect {\n /** Origin in natural-px from the image top-left. */\n x: number;\n y: number;\n /** Crop area dimensions in natural px. */\n width: number;\n height: number;\n}\n\n/**\n * Resolve a corner-resize drag into a crop rect, keeping the opposite corner\n * (`anchor`) fixed. When `aspectRatio` is set, one dimension is snapped to the\n * ratio first (driven by whichever axis the pointer pushed furthest), then the\n * position is derived from the anchor — so a locked resize never drifts the\n * anchored corner. Pure (no clamping to image bounds; the caller clamps).\n */\nexport const resolveCornerResize = ({\n anchorX,\n anchorY,\n point,\n aspectRatio,\n}: {\n anchorX: number;\n anchorY: number;\n point: { x: number; y: number };\n aspectRatio: number | null;\n}): CropRect => {\n let width = Math.abs(point.x - anchorX);\n let height = Math.abs(point.y - anchorY);\n\n if (aspectRatio) {\n if (width / aspectRatio >= height) {\n height = width / aspectRatio;\n } else {\n width = height * aspectRatio;\n }\n }\n\n const x = point.x < anchorX ? anchorX - width : anchorX;\n const y = point.y < anchorY ? anchorY - height : anchorY;\n\n return { x, y, width, height };\n};\n\nexport type Rotation = 0 | 90 | 180 | 270;\n\n/**\n * Remap a crop rect through a quarter-turn. `size` is the image size *before* the\n * turn, so the returned rect is expressed against the swapped size for 90/270.\n * Pure: the caller swaps `naturalSize` to match.\n */\nexport const rotateCropRect = (\n crop: CropRect,\n direction: 'left' | 'right',\n size: NaturalSize\n): CropRect =>\n direction === 'right'\n ? {\n x: size.height - (crop.y + crop.height),\n y: crop.x,\n width: crop.height,\n height: crop.width,\n }\n : {\n x: crop.y,\n y: size.width - (crop.x + crop.width),\n width: crop.height,\n height: crop.width,\n };\n\n/**\n * The crop rect expressed against the *unrotated* source, by undoing each quarter-turn\n * already applied. `produceFile` needs it to know which source pixels to sample.\n */\nexport const sourceCropRect = (\n crop: CropRect,\n rotation: Rotation,\n rotatedSize: NaturalSize\n): CropRect => {\n let rect = crop;\n let size = rotatedSize;\n\n for (let turn = 0; turn < rotation / 90; turn += 1) {\n rect = rotateCropRect(rect, 'left', size);\n size = { width: size.height, height: size.width };\n }\n\n return rect;\n};\n\n/** Advance a rotation by one quarter-turn, wrapping at 360. */\nexport const nextRotation = (current: Rotation, direction: 'left' | 'right'): Rotation =>\n ((current + (direction === 'right' ? 90 : 270)) % 360) as Rotation;\n\n/**\n * Custom crop state + file producer. Replaces a cropperjs-based version: the\n * crop rectangle is stored in natural-image pixels (so it stays locked across\n * window resizes), and `AssetCropEditor` overlays a div sized by\n * (cropNatural × displayRatio). produceFile draws the natural-px crop region\n * straight to a canvas.\n */\nexport const useCropImg = () => {\n const [naturalSize, setNaturalSize] = React.useState<NaturalSize>({ width: 0, height: 0 });\n const [crop, setCrop] = React.useState<CropRect>({ x: 0, y: 0, width: 0, height: 0 });\n const [aspectRatio, setAspectRatioState] = React.useState<number | null>(null);\n const [rotation, setRotation] = React.useState<Rotation>(0);\n const imageRef = React.useRef<HTMLImageElement | null>(null);\n\n /**\n * Call from the <img> onLoad handler. Captures the natural dimensions and\n * seeds the crop to the full image (auto-crop area = 1).\n */\n const init = React.useCallback((image: HTMLImageElement) => {\n imageRef.current = image;\n const next: NaturalSize = { width: image.naturalWidth, height: image.naturalHeight };\n setNaturalSize(next);\n setCrop({ x: 0, y: 0, width: next.width, height: next.height });\n setRotation(0);\n }, []);\n\n /**\n * Turn the image a quarter-turn. `naturalSize` swaps and the crop rect is remapped\n * so the same pixels stay selected; nothing is reset.\n */\n const rotate = React.useCallback(\n (direction: 'left' | 'right') => {\n setCrop((prev) => rotateCropRect(prev, direction, naturalSize));\n setNaturalSize((prev) => ({ width: prev.height, height: prev.width }));\n setRotation((prev) => nextRotation(prev, direction));\n // A locked ratio describes the orientation it was locked in, so a quarter\n // turn inverts it. Without this it keeps enforcing the pre-rotation shape\n // and fights every later resize.\n setAspectRatioState((prev) => (prev ? 1 / prev : prev));\n },\n [naturalSize]\n );\n\n const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\n /** Update crop dimensions, clamping to remain inside the image bounds. */\n const setCropSize = React.useCallback(\n (next: Partial<Pick<CropRect, 'width' | 'height'>>) => {\n setCrop((prev) => {\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = next.width !== undefined ? clamp(next.width, 1, maxW) : prev.width;\n let height = next.height !== undefined ? clamp(next.height, 1, maxH) : prev.height;\n\n if (aspectRatio) {\n // When aspect locked, the axis the user is editing wins; the other\n // axis follows. If both changed in one call, prefer width.\n if (next.width !== undefined) {\n height = clamp(width / aspectRatio, 1, maxH);\n } else if (next.height !== undefined) {\n width = clamp(height * aspectRatio, 1, maxW);\n }\n }\n\n return { ...prev, width, height };\n });\n },\n [naturalSize.width, naturalSize.height, aspectRatio]\n );\n\n /** Update crop origin, clamping so the crop stays inside the image. */\n const setCropPosition = React.useCallback(\n (next: Partial<Pick<CropRect, 'x' | 'y'>>) => {\n setCrop((prev) => {\n const x = next.x !== undefined ? clamp(next.x, 0, naturalSize.width - prev.width) : prev.x;\n const y =\n next.y !== undefined ? clamp(next.y, 0, naturalSize.height - prev.height) : prev.y;\n return { ...prev, x, y };\n });\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /** Lock or release the crop aspect ratio. Pass `null` to free it. */\n const setAspectRatio = React.useCallback(\n (ratio: number | null) => {\n setAspectRatioState(ratio);\n if (ratio) {\n setCrop((prev) => {\n // Bring the current rect into the requested ratio without escaping\n // the image bounds.\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = prev.width;\n let height = width / ratio;\n if (height > maxH) {\n height = maxH;\n width = height * ratio;\n }\n if (width > maxW) {\n width = maxW;\n height = width / ratio;\n }\n return { ...prev, width: Math.round(width), height: Math.round(height) };\n });\n }\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /**\n * Draw the crop region from the loaded image element straight to a canvas\n * and produce a File. The image must be CORS-clean (set crossOrigin on the\n * <img>); otherwise canvas.toBlob throws on tainted canvas.\n */\n const produceFile = React.useCallback(\n (name: string, mimeType: string, lastModifiedDate?: string): Promise<globalThis.File> =>\n new Promise((resolve, reject) => {\n const image = imageRef.current;\n if (!image) {\n reject(new Error('Image not ready: call init() before produceFile().'));\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(crop.width));\n canvas.height = Math.max(1, Math.round(crop.height));\n const context = canvas.getContext('2d');\n if (!context) {\n reject(new Error('Could not get a 2D canvas context to crop the image.'));\n return;\n }\n const source = sourceCropRect(crop, rotation, naturalSize);\n\n context.translate(canvas.width / 2, canvas.height / 2);\n context.rotate((rotation * Math.PI) / 180);\n context.drawImage(\n image,\n source.x,\n source.y,\n source.width,\n source.height,\n -source.width / 2,\n -source.height / 2,\n source.width,\n source.height\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Could not export the cropped image to a blob.'));\n return;\n }\n resolve(\n new File([blob], name, {\n type: mimeType,\n lastModified: lastModifiedDate ? new Date(lastModifiedDate).getTime() : Date.now(),\n })\n );\n },\n mimeType,\n QUALITY\n );\n }),\n [crop, rotation, naturalSize]\n );\n\n return {\n init,\n crop,\n naturalSize,\n rotation,\n rotate,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n // Round-aware getters for the px inputs.\n width: Math.round(crop.width),\n height: Math.round(crop.height),\n };\n};\n"],"names":["QUALITY","resolveCornerResize","anchorX","anchorY","point","aspectRatio","width","Math","abs","x","height","y","rotateCropRect","crop","direction","size","sourceCropRect","rotation","rotatedSize","rect","turn","nextRotation","current","useCropImg","naturalSize","setNaturalSize","React","useState","setCrop","setAspectRatioState","setRotation","imageRef","useRef","init","useCallback","image","next","naturalWidth","naturalHeight","rotate","prev","clamp","value","min","max","setCropSize","maxW","maxH","undefined","setCropPosition","setAspectRatio","ratio","round","produceFile","name","mimeType","lastModifiedDate","Promise","resolve","reject","Error","canvas","document","createElement","context","getContext","source","translate","PI","drawImage","toBlob","blob","File","type","lastModified","Date","getTime","now"],"mappings":"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"}
@@ -26,6 +26,37 @@ const QUALITY = 1;
26
26
  height
27
27
  };
28
28
  };
29
+ /**
30
+ * Remap a crop rect through a quarter-turn. `size` is the image size *before* the
31
+ * turn, so the returned rect is expressed against the swapped size for 90/270.
32
+ * Pure: the caller swaps `naturalSize` to match.
33
+ */ const rotateCropRect = (crop, direction, size)=>direction === 'right' ? {
34
+ x: size.height - (crop.y + crop.height),
35
+ y: crop.x,
36
+ width: crop.height,
37
+ height: crop.width
38
+ } : {
39
+ x: crop.y,
40
+ y: size.width - (crop.x + crop.width),
41
+ width: crop.height,
42
+ height: crop.width
43
+ };
44
+ /**
45
+ * The crop rect expressed against the *unrotated* source, by undoing each quarter-turn
46
+ * already applied. `produceFile` needs it to know which source pixels to sample.
47
+ */ const sourceCropRect = (crop, rotation, rotatedSize)=>{
48
+ let rect = crop;
49
+ let size = rotatedSize;
50
+ for(let turn = 0; turn < rotation / 90; turn += 1){
51
+ rect = rotateCropRect(rect, 'left', size);
52
+ size = {
53
+ width: size.height,
54
+ height: size.width
55
+ };
56
+ }
57
+ return rect;
58
+ };
59
+ /** Advance a rotation by one quarter-turn, wrapping at 360. */ const nextRotation = (current, direction)=>(current + (direction === 'right' ? 90 : 270)) % 360;
29
60
  /**
30
61
  * Custom crop state + file producer. Replaces a cropperjs-based version: the
31
62
  * crop rectangle is stored in natural-image pixels (so it stays locked across
@@ -44,6 +75,7 @@ const QUALITY = 1;
44
75
  height: 0
45
76
  });
46
77
  const [aspectRatio, setAspectRatioState] = React.useState(null);
78
+ const [rotation, setRotation] = React.useState(0);
47
79
  const imageRef = React.useRef(null);
48
80
  /**
49
81
  * Call from the <img> onLoad handler. Captures the natural dimensions and
@@ -61,7 +93,25 @@ const QUALITY = 1;
61
93
  width: next.width,
62
94
  height: next.height
63
95
  });
96
+ setRotation(0);
64
97
  }, []);
98
+ /**
99
+ * Turn the image a quarter-turn. `naturalSize` swaps and the crop rect is remapped
100
+ * so the same pixels stay selected; nothing is reset.
101
+ */ const rotate = React.useCallback((direction)=>{
102
+ setCrop((prev)=>rotateCropRect(prev, direction, naturalSize));
103
+ setNaturalSize((prev)=>({
104
+ width: prev.height,
105
+ height: prev.width
106
+ }));
107
+ setRotation((prev)=>nextRotation(prev, direction));
108
+ // A locked ratio describes the orientation it was locked in, so a quarter
109
+ // turn inverts it. Without this it keeps enforcing the pre-rotation shape
110
+ // and fights every later resize.
111
+ setAspectRatioState((prev)=>prev ? 1 / prev : prev);
112
+ }, [
113
+ naturalSize
114
+ ]);
65
115
  const clamp = (value, min, max)=>Math.min(max, Math.max(min, value));
66
116
  /** Update crop dimensions, clamping to remain inside the image bounds. */ const setCropSize = React.useCallback((next)=>{
67
117
  setCrop((prev)=>{
@@ -150,7 +200,10 @@ const QUALITY = 1;
150
200
  reject(new Error('Could not get a 2D canvas context to crop the image.'));
151
201
  return;
152
202
  }
153
- context.drawImage(image, crop.x, crop.y, crop.width, crop.height, 0, 0, canvas.width, canvas.height);
203
+ const source = sourceCropRect(crop, rotation, naturalSize);
204
+ context.translate(canvas.width / 2, canvas.height / 2);
205
+ context.rotate(rotation * Math.PI / 180);
206
+ context.drawImage(image, source.x, source.y, source.width, source.height, -source.width / 2, -source.height / 2, source.width, source.height);
154
207
  canvas.toBlob((blob)=>{
155
208
  if (!blob) {
156
209
  reject(new Error('Could not export the cropped image to a blob.'));
@@ -164,15 +217,16 @@ const QUALITY = 1;
164
217
  }));
165
218
  }, mimeType, QUALITY);
166
219
  }), [
167
- crop.x,
168
- crop.y,
169
- crop.width,
170
- crop.height
220
+ crop,
221
+ rotation,
222
+ naturalSize
171
223
  ]);
172
224
  return {
173
225
  init,
174
226
  crop,
175
227
  naturalSize,
228
+ rotation,
229
+ rotate,
176
230
  aspectRatio,
177
231
  setCropSize,
178
232
  setCropPosition,
@@ -184,5 +238,5 @@ const QUALITY = 1;
184
238
  };
185
239
  };
186
240
 
187
- export { resolveCornerResize, useCropImg };
241
+ export { nextRotation, resolveCornerResize, rotateCropRect, sourceCropRect, useCropImg };
188
242
  //# sourceMappingURL=useCropImg.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCropImg.mjs","sources":["../../../../../../admin/src/pages/Assets/components/AssetDetails/useCropImg.ts"],"sourcesContent":["import * as React from 'react';\n\nconst QUALITY = 1;\n\ninterface NaturalSize {\n width: number;\n height: number;\n}\n\nexport interface CropRect {\n /** Origin in natural-px from the image top-left. */\n x: number;\n y: number;\n /** Crop area dimensions in natural px. */\n width: number;\n height: number;\n}\n\n/**\n * Resolve a corner-resize drag into a crop rect, keeping the opposite corner\n * (`anchor`) fixed. When `aspectRatio` is set, one dimension is snapped to the\n * ratio first (driven by whichever axis the pointer pushed furthest), then the\n * position is derived from the anchor — so a locked resize never drifts the\n * anchored corner. Pure (no clamping to image bounds; the caller clamps).\n */\nexport const resolveCornerResize = ({\n anchorX,\n anchorY,\n point,\n aspectRatio,\n}: {\n anchorX: number;\n anchorY: number;\n point: { x: number; y: number };\n aspectRatio: number | null;\n}): CropRect => {\n let width = Math.abs(point.x - anchorX);\n let height = Math.abs(point.y - anchorY);\n\n if (aspectRatio) {\n if (width / aspectRatio >= height) {\n height = width / aspectRatio;\n } else {\n width = height * aspectRatio;\n }\n }\n\n const x = point.x < anchorX ? anchorX - width : anchorX;\n const y = point.y < anchorY ? anchorY - height : anchorY;\n\n return { x, y, width, height };\n};\n\n/**\n * Custom crop state + file producer. Replaces a cropperjs-based version: the\n * crop rectangle is stored in natural-image pixels (so it stays locked across\n * window resizes), and `AssetCropEditor` overlays a div sized by\n * (cropNatural × displayRatio). produceFile draws the natural-px crop region\n * straight to a canvas.\n */\nexport const useCropImg = () => {\n const [naturalSize, setNaturalSize] = React.useState<NaturalSize>({ width: 0, height: 0 });\n const [crop, setCrop] = React.useState<CropRect>({ x: 0, y: 0, width: 0, height: 0 });\n const [aspectRatio, setAspectRatioState] = React.useState<number | null>(null);\n const imageRef = React.useRef<HTMLImageElement | null>(null);\n\n /**\n * Call from the <img> onLoad handler. Captures the natural dimensions and\n * seeds the crop to the full image (auto-crop area = 1).\n */\n const init = React.useCallback((image: HTMLImageElement) => {\n imageRef.current = image;\n const next: NaturalSize = { width: image.naturalWidth, height: image.naturalHeight };\n setNaturalSize(next);\n setCrop({ x: 0, y: 0, width: next.width, height: next.height });\n }, []);\n\n const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\n /** Update crop dimensions, clamping to remain inside the image bounds. */\n const setCropSize = React.useCallback(\n (next: Partial<Pick<CropRect, 'width' | 'height'>>) => {\n setCrop((prev) => {\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = next.width !== undefined ? clamp(next.width, 1, maxW) : prev.width;\n let height = next.height !== undefined ? clamp(next.height, 1, maxH) : prev.height;\n\n if (aspectRatio) {\n // When aspect locked, the axis the user is editing wins; the other\n // axis follows. If both changed in one call, prefer width.\n if (next.width !== undefined) {\n height = clamp(width / aspectRatio, 1, maxH);\n } else if (next.height !== undefined) {\n width = clamp(height * aspectRatio, 1, maxW);\n }\n }\n\n return { ...prev, width, height };\n });\n },\n [naturalSize.width, naturalSize.height, aspectRatio]\n );\n\n /** Update crop origin, clamping so the crop stays inside the image. */\n const setCropPosition = React.useCallback(\n (next: Partial<Pick<CropRect, 'x' | 'y'>>) => {\n setCrop((prev) => {\n const x = next.x !== undefined ? clamp(next.x, 0, naturalSize.width - prev.width) : prev.x;\n const y =\n next.y !== undefined ? clamp(next.y, 0, naturalSize.height - prev.height) : prev.y;\n return { ...prev, x, y };\n });\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /** Lock or release the crop aspect ratio. Pass `null` to free it. */\n const setAspectRatio = React.useCallback(\n (ratio: number | null) => {\n setAspectRatioState(ratio);\n if (ratio) {\n setCrop((prev) => {\n // Bring the current rect into the requested ratio without escaping\n // the image bounds.\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = prev.width;\n let height = width / ratio;\n if (height > maxH) {\n height = maxH;\n width = height * ratio;\n }\n if (width > maxW) {\n width = maxW;\n height = width / ratio;\n }\n return { ...prev, width: Math.round(width), height: Math.round(height) };\n });\n }\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /**\n * Draw the crop region from the loaded image element straight to a canvas\n * and produce a File. The image must be CORS-clean (set crossOrigin on the\n * <img>); otherwise canvas.toBlob throws on tainted canvas.\n */\n const produceFile = React.useCallback(\n (name: string, mimeType: string, lastModifiedDate?: string): Promise<globalThis.File> =>\n new Promise((resolve, reject) => {\n const image = imageRef.current;\n if (!image) {\n reject(new Error('Image not ready: call init() before produceFile().'));\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(crop.width));\n canvas.height = Math.max(1, Math.round(crop.height));\n const context = canvas.getContext('2d');\n if (!context) {\n reject(new Error('Could not get a 2D canvas context to crop the image.'));\n return;\n }\n context.drawImage(\n image,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n 0,\n 0,\n canvas.width,\n canvas.height\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Could not export the cropped image to a blob.'));\n return;\n }\n resolve(\n new File([blob], name, {\n type: mimeType,\n lastModified: lastModifiedDate ? new Date(lastModifiedDate).getTime() : Date.now(),\n })\n );\n },\n mimeType,\n QUALITY\n );\n }),\n [crop.x, crop.y, crop.width, crop.height]\n );\n\n return {\n init,\n crop,\n naturalSize,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n // Round-aware getters for the px inputs.\n width: Math.round(crop.width),\n height: Math.round(crop.height),\n };\n};\n"],"names":["QUALITY","resolveCornerResize","anchorX","anchorY","point","aspectRatio","width","Math","abs","x","height","y","useCropImg","naturalSize","setNaturalSize","React","useState","crop","setCrop","setAspectRatioState","imageRef","useRef","init","useCallback","image","current","next","naturalWidth","naturalHeight","clamp","value","min","max","setCropSize","prev","maxW","maxH","undefined","setCropPosition","setAspectRatio","ratio","round","produceFile","name","mimeType","lastModifiedDate","Promise","resolve","reject","Error","canvas","document","createElement","context","getContext","drawImage","toBlob","blob","File","type","lastModified","Date","getTime","now"],"mappings":"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"}
1
+ {"version":3,"file":"useCropImg.mjs","sources":["../../../../../../admin/src/pages/Assets/components/AssetDetails/useCropImg.ts"],"sourcesContent":["import * as React from 'react';\n\nconst QUALITY = 1;\n\ninterface NaturalSize {\n width: number;\n height: number;\n}\n\nexport interface CropRect {\n /** Origin in natural-px from the image top-left. */\n x: number;\n y: number;\n /** Crop area dimensions in natural px. */\n width: number;\n height: number;\n}\n\n/**\n * Resolve a corner-resize drag into a crop rect, keeping the opposite corner\n * (`anchor`) fixed. When `aspectRatio` is set, one dimension is snapped to the\n * ratio first (driven by whichever axis the pointer pushed furthest), then the\n * position is derived from the anchor — so a locked resize never drifts the\n * anchored corner. Pure (no clamping to image bounds; the caller clamps).\n */\nexport const resolveCornerResize = ({\n anchorX,\n anchorY,\n point,\n aspectRatio,\n}: {\n anchorX: number;\n anchorY: number;\n point: { x: number; y: number };\n aspectRatio: number | null;\n}): CropRect => {\n let width = Math.abs(point.x - anchorX);\n let height = Math.abs(point.y - anchorY);\n\n if (aspectRatio) {\n if (width / aspectRatio >= height) {\n height = width / aspectRatio;\n } else {\n width = height * aspectRatio;\n }\n }\n\n const x = point.x < anchorX ? anchorX - width : anchorX;\n const y = point.y < anchorY ? anchorY - height : anchorY;\n\n return { x, y, width, height };\n};\n\nexport type Rotation = 0 | 90 | 180 | 270;\n\n/**\n * Remap a crop rect through a quarter-turn. `size` is the image size *before* the\n * turn, so the returned rect is expressed against the swapped size for 90/270.\n * Pure: the caller swaps `naturalSize` to match.\n */\nexport const rotateCropRect = (\n crop: CropRect,\n direction: 'left' | 'right',\n size: NaturalSize\n): CropRect =>\n direction === 'right'\n ? {\n x: size.height - (crop.y + crop.height),\n y: crop.x,\n width: crop.height,\n height: crop.width,\n }\n : {\n x: crop.y,\n y: size.width - (crop.x + crop.width),\n width: crop.height,\n height: crop.width,\n };\n\n/**\n * The crop rect expressed against the *unrotated* source, by undoing each quarter-turn\n * already applied. `produceFile` needs it to know which source pixels to sample.\n */\nexport const sourceCropRect = (\n crop: CropRect,\n rotation: Rotation,\n rotatedSize: NaturalSize\n): CropRect => {\n let rect = crop;\n let size = rotatedSize;\n\n for (let turn = 0; turn < rotation / 90; turn += 1) {\n rect = rotateCropRect(rect, 'left', size);\n size = { width: size.height, height: size.width };\n }\n\n return rect;\n};\n\n/** Advance a rotation by one quarter-turn, wrapping at 360. */\nexport const nextRotation = (current: Rotation, direction: 'left' | 'right'): Rotation =>\n ((current + (direction === 'right' ? 90 : 270)) % 360) as Rotation;\n\n/**\n * Custom crop state + file producer. Replaces a cropperjs-based version: the\n * crop rectangle is stored in natural-image pixels (so it stays locked across\n * window resizes), and `AssetCropEditor` overlays a div sized by\n * (cropNatural × displayRatio). produceFile draws the natural-px crop region\n * straight to a canvas.\n */\nexport const useCropImg = () => {\n const [naturalSize, setNaturalSize] = React.useState<NaturalSize>({ width: 0, height: 0 });\n const [crop, setCrop] = React.useState<CropRect>({ x: 0, y: 0, width: 0, height: 0 });\n const [aspectRatio, setAspectRatioState] = React.useState<number | null>(null);\n const [rotation, setRotation] = React.useState<Rotation>(0);\n const imageRef = React.useRef<HTMLImageElement | null>(null);\n\n /**\n * Call from the <img> onLoad handler. Captures the natural dimensions and\n * seeds the crop to the full image (auto-crop area = 1).\n */\n const init = React.useCallback((image: HTMLImageElement) => {\n imageRef.current = image;\n const next: NaturalSize = { width: image.naturalWidth, height: image.naturalHeight };\n setNaturalSize(next);\n setCrop({ x: 0, y: 0, width: next.width, height: next.height });\n setRotation(0);\n }, []);\n\n /**\n * Turn the image a quarter-turn. `naturalSize` swaps and the crop rect is remapped\n * so the same pixels stay selected; nothing is reset.\n */\n const rotate = React.useCallback(\n (direction: 'left' | 'right') => {\n setCrop((prev) => rotateCropRect(prev, direction, naturalSize));\n setNaturalSize((prev) => ({ width: prev.height, height: prev.width }));\n setRotation((prev) => nextRotation(prev, direction));\n // A locked ratio describes the orientation it was locked in, so a quarter\n // turn inverts it. Without this it keeps enforcing the pre-rotation shape\n // and fights every later resize.\n setAspectRatioState((prev) => (prev ? 1 / prev : prev));\n },\n [naturalSize]\n );\n\n const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\n /** Update crop dimensions, clamping to remain inside the image bounds. */\n const setCropSize = React.useCallback(\n (next: Partial<Pick<CropRect, 'width' | 'height'>>) => {\n setCrop((prev) => {\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = next.width !== undefined ? clamp(next.width, 1, maxW) : prev.width;\n let height = next.height !== undefined ? clamp(next.height, 1, maxH) : prev.height;\n\n if (aspectRatio) {\n // When aspect locked, the axis the user is editing wins; the other\n // axis follows. If both changed in one call, prefer width.\n if (next.width !== undefined) {\n height = clamp(width / aspectRatio, 1, maxH);\n } else if (next.height !== undefined) {\n width = clamp(height * aspectRatio, 1, maxW);\n }\n }\n\n return { ...prev, width, height };\n });\n },\n [naturalSize.width, naturalSize.height, aspectRatio]\n );\n\n /** Update crop origin, clamping so the crop stays inside the image. */\n const setCropPosition = React.useCallback(\n (next: Partial<Pick<CropRect, 'x' | 'y'>>) => {\n setCrop((prev) => {\n const x = next.x !== undefined ? clamp(next.x, 0, naturalSize.width - prev.width) : prev.x;\n const y =\n next.y !== undefined ? clamp(next.y, 0, naturalSize.height - prev.height) : prev.y;\n return { ...prev, x, y };\n });\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /** Lock or release the crop aspect ratio. Pass `null` to free it. */\n const setAspectRatio = React.useCallback(\n (ratio: number | null) => {\n setAspectRatioState(ratio);\n if (ratio) {\n setCrop((prev) => {\n // Bring the current rect into the requested ratio without escaping\n // the image bounds.\n const maxW = naturalSize.width - prev.x;\n const maxH = naturalSize.height - prev.y;\n let width = prev.width;\n let height = width / ratio;\n if (height > maxH) {\n height = maxH;\n width = height * ratio;\n }\n if (width > maxW) {\n width = maxW;\n height = width / ratio;\n }\n return { ...prev, width: Math.round(width), height: Math.round(height) };\n });\n }\n },\n [naturalSize.width, naturalSize.height]\n );\n\n /**\n * Draw the crop region from the loaded image element straight to a canvas\n * and produce a File. The image must be CORS-clean (set crossOrigin on the\n * <img>); otherwise canvas.toBlob throws on tainted canvas.\n */\n const produceFile = React.useCallback(\n (name: string, mimeType: string, lastModifiedDate?: string): Promise<globalThis.File> =>\n new Promise((resolve, reject) => {\n const image = imageRef.current;\n if (!image) {\n reject(new Error('Image not ready: call init() before produceFile().'));\n return;\n }\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, Math.round(crop.width));\n canvas.height = Math.max(1, Math.round(crop.height));\n const context = canvas.getContext('2d');\n if (!context) {\n reject(new Error('Could not get a 2D canvas context to crop the image.'));\n return;\n }\n const source = sourceCropRect(crop, rotation, naturalSize);\n\n context.translate(canvas.width / 2, canvas.height / 2);\n context.rotate((rotation * Math.PI) / 180);\n context.drawImage(\n image,\n source.x,\n source.y,\n source.width,\n source.height,\n -source.width / 2,\n -source.height / 2,\n source.width,\n source.height\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error('Could not export the cropped image to a blob.'));\n return;\n }\n resolve(\n new File([blob], name, {\n type: mimeType,\n lastModified: lastModifiedDate ? new Date(lastModifiedDate).getTime() : Date.now(),\n })\n );\n },\n mimeType,\n QUALITY\n );\n }),\n [crop, rotation, naturalSize]\n );\n\n return {\n init,\n crop,\n naturalSize,\n rotation,\n rotate,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n // Round-aware getters for the px inputs.\n width: Math.round(crop.width),\n height: Math.round(crop.height),\n };\n};\n"],"names":["QUALITY","resolveCornerResize","anchorX","anchorY","point","aspectRatio","width","Math","abs","x","height","y","rotateCropRect","crop","direction","size","sourceCropRect","rotation","rotatedSize","rect","turn","nextRotation","current","useCropImg","naturalSize","setNaturalSize","React","useState","setCrop","setAspectRatioState","setRotation","imageRef","useRef","init","useCallback","image","next","naturalWidth","naturalHeight","rotate","prev","clamp","value","min","max","setCropSize","maxW","maxH","undefined","setCropPosition","setAspectRatio","ratio","round","produceFile","name","mimeType","lastModifiedDate","Promise","resolve","reject","Error","canvas","document","createElement","context","getContext","source","translate","PI","drawImage","toBlob","blob","File","type","lastModified","Date","getTime","now"],"mappings":"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"}
@@ -23,6 +23,7 @@ var BusyOverlay = require('./BusyOverlay.js');
23
23
  var AssetsDndProvider = require('./Dnd/AssetsDndProvider.js');
24
24
  var useAssetDnd = require('./Dnd/useAssetDnd.js');
25
25
  var FolderActionsMenu = require('./FolderActionsMenu.js');
26
+ var ItemContextMenu = require('./ItemContextMenu.js');
26
27
 
27
28
  /* -------------------------------------------------------------------------------------------------
28
29
  * AssetsGrid
@@ -129,6 +130,7 @@ const FolderCard = ({ folder, orderedItemKeys })=>{
129
130
  };
130
131
  const { isSelected, toggle, selectRange } = useAssetSelection.useAssetSelection();
131
132
  const { canUpdate } = useMediaLibraryPermissions.useMediaLibraryPermissions();
133
+ const openContextMenu = ItemContextMenu.useItemContextMenuTrigger();
132
134
  const { dragData, draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging }, droppable: { setNodeRef: setDropRef }, showValidDropHighlight, showInvalidDropCursor } = useAssetDnd.useFolderDraggableDroppable(folder);
133
135
  const key = selection.folderKey(folder.id);
134
136
  const setNodeRef = (node)=>{
@@ -193,9 +195,19 @@ const FolderCard = ({ folder, orderedItemKeys })=>{
193
195
  },
194
196
  role: "listitem",
195
197
  tabIndex: 0,
196
- // Right-clicking an item is not the background gesture: the folder keeps
197
- // the browser's own menu. See MainAreaContextMenu.
198
+ // Right-click opens this folder's own actions, or the selection's when it
199
+ // is part of one. Still marked as "not the background gesture" so
200
+ // MainAreaContextMenu's create menu stays out of it.
198
201
  "data-native-context-menu": true,
202
+ onContextMenu: (e)=>{
203
+ if (isEventFromWithin.isEventFromWithin(e)) {
204
+ openContextMenu?.(e, key, {
205
+ kind: 'folder',
206
+ folder,
207
+ dragData
208
+ });
209
+ }
210
+ },
199
211
  children: [
200
212
  canUpdate && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
201
213
  onKeyDown: (e)=>e.stopPropagation(),
@@ -355,6 +367,7 @@ const AssetCard = ({ asset, orderedItemKeys, onAssetItemClick })=>{
355
367
  const { isSelected, toggle, selectRange } = useAssetSelection.useAssetSelection();
356
368
  const { canUpdate } = useMediaLibraryPermissions.useMediaLibraryPermissions();
357
369
  const busyMessage = useBusyAssets.useBusyAssetsOptional()?.getBusyMessage(asset.id) ?? null;
370
+ const openContextMenu = ItemContextMenu.useItemContextMenuTrigger();
358
371
  const key = selection.assetKey(asset.id);
359
372
  const selected = isSelected(key);
360
373
  // Plain click opens the asset details; pointer selection lives on the
@@ -414,9 +427,19 @@ const AssetCard = ({ asset, orderedItemKeys, onAssetItemClick })=>{
414
427
  $isSelected: selected,
415
428
  tabIndex: 0,
416
429
  role: "listitem",
417
- // Right-clicking an item is not the background gesture: the card keeps
418
- // the browser's own menu. See MainAreaContextMenu.
430
+ // Right-click opens this asset's own actions, or the selection's when it
431
+ // is part of one. Still marked as "not the background gesture" so
432
+ // MainAreaContextMenu's create menu stays out of it.
419
433
  "data-native-context-menu": true,
434
+ onContextMenu: (e)=>{
435
+ if (isEventFromWithin.isEventFromWithin(e)) {
436
+ openContextMenu?.(e, key, {
437
+ kind: 'asset',
438
+ asset,
439
+ dragData
440
+ });
441
+ }
442
+ },
420
443
  onDragStart: (e)=>e.preventDefault(),
421
444
  onClick: handleCardClick,
422
445
  onKeyDown: handleKeyDown,
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsGrid.js","sources":["../../../../../admin/src/pages/Assets/components/AssetsGrid.tsx"],"sourcesContent":["import { Box, Card, CardBody, CardHeader, Checkbox, Flex } from '@strapi/design-system';\nimport { Folder as FolderIcon } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, css } from 'styled-components';\n\nimport { TruncatedText } from '../../../components/TruncatedText';\nimport { ASSET_TYPES } from '../../../enums';\nimport { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions';\nimport { prefixFileUrlWithBackendUrl } from '../../../utils/files';\nimport { getAssetIcon } from '../../../utils/getAssetIcon';\nimport { isEventFromWithin } from '../../../utils/isEventFromWithin';\nimport { getTranslationKey } from '../../../utils/translations';\nimport { ASSET_DETAILS_TRIGGER_PROPS, ASSET_ITEM_CONTROL_PROPS } from '../constants';\nimport { useAssetSelection } from '../hooks/useAssetSelection';\nimport { useBusyAssetsOptional } from '../hooks/useBusyAssets';\nimport { useFolderNavigation } from '../hooks/useFolderNavigation';\nimport { buildRenderedKeys } from '../utils/renderedKeys';\nimport { assetKey, folderKey, type ItemKey } from '../utils/selection';\n\nimport { AssetActionsMenu } from './AssetActionsMenu';\nimport { BusyOverlay } from './BusyOverlay';\nimport { useAssetsDndOptional } from './Dnd/AssetsDndProvider';\nimport { useFileDraggable, useFolderDraggableDroppable } from './Dnd/useAssetDnd';\nimport { FolderActionsMenu } from './FolderActionsMenu';\n\nimport type { File } from '../../../../../shared/contracts/files';\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\n/* -------------------------------------------------------------------------------------------------\n * AssetsGrid\n * -----------------------------------------------------------------------------------------------*/\n\n// Cards own click, Enter and Space; the controls sitting on them (checkbox, \"...\"\n// menu) must not let those reach the card. Scoped to the wrapper's own DOM\n// subtree so the menu's portaled content — a React child of the wrapper, but\n// never a DOM descendant — still reaches `document`, where Radix listens in\n// order to dismiss its layers.\nconst stopCardEvent = (e: React.SyntheticEvent) => {\n if (isEventFromWithin(e)) {\n e.stopPropagation();\n }\n};\n\n// Top-left selection checkbox overlaid on the asset preview, always visible.\nconst CheckboxOverlay = styled(Flex)`\n position: absolute;\n top: ${({ theme }) => theme.spaces[3]};\n left: ${({ theme }) => theme.spaces[3]};\n z-index: 1;\n box-shadow: ${({ theme }) => theme.shadows.filterShadow};\n`;\n\nconst StyledCard = styled(Card)<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isBusy?: boolean;\n $isSelected?: boolean;\n}>`\n border: 1px solid\n ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary600 : theme.colors.neutral200)};\n border-radius: 8px;\n overflow: hidden;\n isolation: isolate;\n cursor: ${({ $isMovePending, $isBusy }) => ($isMovePending || $isBusy ? 'wait' : 'pointer')};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n /* No opacity change while busy — the overlay does the dimming, and stacking\n one on the other would wash the card out. */\n pointer-events: ${({ $isMovePending, $isBusy }) => ($isMovePending || $isBusy ? 'none' : 'auto')};\n background: ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary100 : undefined)};\n /* Shift+click range selection must not highlight card text. */\n user-select: none;\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n }\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * FolderCard\n * -----------------------------------------------------------------------------------------------*/\n\nconst FoldersRow = styled(Box)`\n grid-column: 1 / -1;\n`;\n\nconst MIN_TILE_WIDTH = '240px';\n\nconst ItemsGrid = styled(Box)`\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(${MIN_TILE_WIDTH}, 100%), 1fr));\n gap: ${({ theme }) => theme.spaces[4]};\n`;\n\nconst StyledFolderCard = styled(Flex)<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isValidDropTarget?: boolean;\n $isInvalidDropTarget?: boolean;\n $isSelected?: boolean;\n}>`\n width: 100%;\n user-select: none;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`}; // 8px 12px\n align-items: center;\n gap: ${({ theme }) => theme.spaces[2]}; // 8px\n border: 1px solid\n ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary600 : theme.colors.neutral200)};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme, $isSelected }) =>\n $isSelected ? theme.colors.primary100 : theme.colors.neutral0};\n cursor: ${({ $isMovePending, $isInvalidDropTarget }) => {\n if ($isMovePending) {\n return 'wait';\n }\n\n return $isInvalidDropTarget ? 'not-allowed' : 'pointer';\n }};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n pointer-events: ${({ $isMovePending }) => ($isMovePending ? 'none' : 'auto')};\n transition: background 0.2s;\n\n ${({ $isValidDropTarget, theme }) =>\n $isValidDropTarget &&\n css`\n background: ${theme.colors.primary100};\n border: 1px dashed ${theme.colors.primary600};\n `}\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n }\n`;\n\nconst FolderIconContainer = styled(Flex)`\n flex-shrink: 0;\n color: ${({ theme }) => theme.colors.neutral600};\n`;\n\nconst FolderName = styled(TruncatedText)`\n flex: 1;\n min-width: 0;\n`;\n\ninterface FolderCardProps {\n folder: Folder;\n orderedItemKeys: ItemKey[];\n}\n\nconst FolderCard = ({ folder, orderedItemKeys }: FolderCardProps) => {\n const { formatMessage } = useIntl();\n const { navigateToFolder } = useFolderNavigation();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { isSelected, toggle, selectRange } = useAssetSelection();\n const { canUpdate } = useMediaLibraryPermissions();\n const {\n dragData,\n draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging },\n droppable: { setNodeRef: setDropRef },\n showValidDropHighlight,\n showInvalidDropCursor,\n } = useFolderDraggableDroppable(folder);\n\n const key = folderKey(folder.id);\n\n const setNodeRef = (node: HTMLElement | null) => {\n setDragRef(node);\n setDropRef(node);\n };\n\n // Folders share the selection mechanism with assets (toggle, range,\n // select-all). Only the plain-click semantic differs: it navigates into the\n // folder instead of selecting it.\n //\n // The containment guard on this and the handlers below is what keeps the\n // actions menu's portaled dialogs — React children of this card — from\n // navigating into the folder or starting a drag.\n const handleClick = (e: React.MouseEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else if (e.metaKey || e.ctrlKey) {\n toggle(key);\n } else {\n navigateToFolder(folder);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n navigateToFolder(folder);\n } else if (e.key === ' ') {\n e.preventDefault();\n toggle(key);\n }\n };\n\n // Checkbox is the pointer path to selection; Shift extends the range.\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else {\n toggle(key);\n }\n };\n\n return (\n <StyledFolderCard\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isValidDropTarget={showValidDropHighlight}\n $isInvalidDropTarget={showInvalidDropCursor}\n $isSelected={isSelected(key)}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onPointerDown={(e: React.PointerEvent) => {\n if (isEventFromWithin(e)) {\n listeners?.onPointerDown?.(e);\n }\n }}\n role=\"listitem\"\n tabIndex={0}\n // Right-clicking an item is not the background gesture: the folder keeps\n // the browser's own menu. See MainAreaContextMenu.\n data-native-context-menu\n >\n {canUpdate && (\n <Flex onKeyDown={(e: React.KeyboardEvent) => e.stopPropagation()}>\n <Checkbox\n checked={isSelected(key)}\n onClick={handleCheckboxClick}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.table.row.select'),\n defaultMessage: 'Select {name}',\n },\n { name: folder.name }\n )}\n />\n </Flex>\n )}\n <FolderIconContainer>\n <FolderIcon width={20} height={20} />\n </FolderIconContainer>\n <FolderName textColor=\"neutral800\">{folder.name}</FolderName>\n <Flex onClick={stopCardEvent} onKeyDown={stopCardEvent} onPointerDown={stopCardEvent}>\n <FolderActionsMenu folder={folder} dragData={dragData} />\n </Flex>\n </StyledFolderCard>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetPreview\n * -----------------------------------------------------------------------------------------------*/\n\nconst PreviewContainer = styled(Box)`\n position: relative;\n width: 100%;\n padding-bottom: 62.5%;\n height: 0;\n overflow: hidden;\n background: repeating-conic-gradient(\n ${({ theme }) => theme.colors.neutral100} 0% 25%,\n transparent 0% 50%\n )\n 50% / 20px 20px;\n`;\n\nconst StyledImage = styled.img`\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n`;\n\nconst IconPreview = styled(Flex)`\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n color: ${({ theme }) => theme.colors.neutral500};\n background: ${({ theme }) => theme.colors.neutral100};\n`;\n\ninterface AssetPreviewProps {\n asset: File;\n}\n\nconst AssetPreview = ({ asset }: AssetPreviewProps) => {\n const { alternativeText, ext, formats, mime, url, updatedAt, isLocal, isUrlSigned } = asset;\n\n if (mime?.includes(ASSET_TYPES.Image)) {\n // Replace keeps the same hash/URL, so without a cache-buster the browser\n // serves the stale thumbnail after a Replace Media. `updatedAt`\n // changes on replace, so it re-fetches exactly once per replacement.\n // Skipped for signed URLs — an extra query param invalidates the signature.\n const cacheKey = updatedAt && !isUrlSigned ? new Date(updatedAt).getTime() : undefined;\n const appendCacheBuster = (raw: string) => {\n if (cacheKey === undefined) {\n return raw;\n }\n return raw.includes('?') ? `${raw}&v=${cacheKey}` : `${raw}?v=${cacheKey}`;\n };\n\n const rawMediaURL =\n prefixFileUrlWithBackendUrl(formats?.thumbnail?.url) ?? prefixFileUrlWithBackendUrl(url);\n const mediaURL = rawMediaURL ? appendCacheBuster(rawMediaURL) : rawMediaURL;\n\n if (mediaURL) {\n return (\n <PreviewContainer>\n <StyledImage\n src={mediaURL}\n alt={alternativeText || ''}\n // Only signed remote URLs need crossOrigin (cache collision with\n // the preview). Public/unsigned remote thumbnails must render\n // without a bucket CORS rule. See #26581.\n crossOrigin={!isLocal && isUrlSigned ? 'anonymous' : undefined}\n draggable={false}\n onDragStart={(e) => e.preventDefault()}\n />\n </PreviewContainer>\n );\n }\n }\n\n const DocIcon = getAssetIcon(mime, ext);\n\n return (\n <PreviewContainer>\n <IconPreview justifyContent=\"center\" alignItems=\"center\">\n <DocIcon width={48} height={48} />\n </IconPreview>\n </PreviewContainer>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetCard\n * -----------------------------------------------------------------------------------------------*/\n\nconst StyledCardHeader = styled(CardHeader)`\n position: relative;\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\nconst CardFooter = styled(Flex)`\n min-width: 0;\n width: 100%;\n`;\n\nconst FileTypeIcon = styled(Flex)`\n color: ${({ theme }) => theme.colors.neutral600};\n flex-shrink: 0;\n`;\n\nconst FileName = styled(TruncatedText)`\n flex: 1;\n min-width: 0;\n`;\n\n// The asset filename is its own interactive element: clicking it opens the\n// details drawer instead of selecting the card (mirrors the table view).\nconst NameButton = styled.button`\n display: inline-flex;\n flex: 1;\n min-width: 0;\n border: none;\n background: transparent;\n padding: 0;\n margin: 0;\n cursor: pointer;\n text-align: left;\n color: inherit;\n font: inherit;\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n border-radius: 2px;\n }\n`;\n\ninterface AssetCardProps {\n asset: File;\n orderedItemKeys: ItemKey[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nconst AssetCard = ({ asset, orderedItemKeys, onAssetItemClick }: AssetCardProps) => {\n const { formatMessage } = useIntl();\n const TypeIcon = getAssetIcon(asset.mime, asset.ext);\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { attributes, listeners, setNodeRef, isDragging, dragData } = useFileDraggable(asset);\n const { isSelected, toggle, selectRange } = useAssetSelection();\n const { canUpdate } = useMediaLibraryPermissions();\n const busyMessage = useBusyAssetsOptional()?.getBusyMessage(asset.id) ?? null;\n\n const key = assetKey(asset.id);\n const selected = isSelected(key);\n\n // Plain click opens the asset details; pointer selection lives on the\n // checkbox only. Modifier clicks keep the selection semantics: shift selects\n // a range, cmd/ctrl toggles.\n //\n // The containment guard on this and the handler below is what keeps the\n // actions menu's portaled dialogs — React children of this card — from\n // opening the details drawer or toggling the selection.\n const handleCardClick = (e: React.MouseEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else if (e.metaKey || e.ctrlKey) {\n toggle(key);\n } else {\n onAssetItemClick(asset.id);\n }\n };\n\n // Space toggles selection (additive), Enter opens the details drawer.\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n onAssetItemClick(asset.id);\n } else if (e.key === ' ') {\n e.preventDefault();\n toggle(key);\n }\n };\n\n const handleNameClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onAssetItemClick(asset.id);\n };\n\n // Same semantics as the table's row checkbox: Shift extends the range,\n // otherwise a plain additive toggle. Never bubbles into the card click.\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else {\n toggle(key);\n }\n };\n\n return (\n <StyledCard\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n {...ASSET_DETAILS_TRIGGER_PROPS}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isBusy={busyMessage !== null}\n $isSelected={selected}\n tabIndex={0}\n role=\"listitem\"\n // Right-clicking an item is not the background gesture: the card keeps\n // the browser's own menu. See MainAreaContextMenu.\n data-native-context-menu\n onDragStart={(e) => e.preventDefault()}\n onClick={handleCardClick}\n onKeyDown={handleKeyDown}\n onPointerDown={(e: React.PointerEvent) => {\n if (isEventFromWithin(e)) {\n listeners?.onPointerDown?.(e);\n }\n }}\n >\n <StyledCardHeader>\n {canUpdate && (\n <CheckboxOverlay\n {...ASSET_ITEM_CONTROL_PROPS}\n onKeyDown={(e: React.KeyboardEvent) => e.stopPropagation()}\n >\n <Checkbox\n checked={selected}\n onClick={handleCheckboxClick}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.table.row.select'),\n defaultMessage: 'Select {name}',\n },\n { name: asset.name }\n )}\n />\n </CheckboxOverlay>\n )}\n <AssetPreview asset={asset} />\n {/* The header is the card's only positioned ancestor, and it's the part\n worth covering — the footer keeps the name legible while the preview\n is mid-replace. Below the checkbox overlay (z-index 1) would hide\n the spinner, so it sits above it. */}\n {busyMessage !== null ? <BusyOverlay zIndex={2}>{busyMessage}</BusyOverlay> : null}\n </StyledCardHeader>\n <CardBody>\n <CardFooter alignItems=\"center\" gap={2}>\n <FileTypeIcon>\n <TypeIcon width={20} height={20} />\n </FileTypeIcon>\n <NameButton type=\"button\" onClick={handleNameClick}>\n <FileName textColor=\"primary800\">{asset.name}</FileName>\n </NameButton>\n <Flex\n {...ASSET_ITEM_CONTROL_PROPS}\n onClick={stopCardEvent}\n onKeyDown={stopCardEvent}\n onPointerDown={stopCardEvent}\n >\n <AssetActionsMenu asset={asset} dragData={dragData} />\n </Flex>\n </CardFooter>\n </CardBody>\n </StyledCard>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetsGrid\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsGridProps {\n assets: File[];\n folders?: Folder[];\n /** Keys of the rendered items, in render order. Owned by the view. */\n renderedKeys?: ItemKey[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nexport const AssetsGrid = ({\n assets,\n folders = [],\n renderedKeys,\n onAssetItemClick,\n}: AssetsGridProps) => {\n const totalItems = folders.length + assets.length;\n\n // Render order: folders always on top in the grid (mixing is table-only) —\n // range selection follows it.\n const orderedItemKeys: ItemKey[] = renderedKeys ?? buildRenderedKeys({ folders, assets });\n\n // The empty state is owned by the page (`AssetsView` renders `EmptyState`) — an\n // empty grid renders nothing at all.\n if (totalItems === 0) {\n return null;\n }\n\n return (\n <ItemsGrid role=\"list\" data-testid=\"assets-grid\">\n {folders.length > 0 && (\n <FoldersRow>\n <ItemsGrid>\n {folders.map((folder) => (\n <FolderCard\n folder={folder}\n orderedItemKeys={orderedItemKeys}\n key={`folder-${folder.id}`}\n />\n ))}\n </ItemsGrid>\n </FoldersRow>\n )}\n {assets.map((asset) => (\n <Flex key={asset.id} direction=\"column\" alignItems=\"stretch\">\n <AssetCard\n asset={asset}\n orderedItemKeys={orderedItemKeys}\n onAssetItemClick={onAssetItemClick}\n />\n </Flex>\n ))}\n </ItemsGrid>\n );\n};\n"],"names":["stopCardEvent","e","isEventFromWithin","stopPropagation","CheckboxOverlay","styled","Flex","theme","spaces","shadows","filterShadow","StyledCard","Card","$isSelected","colors","primary600","neutral200","$isMovePending","$isBusy","$isDragging","primary100","undefined","FoldersRow","Box","MIN_TILE_WIDTH","ItemsGrid","StyledFolderCard","borderRadius","neutral0","$isInvalidDropTarget","$isValidDropTarget","css","FolderIconContainer","neutral600","FolderName","TruncatedText","FolderCard","folder","orderedItemKeys","formatMessage","useIntl","navigateToFolder","useFolderNavigation","isMovePending","useAssetsDndOptional","isSelected","toggle","selectRange","useAssetSelection","canUpdate","useMediaLibraryPermissions","dragData","draggable","attributes","listeners","setNodeRef","setDragRef","isDragging","droppable","setDropRef","showValidDropHighlight","showInvalidDropCursor","useFolderDraggableDroppable","key","folderKey","id","node","handleClick","shiftKey","metaKey","ctrlKey","handleKeyDown","preventDefault","handleCheckboxClick","_jsxs","ref","onClick","onKeyDown","onPointerDown","role","tabIndex","data-native-context-menu","_jsx","Checkbox","checked","aria-label","getTranslationKey","defaultMessage","name","FolderIcon","width","height","textColor","FolderActionsMenu","PreviewContainer","neutral100","StyledImage","img","IconPreview","neutral500","AssetPreview","asset","alternativeText","ext","formats","mime","url","updatedAt","isLocal","isUrlSigned","includes","ASSET_TYPES","Image","cacheKey","Date","getTime","appendCacheBuster","raw","rawMediaURL","prefixFileUrlWithBackendUrl","thumbnail","mediaURL","src","alt","crossOrigin","onDragStart","DocIcon","getAssetIcon","justifyContent","alignItems","StyledCardHeader","CardHeader","CardFooter","FileTypeIcon","FileName","NameButton","button","AssetCard","onAssetItemClick","TypeIcon","useFileDraggable","busyMessage","useBusyAssetsOptional","getBusyMessage","assetKey","selected","handleCardClick","handleNameClick","ASSET_DETAILS_TRIGGER_PROPS","ASSET_ITEM_CONTROL_PROPS","BusyOverlay","zIndex","CardBody","gap","type","AssetActionsMenu","AssetsGrid","assets","folders","renderedKeys","totalItems","length","buildRenderedKeys","data-testid","map","direction"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA;;AAEkG;AAGlG;AACA;AACA;AACA;AACA,MAAMA,gBAAgB,CAACC,CAAAA,GAAAA;AACrB,IAAA,IAAIC,oCAAkBD,CAAAA,CAAAA,EAAI;AACxBA,QAAAA,CAAAA,CAAEE,eAAe,EAAA;AACnB,IAAA;AACF,CAAA;AAEA;AACA,MAAMC,eAAAA,GAAkBC,uBAAAA,CAAOC,iBAAAA,CAAK;;OAE7B,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAAC,CAAA,CAAE,CAAC;QAChC,EAAE,CAAC,EAAED,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAAC,CAAA,CAAE,CAAC;;cAE3B,EAAE,CAAC,EAAED,KAAK,EAAE,GAAKA,KAAAA,CAAME,OAAO,CAACC,YAAY,CAAC;AAC1D,CAAC;AAED,MAAMC,UAAAA,GAAaN,uBAAAA,CAAOO,iBAAAA,CAKxB;;AAEE,IAAA,EAAE,CAAC,EAAEL,KAAK,EAAEM,WAAW,EAAE,GAAMA,WAAAA,GAAcN,KAAAA,CAAMO,MAAM,CAACC,UAAU,GAAGR,MAAMO,MAAM,CAACE,UAAU,CAAE;;;;UAI1F,EAAE,CAAC,EAAEC,cAAc,EAAEC,OAAO,EAAE,GAAMD,cAAAA,IAAkBC,OAAAA,GAAU,MAAA,GAAS,SAAA,CAAW;AACnF,WAAA,EAAE,CAAC,EAAEC,WAAW,EAAE,GAAMA,WAAAA,GAAc,MAAM,CAAA,CAAG;;;kBAGxC,EAAE,CAAC,EAAEF,cAAc,EAAEC,OAAO,EAAE,GAAMD,cAAAA,IAAkBC,OAAAA,GAAU,MAAA,GAAS,MAAA,CAAQ;AACrF,cAAA,EAAE,CAAC,EAAEX,KAAK,EAAEM,WAAW,EAAE,GAAMA,WAAAA,GAAcN,KAAAA,CAAMO,MAAM,CAACM,UAAU,GAAGC,SAAAA,CAAW;;;;;gBAKhF,EAAE,CAAC,EAAEd,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACM,UAAU,CAAC;;;;uBAIlC,EAAE,CAAC,EAAEb,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACC,UAAU,CAAC;;;AAGhE,CAAC;AAED;;AAEkG,qGAElG,MAAMO,UAAAA,GAAajB,uBAAAA,CAAOkB,gBAAAA,CAAI;;AAE9B,CAAC;AAED,MAAMC,cAAAA,GAAiB,OAAA;AAEvB,MAAMC,SAAAA,GAAYpB,uBAAAA,CAAOkB,gBAAAA,CAAI;;AAEyB,sDAAA,EAAEC,cAAAA,CAAe;OAChE,EAAE,CAAC,EAAEjB,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAAC,CAAA,CAAE,CAAC;AACxC,CAAC;AAED,MAAMkB,gBAAAA,GAAmBrB,uBAAAA,CAAOC,iBAAAA,CAM9B;;;AAGS,WAAA,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAK,CAAA,EAAGA,MAAMC,MAAM,CAAC,CAAA,CAAE,CAAC,CAAC,EAAED,KAAAA,CAAMC,MAAM,CAAC,CAAA,CAAE,EAAE,CAAC;;OAE7D,EAAE,CAAC,EAAED,KAAK,EAAE,GAAKA,KAAAA,CAAMC,MAAM,CAAC,CAAA,CAAE,CAAC;;AAEpC,IAAA,EAAE,CAAC,EAAED,KAAK,EAAEM,WAAW,EAAE,GAAMA,WAAAA,GAAcN,KAAAA,CAAMO,MAAM,CAACC,UAAU,GAAGR,MAAMO,MAAM,CAACE,UAAU,CAAE;AACnF,iBAAA,EAAE,CAAC,EAAET,KAAK,EAAE,GAAKA,KAAAA,CAAMoB,YAAY,CAAC;AACvC,cAAA,EAAE,CAAC,EAAEpB,KAAK,EAAEM,WAAW,EAAE,GACnCA,WAAAA,GAAcN,KAAAA,CAAMO,MAAM,CAACM,UAAU,GAAGb,MAAMO,MAAM,CAACc,QAAQ,CAAC;AACxD,UAAA,EAAE,CAAC,EAAEX,cAAc,EAAEY,oBAAoB,EAAE,GAAA;AACjD,IAAA,IAAIZ,cAAAA,EAAgB;QAClB,OAAO,MAAA;AACT,IAAA;AAEA,IAAA,OAAOY,uBAAuB,aAAA,GAAgB,SAAA;AAChD,CAAA,CAAE;AACO,WAAA,EAAE,CAAC,EAAEV,WAAW,EAAE,GAAMA,WAAAA,GAAc,MAAM,CAAA,CAAG;AACxC,kBAAA,EAAE,CAAC,EAAEF,cAAc,EAAE,GAAMA,cAAAA,GAAiB,SAAS,MAAA,CAAQ;;;EAG7E,EAAE,CAAC,EAAEa,kBAAkB,EAAEvB,KAAK,EAAE,GAC9BuB,kBAAAA,IACAC,oBAAG;AACW,kBAAA,EAAExB,KAAAA,CAAMO,MAAM,CAACM,UAAU,CAAC;AACnB,yBAAA,EAAEb,KAAAA,CAAMO,MAAM,CAACC,UAAU,CAAC;AAC/C,IAAA,CAAC;;;gBAGW,EAAE,CAAC,EAAER,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACM,UAAU,CAAC;;;;uBAIlC,EAAE,CAAC,EAAEb,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACC,UAAU,CAAC;;;AAGhE,CAAC;AAED,MAAMiB,mBAAAA,GAAsB3B,uBAAAA,CAAOC,iBAAAA,CAAK;;SAE/B,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACmB,UAAU,CAAC;AAClD,CAAC;AAED,MAAMC,UAAAA,GAAa7B,uBAAAA,CAAO8B,2BAAAA,CAAc;;;AAGxC,CAAC;AAOD,MAAMC,aAAa,CAAC,EAAEC,MAAM,EAAEC,eAAe,EAAmB,GAAA;IAC9D,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;IAC1B,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,uCAAAA,EAAAA;AAC7B,IAAA,MAAM,EAAEC,aAAa,EAAE,GAAGC,sCAAAA,EAAAA,IAA0B;QAAED,aAAAA,EAAe;AAAM,KAAA;AAC3E,IAAA,MAAM,EAAEE,UAAU,EAAEC,MAAM,EAAEC,WAAW,EAAE,GAAGC,mCAAAA,EAAAA;IAC5C,MAAM,EAAEC,SAAS,EAAE,GAAGC,qDAAAA,EAAAA;IACtB,MAAM,EACJC,QAAQ,EACRC,SAAAA,EAAW,EAAEC,UAAU,EAAEC,SAAS,EAAEC,UAAAA,EAAYC,UAAU,EAAEC,UAAU,EAAE,EACxEC,SAAAA,EAAW,EAAEH,UAAAA,EAAYI,UAAU,EAAE,EACrCC,sBAAsB,EACtBC,qBAAqB,EACtB,GAAGC,uCAAAA,CAA4BzB,MAAAA,CAAAA;IAEhC,MAAM0B,GAAAA,GAAMC,mBAAAA,CAAU3B,MAAAA,CAAO4B,EAAE,CAAA;AAE/B,IAAA,MAAMV,aAAa,CAACW,IAAAA,GAAAA;QAClBV,UAAAA,CAAWU,IAAAA,CAAAA;QACXP,UAAAA,CAAWO,IAAAA,CAAAA;AACb,IAAA,CAAA;;;;;;;;AASA,IAAA,MAAMC,cAAc,CAAClE,CAAAA,GAAAA;QACnB,IAAI,CAACC,oCAAkBD,CAAAA,CAAAA,EAAI;AACzB,YAAA;AACF,QAAA;QAEA,IAAIA,CAAAA,CAAEmE,QAAQ,EAAE;AACdrB,YAAAA,WAAAA,CAAYT,eAAAA,EAAiByB,GAAAA,CAAAA;AAC/B,QAAA,CAAA,MAAO,IAAI9D,CAAAA,CAAEoE,OAAO,IAAIpE,CAAAA,CAAEqE,OAAO,EAAE;YACjCxB,MAAAA,CAAOiB,GAAAA,CAAAA;QACT,CAAA,MAAO;YACLtB,gBAAAA,CAAiBJ,MAAAA,CAAAA;AACnB,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMkC,gBAAgB,CAACtE,CAAAA,GAAAA;QACrB,IAAI,CAACC,oCAAkBD,CAAAA,CAAAA,EAAI;AACzB,YAAA;AACF,QAAA;QAEA,IAAIA,CAAAA,CAAE8D,GAAG,KAAK,OAAA,EAAS;AACrB9D,YAAAA,CAAAA,CAAEuE,cAAc,EAAA;YAChB/B,gBAAAA,CAAiBJ,MAAAA,CAAAA;AACnB,QAAA,CAAA,MAAO,IAAIpC,CAAAA,CAAE8D,GAAG,KAAK,GAAA,EAAK;AACxB9D,YAAAA,CAAAA,CAAEuE,cAAc,EAAA;YAChB1B,MAAAA,CAAOiB,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA;;AAGA,IAAA,MAAMU,sBAAsB,CAACxE,CAAAA,GAAAA;AAC3BA,QAAAA,CAAAA,CAAEE,eAAe,EAAA;QACjB,IAAIF,CAAAA,CAAEmE,QAAQ,EAAE;AACdrB,YAAAA,WAAAA,CAAYT,eAAAA,EAAiByB,GAAAA,CAAAA;QAC/B,CAAA,MAAO;YACLjB,MAAAA,CAAOiB,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,qBACEW,eAAA,CAAChD,gBAAAA,EAAAA;QACCiD,GAAAA,EAAKpB,UAAAA;AACJ,QAAA,GAAGF,UAAU;AACb,QAAA,GAAGC,SAAS;QACbnC,WAAAA,EAAasC,UAAAA;QACbxC,cAAAA,EAAgB0B,aAAAA;QAChBb,kBAAAA,EAAoB8B,sBAAAA;QACpB/B,oBAAAA,EAAsBgC,qBAAAA;AACtBhD,QAAAA,WAAAA,EAAagC,UAAAA,CAAWkB,GAAAA,CAAAA;QACxBa,OAAAA,EAAST,WAAAA;QACTU,SAAAA,EAAWN,aAAAA;AACXO,QAAAA,aAAAA,EAAe,CAAC7E,CAAAA,GAAAA;AACd,YAAA,IAAIC,oCAAkBD,CAAAA,CAAAA,EAAI;AACxBqD,gBAAAA,SAAAA,EAAWwB,aAAAA,GAAgB7E,CAAAA,CAAAA;AAC7B,YAAA;AACF,QAAA,CAAA;QACA8E,IAAAA,EAAK,UAAA;QACLC,QAAAA,EAAU,CAAA;;;QAGVC,0BAAwB,EAAA,IAAA;;AAEvBhC,YAAAA,SAAAA,kBACCiC,cAAA,CAAC5E,iBAAAA,EAAAA;gBAAKuE,SAAAA,EAAW,CAAC5E,CAAAA,GAA2BA,CAAAA,CAAEE,eAAe,EAAA;AAC5D,gBAAA,QAAA,gBAAA+E,cAAA,CAACC,qBAAAA,EAAAA;AACCC,oBAAAA,OAAAA,EAASvC,UAAAA,CAAWkB,GAAAA,CAAAA;oBACpBa,OAAAA,EAASH,mBAAAA;AACTY,oBAAAA,YAAAA,EAAY9C,aAAAA,CACV;AACE0B,wBAAAA,EAAAA,EAAIqB,8BAAAA,CAAkB,uBAAA,CAAA;wBACtBC,cAAAA,EAAgB;qBAClB,EACA;AAAEC,wBAAAA,IAAAA,EAAMnD,OAAOmD;AAAK,qBAAA;;;0BAK5BN,cAAA,CAAClD,mBAAAA,EAAAA;AACC,gBAAA,QAAA,gBAAAkD,cAAA,CAACO,YAAAA,EAAAA;oBAAWC,KAAAA,EAAO,EAAA;oBAAIC,MAAAA,EAAQ;;;0BAEjCT,cAAA,CAAChD,UAAAA,EAAAA;gBAAW0D,SAAAA,EAAU,YAAA;AAAcvD,gBAAAA,QAAAA,EAAAA,MAAAA,CAAOmD;;0BAC3CN,cAAA,CAAC5E,iBAAAA,EAAAA;gBAAKsE,OAAAA,EAAS5E,aAAAA;gBAAe6E,SAAAA,EAAW7E,aAAAA;gBAAe8E,aAAAA,EAAe9E,aAAAA;AACrE,gBAAA,QAAA,gBAAAkF,cAAA,CAACW,mCAAAA,EAAAA;oBAAkBxD,MAAAA,EAAQA,MAAAA;oBAAQc,QAAAA,EAAUA;;;;;AAIrD,CAAA;AAEA;;AAEkG,qGAElG,MAAM2C,gBAAAA,GAAmBzF,uBAAAA,CAAOkB,gBAAAA,CAAI;;;;;;;MAO9B,EAAE,CAAC,EAAEhB,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACiF,UAAU,CAAC;;;;AAI/C,CAAC;AAED,MAAMC,WAAAA,GAAc3F,uBAAAA,CAAO4F,GAAG;;;;;;;AAO9B,CAAC;AAED,MAAMC,WAAAA,GAAc7F,uBAAAA,CAAOC,iBAAAA,CAAK;;;;;;SAMvB,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACqF,UAAU,CAAC;cACpC,EAAE,CAAC,EAAE5F,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACiF,UAAU,CAAC;AACvD,CAAC;AAMD,MAAMK,YAAAA,GAAe,CAAC,EAAEC,KAAK,EAAqB,GAAA;AAChD,IAAA,MAAM,EAAEC,eAAe,EAAEC,GAAG,EAAEC,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAEC,SAAS,EAAEC,OAAO,EAAEC,WAAW,EAAE,GAAGR,KAAAA;AAEtF,IAAA,IAAII,IAAAA,EAAMK,QAAAA,CAASC,iBAAAA,CAAYC,KAAK,CAAA,EAAG;;;;;QAKrC,MAAMC,QAAAA,GAAWN,aAAa,CAACE,WAAAA,GAAc,IAAIK,IAAAA,CAAKP,SAAAA,CAAAA,CAAWQ,OAAO,EAAA,GAAK9F,SAAAA;AAC7E,QAAA,MAAM+F,oBAAoB,CAACC,GAAAA,GAAAA;AACzB,YAAA,IAAIJ,aAAa5F,SAAAA,EAAW;gBAC1B,OAAOgG,GAAAA;AACT,YAAA;AACA,YAAA,OAAOA,GAAAA,CAAIP,QAAQ,CAAC,GAAA,CAAA,GAAO,GAAGO,GAAAA,CAAI,GAAG,EAAEJ,QAAAA,CAAAA,CAAU,GAAG,CAAA,EAAGI,GAAAA,CAAI,GAAG,EAAEJ,QAAAA,CAAAA,CAAU;AAC5E,QAAA,CAAA;AAEA,QAAA,MAAMK,WAAAA,GACJC,iCAAAA,CAA4Bf,OAAAA,EAASgB,SAAAA,EAAWd,QAAQa,iCAAAA,CAA4Bb,GAAAA,CAAAA;QACtF,MAAMe,QAAAA,GAAWH,WAAAA,GAAcF,iBAAAA,CAAkBE,WAAAA,CAAAA,GAAeA,WAAAA;AAEhE,QAAA,IAAIG,QAAAA,EAAU;AACZ,YAAA,qBACEvC,cAAA,CAACY,gBAAAA,EAAAA;AACC,gBAAA,QAAA,gBAAAZ,cAAA,CAACc,WAAAA,EAAAA;oBACC0B,GAAAA,EAAKD,QAAAA;AACLE,oBAAAA,GAAAA,EAAKrB,eAAAA,IAAmB,EAAA;;;;oBAIxBsB,WAAAA,EAAa,CAAChB,OAAAA,IAAWC,WAAAA,GAAc,WAAA,GAAcxF,SAAAA;oBACrD+B,SAAAA,EAAW,KAAA;oBACXyE,WAAAA,EAAa,CAAC5H,CAAAA,GAAMA,CAAAA,CAAEuE,cAAc;;;AAI5C,QAAA;AACF,IAAA;IAEA,MAAMsD,OAAAA,GAAUC,0BAAatB,IAAAA,EAAMF,GAAAA,CAAAA;AAEnC,IAAA,qBACErB,cAAA,CAACY,gBAAAA,EAAAA;AACC,QAAA,QAAA,gBAAAZ,cAAA,CAACgB,WAAAA,EAAAA;YAAY8B,cAAAA,EAAe,QAAA;YAASC,UAAAA,EAAW,QAAA;AAC9C,YAAA,QAAA,gBAAA/C,cAAA,CAAC4C,OAAAA,EAAAA;gBAAQpC,KAAAA,EAAO,EAAA;gBAAIC,MAAAA,EAAQ;;;;AAIpC,CAAA;AAEA;;AAEkG,qGAElG,MAAMuC,gBAAAA,GAAmB7H,uBAAAA,CAAO8H,uBAAAA,CAAW;;2BAEhB,EAAE,CAAC,EAAE5H,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACE,UAAU,CAAC;AACpE,CAAC;AAED,MAAMoH,UAAAA,GAAa/H,uBAAAA,CAAOC,iBAAAA,CAAK;;;AAG/B,CAAC;AAED,MAAM+H,YAAAA,GAAehI,uBAAAA,CAAOC,iBAAAA,CAAK;SACxB,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACmB,UAAU,CAAC;;AAElD,CAAC;AAED,MAAMqG,QAAAA,GAAWjI,uBAAAA,CAAO8B,2BAAAA,CAAc;;;AAGtC,CAAC;AAED;AACA;AACA,MAAMoG,UAAAA,GAAalI,uBAAAA,CAAOmI,MAAM;;;;;;;;;;;;;;uBAcT,EAAE,CAAC,EAAEjI,KAAK,EAAE,GAAKA,KAAAA,CAAMO,MAAM,CAACC,UAAU,CAAC;;;;AAIhE,CAAC;AAQD,MAAM0H,SAAAA,GAAY,CAAC,EAAEpC,KAAK,EAAE/D,eAAe,EAAEoG,gBAAgB,EAAkB,GAAA;IAC7E,MAAM,EAAEnG,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAC1B,IAAA,MAAMmG,WAAWZ,yBAAAA,CAAa1B,KAAAA,CAAMI,IAAI,EAAEJ,MAAME,GAAG,CAAA;AACnD,IAAA,MAAM,EAAE5D,aAAa,EAAE,GAAGC,sCAAAA,EAAAA,IAA0B;QAAED,aAAAA,EAAe;AAAM,KAAA;AAC3E,IAAA,MAAM,EAAEU,UAAU,EAAEC,SAAS,EAAEC,UAAU,EAAEE,UAAU,EAAEN,QAAQ,EAAE,GAAGyF,4BAAAA,CAAiBvC,KAAAA,CAAAA;AACrF,IAAA,MAAM,EAAExD,UAAU,EAAEC,MAAM,EAAEC,WAAW,EAAE,GAAGC,mCAAAA,EAAAA;IAC5C,MAAM,EAAEC,SAAS,EAAE,GAAGC,qDAAAA,EAAAA;AACtB,IAAA,MAAM2F,WAAAA,GAAcC,mCAAAA,EAAAA,EAAyBC,cAAAA,CAAe1C,KAAAA,CAAMpC,EAAE,CAAA,IAAK,IAAA;IAEzE,MAAMF,GAAAA,GAAMiF,kBAAAA,CAAS3C,KAAAA,CAAMpC,EAAE,CAAA;AAC7B,IAAA,MAAMgF,WAAWpG,UAAAA,CAAWkB,GAAAA,CAAAA;;;;;;;;AAS5B,IAAA,MAAMmF,kBAAkB,CAACjJ,CAAAA,GAAAA;QACvB,IAAI,CAACC,oCAAkBD,CAAAA,CAAAA,EAAI;AACzB,YAAA;AACF,QAAA;QAEA,IAAIA,CAAAA,CAAEmE,QAAQ,EAAE;AACdrB,YAAAA,WAAAA,CAAYT,eAAAA,EAAiByB,GAAAA,CAAAA;AAC/B,QAAA,CAAA,MAAO,IAAI9D,CAAAA,CAAEoE,OAAO,IAAIpE,CAAAA,CAAEqE,OAAO,EAAE;YACjCxB,MAAAA,CAAOiB,GAAAA,CAAAA;QACT,CAAA,MAAO;AACL2E,YAAAA,gBAAAA,CAAiBrC,MAAMpC,EAAE,CAAA;AAC3B,QAAA;AACF,IAAA,CAAA;;AAGA,IAAA,MAAMM,gBAAgB,CAACtE,CAAAA,GAAAA;QACrB,IAAI,CAACC,oCAAkBD,CAAAA,CAAAA,EAAI;AACzB,YAAA;AACF,QAAA;QAEA,IAAIA,CAAAA,CAAE8D,GAAG,KAAK,OAAA,EAAS;AACrB9D,YAAAA,CAAAA,CAAEuE,cAAc,EAAA;AAChBkE,YAAAA,gBAAAA,CAAiBrC,MAAMpC,EAAE,CAAA;AAC3B,QAAA,CAAA,MAAO,IAAIhE,CAAAA,CAAE8D,GAAG,KAAK,GAAA,EAAK;AACxB9D,YAAAA,CAAAA,CAAEuE,cAAc,EAAA;YAChB1B,MAAAA,CAAOiB,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMoF,kBAAkB,CAAClJ,CAAAA,GAAAA;AACvBA,QAAAA,CAAAA,CAAEE,eAAe,EAAA;AACjBuI,QAAAA,gBAAAA,CAAiBrC,MAAMpC,EAAE,CAAA;AAC3B,IAAA,CAAA;;;AAIA,IAAA,MAAMQ,sBAAsB,CAACxE,CAAAA,GAAAA;AAC3BA,QAAAA,CAAAA,CAAEE,eAAe,EAAA;QACjB,IAAIF,CAAAA,CAAEmE,QAAQ,EAAE;AACdrB,YAAAA,WAAAA,CAAYT,eAAAA,EAAiByB,GAAAA,CAAAA;QAC/B,CAAA,MAAO;YACLjB,MAAAA,CAAOiB,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,qBACEW,eAAA,CAAC/D,UAAAA,EAAAA;QACCgE,GAAAA,EAAKpB,UAAAA;AACJ,QAAA,GAAGF,UAAU;AACb,QAAA,GAAGC,SAAS;AACZ,QAAA,GAAG8F,qCAA2B;QAC/BjI,WAAAA,EAAasC,UAAAA;QACbxC,cAAAA,EAAgB0B,aAAAA;AAChBzB,QAAAA,OAAAA,EAAS2H,WAAAA,KAAgB,IAAA;QACzBhI,WAAAA,EAAaoI,QAAAA;QACbjE,QAAAA,EAAU,CAAA;QACVD,IAAAA,EAAK,UAAA;;;QAGLE,0BAAwB,EAAA,IAAA;QACxB4C,WAAAA,EAAa,CAAC5H,CAAAA,GAAMA,CAAAA,CAAEuE,cAAc,EAAA;QACpCI,OAAAA,EAASsE,eAAAA;QACTrE,SAAAA,EAAWN,aAAAA;AACXO,QAAAA,aAAAA,EAAe,CAAC7E,CAAAA,GAAAA;AACd,YAAA,IAAIC,oCAAkBD,CAAAA,CAAAA,EAAI;AACxBqD,gBAAAA,SAAAA,EAAWwB,aAAAA,GAAgB7E,CAAAA,CAAAA;AAC7B,YAAA;AACF,QAAA,CAAA;;0BAEAyE,eAAA,CAACwD,gBAAAA,EAAAA;;AACEjF,oBAAAA,SAAAA,kBACCiC,cAAA,CAAC9E,eAAAA,EAAAA;AACE,wBAAA,GAAGiJ,kCAAwB;wBAC5BxE,SAAAA,EAAW,CAAC5E,CAAAA,GAA2BA,CAAAA,CAAEE,eAAe,EAAA;AAExD,wBAAA,QAAA,gBAAA+E,cAAA,CAACC,qBAAAA,EAAAA;4BACCC,OAAAA,EAAS6D,QAAAA;4BACTrE,OAAAA,EAASH,mBAAAA;AACTY,4BAAAA,YAAAA,EAAY9C,aAAAA,CACV;AACE0B,gCAAAA,EAAAA,EAAIqB,8BAAAA,CAAkB,uBAAA,CAAA;gCACtBC,cAAAA,EAAgB;6BAClB,EACA;AAAEC,gCAAAA,IAAAA,EAAMa,MAAMb;AAAK,6BAAA;;;kCAK3BN,cAAA,CAACkB,YAAAA,EAAAA;wBAAaC,KAAAA,EAAOA;;AAKpBwC,oBAAAA,WAAAA,KAAgB,qBAAO3D,cAAA,CAACoE,uBAAAA,EAAAA;wBAAYC,MAAAA,EAAQ,CAAA;AAAIV,wBAAAA,QAAAA,EAAAA;AAA6B,qBAAA,CAAA,GAAA;;;0BAEhF3D,cAAA,CAACsE,qBAAAA,EAAAA;AACC,gBAAA,QAAA,gBAAA9E,eAAA,CAAC0D,UAAAA,EAAAA;oBAAWH,UAAAA,EAAW,QAAA;oBAASwB,GAAAA,EAAK,CAAA;;sCACnCvE,cAAA,CAACmD,YAAAA,EAAAA;AACC,4BAAA,QAAA,gBAAAnD,cAAA,CAACyD,QAAAA,EAAAA;gCAASjD,KAAAA,EAAO,EAAA;gCAAIC,MAAAA,EAAQ;;;sCAE/BT,cAAA,CAACqD,UAAAA,EAAAA;4BAAWmB,IAAAA,EAAK,QAAA;4BAAS9E,OAAAA,EAASuE,eAAAA;AACjC,4BAAA,QAAA,gBAAAjE,cAAA,CAACoD,QAAAA,EAAAA;gCAAS1C,SAAAA,EAAU,YAAA;AAAcS,gCAAAA,QAAAA,EAAAA,KAAAA,CAAMb;;;sCAE1CN,cAAA,CAAC5E,iBAAAA,EAAAA;AACE,4BAAA,GAAG+I,kCAAwB;4BAC5BzE,OAAAA,EAAS5E,aAAAA;4BACT6E,SAAAA,EAAW7E,aAAAA;4BACX8E,aAAAA,EAAe9E,aAAAA;AAEf,4BAAA,QAAA,gBAAAkF,cAAA,CAACyE,iCAAAA,EAAAA;gCAAiBtD,KAAAA,EAAOA,KAAAA;gCAAOlD,QAAAA,EAAUA;;;;;;;;AAMtD,CAAA;AAcO,MAAMyG,UAAAA,GAAa,CAAC,EACzBC,MAAM,EACNC,OAAAA,GAAU,EAAE,gBACZC,cAAY,EACZrB,gBAAgB,EACA,GAAA;AAChB,IAAA,MAAMsB,UAAAA,GAAaF,OAAAA,CAAQG,MAAM,GAAGJ,OAAOI,MAAM;;;IAIjD,MAAM3H,eAAAA,GAA6ByH,kBAAgBG,8BAAAA,CAAkB;AAAEJ,QAAAA,OAAAA;AAASD,QAAAA;AAAO,KAAA,CAAA;;;AAIvF,IAAA,IAAIG,eAAe,CAAA,EAAG;QACpB,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,qBACEtF,eAAA,CAACjD,SAAAA,EAAAA;QAAUsD,IAAAA,EAAK,MAAA;QAAOoF,aAAAA,EAAY,aAAA;;YAChCL,OAAAA,CAAQG,MAAM,GAAG,CAAA,kBAChB/E,cAAA,CAAC5D,UAAAA,EAAAA;AACC,gBAAA,QAAA,gBAAA4D,cAAA,CAACzD,SAAAA,EAAAA;AACEqI,oBAAAA,QAAAA,EAAAA,OAAAA,CAAQM,GAAG,CAAC,CAAC/H,MAAAA,iBACZ6C,cAAA,CAAC9C,UAAAA,EAAAA;4BACCC,MAAAA,EAAQA,MAAAA;4BACRC,eAAAA,EAAiBA;AACZ,yBAAA,EAAA,CAAC,OAAO,EAAED,MAAAA,CAAO4B,EAAE,CAAA,CAAE,CAAA;;;AAMnC4F,YAAAA,MAAAA,CAAOO,GAAG,CAAC,CAAC/D,KAAAA,iBACXnB,cAAA,CAAC5E,iBAAAA,EAAAA;oBAAoB+J,SAAAA,EAAU,QAAA;oBAASpC,UAAAA,EAAW,SAAA;AACjD,oBAAA,QAAA,gBAAA/C,cAAA,CAACuD,SAAAA,EAAAA;wBACCpC,KAAAA,EAAOA,KAAAA;wBACP/D,eAAAA,EAAiBA,eAAAA;wBACjBoG,gBAAAA,EAAkBA;;AAJXrC,iBAAAA,EAAAA,KAAAA,CAAMpC,EAAE,CAAA;;;AAU3B;;;;"}
1
+ {"version":3,"file":"AssetsGrid.js","sources":["../../../../../admin/src/pages/Assets/components/AssetsGrid.tsx"],"sourcesContent":["import { Box, Card, CardBody, CardHeader, Checkbox, Flex } from '@strapi/design-system';\nimport { Folder as FolderIcon } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, css } from 'styled-components';\n\nimport { TruncatedText } from '../../../components/TruncatedText';\nimport { ASSET_TYPES } from '../../../enums';\nimport { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions';\nimport { prefixFileUrlWithBackendUrl } from '../../../utils/files';\nimport { getAssetIcon } from '../../../utils/getAssetIcon';\nimport { isEventFromWithin } from '../../../utils/isEventFromWithin';\nimport { getTranslationKey } from '../../../utils/translations';\nimport { ASSET_DETAILS_TRIGGER_PROPS, ASSET_ITEM_CONTROL_PROPS } from '../constants';\nimport { useAssetSelection } from '../hooks/useAssetSelection';\nimport { useBusyAssetsOptional } from '../hooks/useBusyAssets';\nimport { useFolderNavigation } from '../hooks/useFolderNavigation';\nimport { buildRenderedKeys } from '../utils/renderedKeys';\nimport { assetKey, folderKey, type ItemKey } from '../utils/selection';\n\nimport { AssetActionsMenu } from './AssetActionsMenu';\nimport { BusyOverlay } from './BusyOverlay';\nimport { useAssetsDndOptional } from './Dnd/AssetsDndProvider';\nimport { useFileDraggable, useFolderDraggableDroppable } from './Dnd/useAssetDnd';\nimport { FolderActionsMenu } from './FolderActionsMenu';\nimport { useItemContextMenuTrigger } from './ItemContextMenu';\n\nimport type { File } from '../../../../../shared/contracts/files';\nimport type { Folder } from '../../../../../shared/contracts/folders';\n\n/* -------------------------------------------------------------------------------------------------\n * AssetsGrid\n * -----------------------------------------------------------------------------------------------*/\n\n// Cards own click, Enter and Space; the controls sitting on them (checkbox, \"...\"\n// menu) must not let those reach the card. Scoped to the wrapper's own DOM\n// subtree so the menu's portaled content — a React child of the wrapper, but\n// never a DOM descendant — still reaches `document`, where Radix listens in\n// order to dismiss its layers.\nconst stopCardEvent = (e: React.SyntheticEvent) => {\n if (isEventFromWithin(e)) {\n e.stopPropagation();\n }\n};\n\n// Top-left selection checkbox overlaid on the asset preview, always visible.\nconst CheckboxOverlay = styled(Flex)`\n position: absolute;\n top: ${({ theme }) => theme.spaces[3]};\n left: ${({ theme }) => theme.spaces[3]};\n z-index: 1;\n box-shadow: ${({ theme }) => theme.shadows.filterShadow};\n`;\n\nconst StyledCard = styled(Card)<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isBusy?: boolean;\n $isSelected?: boolean;\n}>`\n border: 1px solid\n ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary600 : theme.colors.neutral200)};\n border-radius: 8px;\n overflow: hidden;\n isolation: isolate;\n cursor: ${({ $isMovePending, $isBusy }) => ($isMovePending || $isBusy ? 'wait' : 'pointer')};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n /* No opacity change while busy — the overlay does the dimming, and stacking\n one on the other would wash the card out. */\n pointer-events: ${({ $isMovePending, $isBusy }) => ($isMovePending || $isBusy ? 'none' : 'auto')};\n background: ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary100 : undefined)};\n /* Shift+click range selection must not highlight card text. */\n user-select: none;\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n }\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * FolderCard\n * -----------------------------------------------------------------------------------------------*/\n\nconst FoldersRow = styled(Box)`\n grid-column: 1 / -1;\n`;\n\nconst MIN_TILE_WIDTH = '240px';\n\nconst ItemsGrid = styled(Box)`\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(${MIN_TILE_WIDTH}, 100%), 1fr));\n gap: ${({ theme }) => theme.spaces[4]};\n`;\n\nconst StyledFolderCard = styled(Flex)<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isValidDropTarget?: boolean;\n $isInvalidDropTarget?: boolean;\n $isSelected?: boolean;\n}>`\n width: 100%;\n user-select: none;\n padding: ${({ theme }) => `${theme.spaces[2]} ${theme.spaces[3]}`}; // 8px 12px\n align-items: center;\n gap: ${({ theme }) => theme.spaces[2]}; // 8px\n border: 1px solid\n ${({ theme, $isSelected }) => ($isSelected ? theme.colors.primary600 : theme.colors.neutral200)};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme, $isSelected }) =>\n $isSelected ? theme.colors.primary100 : theme.colors.neutral0};\n cursor: ${({ $isMovePending, $isInvalidDropTarget }) => {\n if ($isMovePending) {\n return 'wait';\n }\n\n return $isInvalidDropTarget ? 'not-allowed' : 'pointer';\n }};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n pointer-events: ${({ $isMovePending }) => ($isMovePending ? 'none' : 'auto')};\n transition: background 0.2s;\n\n ${({ $isValidDropTarget, theme }) =>\n $isValidDropTarget &&\n css`\n background: ${theme.colors.primary100};\n border: 1px dashed ${theme.colors.primary600};\n `}\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n }\n`;\n\nconst FolderIconContainer = styled(Flex)`\n flex-shrink: 0;\n color: ${({ theme }) => theme.colors.neutral600};\n`;\n\nconst FolderName = styled(TruncatedText)`\n flex: 1;\n min-width: 0;\n`;\n\ninterface FolderCardProps {\n folder: Folder;\n orderedItemKeys: ItemKey[];\n}\n\nconst FolderCard = ({ folder, orderedItemKeys }: FolderCardProps) => {\n const { formatMessage } = useIntl();\n const { navigateToFolder } = useFolderNavigation();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { isSelected, toggle, selectRange } = useAssetSelection();\n const { canUpdate } = useMediaLibraryPermissions();\n const openContextMenu = useItemContextMenuTrigger();\n const {\n dragData,\n draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging },\n droppable: { setNodeRef: setDropRef },\n showValidDropHighlight,\n showInvalidDropCursor,\n } = useFolderDraggableDroppable(folder);\n\n const key = folderKey(folder.id);\n\n const setNodeRef = (node: HTMLElement | null) => {\n setDragRef(node);\n setDropRef(node);\n };\n\n // Folders share the selection mechanism with assets (toggle, range,\n // select-all). Only the plain-click semantic differs: it navigates into the\n // folder instead of selecting it.\n //\n // The containment guard on this and the handlers below is what keeps the\n // actions menu's portaled dialogs — React children of this card — from\n // navigating into the folder or starting a drag.\n const handleClick = (e: React.MouseEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else if (e.metaKey || e.ctrlKey) {\n toggle(key);\n } else {\n navigateToFolder(folder);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n navigateToFolder(folder);\n } else if (e.key === ' ') {\n e.preventDefault();\n toggle(key);\n }\n };\n\n // Checkbox is the pointer path to selection; Shift extends the range.\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else {\n toggle(key);\n }\n };\n\n return (\n <StyledFolderCard\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isValidDropTarget={showValidDropHighlight}\n $isInvalidDropTarget={showInvalidDropCursor}\n $isSelected={isSelected(key)}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onPointerDown={(e: React.PointerEvent) => {\n if (isEventFromWithin(e)) {\n listeners?.onPointerDown?.(e);\n }\n }}\n role=\"listitem\"\n tabIndex={0}\n // Right-click opens this folder's own actions, or the selection's when it\n // is part of one. Still marked as \"not the background gesture\" so\n // MainAreaContextMenu's create menu stays out of it.\n data-native-context-menu\n onContextMenu={(e: React.MouseEvent) => {\n if (isEventFromWithin(e)) {\n openContextMenu?.(e, key, { kind: 'folder', folder, dragData });\n }\n }}\n >\n {canUpdate && (\n <Flex onKeyDown={(e: React.KeyboardEvent) => e.stopPropagation()}>\n <Checkbox\n checked={isSelected(key)}\n onClick={handleCheckboxClick}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.table.row.select'),\n defaultMessage: 'Select {name}',\n },\n { name: folder.name }\n )}\n />\n </Flex>\n )}\n <FolderIconContainer>\n <FolderIcon width={20} height={20} />\n </FolderIconContainer>\n <FolderName textColor=\"neutral800\">{folder.name}</FolderName>\n <Flex onClick={stopCardEvent} onKeyDown={stopCardEvent} onPointerDown={stopCardEvent}>\n <FolderActionsMenu folder={folder} dragData={dragData} />\n </Flex>\n </StyledFolderCard>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetPreview\n * -----------------------------------------------------------------------------------------------*/\n\nconst PreviewContainer = styled(Box)`\n position: relative;\n width: 100%;\n padding-bottom: 62.5%;\n height: 0;\n overflow: hidden;\n background: repeating-conic-gradient(\n ${({ theme }) => theme.colors.neutral100} 0% 25%,\n transparent 0% 50%\n )\n 50% / 20px 20px;\n`;\n\nconst StyledImage = styled.img`\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n`;\n\nconst IconPreview = styled(Flex)`\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n color: ${({ theme }) => theme.colors.neutral500};\n background: ${({ theme }) => theme.colors.neutral100};\n`;\n\ninterface AssetPreviewProps {\n asset: File;\n}\n\nconst AssetPreview = ({ asset }: AssetPreviewProps) => {\n const { alternativeText, ext, formats, mime, url, updatedAt, isLocal, isUrlSigned } = asset;\n\n if (mime?.includes(ASSET_TYPES.Image)) {\n // Replace keeps the same hash/URL, so without a cache-buster the browser\n // serves the stale thumbnail after a Replace Media. `updatedAt`\n // changes on replace, so it re-fetches exactly once per replacement.\n // Skipped for signed URLs — an extra query param invalidates the signature.\n const cacheKey = updatedAt && !isUrlSigned ? new Date(updatedAt).getTime() : undefined;\n const appendCacheBuster = (raw: string) => {\n if (cacheKey === undefined) {\n return raw;\n }\n return raw.includes('?') ? `${raw}&v=${cacheKey}` : `${raw}?v=${cacheKey}`;\n };\n\n const rawMediaURL =\n prefixFileUrlWithBackendUrl(formats?.thumbnail?.url) ?? prefixFileUrlWithBackendUrl(url);\n const mediaURL = rawMediaURL ? appendCacheBuster(rawMediaURL) : rawMediaURL;\n\n if (mediaURL) {\n return (\n <PreviewContainer>\n <StyledImage\n src={mediaURL}\n alt={alternativeText || ''}\n // Only signed remote URLs need crossOrigin (cache collision with\n // the preview). Public/unsigned remote thumbnails must render\n // without a bucket CORS rule. See #26581.\n crossOrigin={!isLocal && isUrlSigned ? 'anonymous' : undefined}\n draggable={false}\n onDragStart={(e) => e.preventDefault()}\n />\n </PreviewContainer>\n );\n }\n }\n\n const DocIcon = getAssetIcon(mime, ext);\n\n return (\n <PreviewContainer>\n <IconPreview justifyContent=\"center\" alignItems=\"center\">\n <DocIcon width={48} height={48} />\n </IconPreview>\n </PreviewContainer>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetCard\n * -----------------------------------------------------------------------------------------------*/\n\nconst StyledCardHeader = styled(CardHeader)`\n position: relative;\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral200};\n`;\n\nconst CardFooter = styled(Flex)`\n min-width: 0;\n width: 100%;\n`;\n\nconst FileTypeIcon = styled(Flex)`\n color: ${({ theme }) => theme.colors.neutral600};\n flex-shrink: 0;\n`;\n\nconst FileName = styled(TruncatedText)`\n flex: 1;\n min-width: 0;\n`;\n\n// The asset filename is its own interactive element: clicking it opens the\n// details drawer instead of selecting the card (mirrors the table view).\nconst NameButton = styled.button`\n display: inline-flex;\n flex: 1;\n min-width: 0;\n border: none;\n background: transparent;\n padding: 0;\n margin: 0;\n cursor: pointer;\n text-align: left;\n color: inherit;\n font: inherit;\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n border-radius: 2px;\n }\n`;\n\ninterface AssetCardProps {\n asset: File;\n orderedItemKeys: ItemKey[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nconst AssetCard = ({ asset, orderedItemKeys, onAssetItemClick }: AssetCardProps) => {\n const { formatMessage } = useIntl();\n const TypeIcon = getAssetIcon(asset.mime, asset.ext);\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { attributes, listeners, setNodeRef, isDragging, dragData } = useFileDraggable(asset);\n const { isSelected, toggle, selectRange } = useAssetSelection();\n const { canUpdate } = useMediaLibraryPermissions();\n const busyMessage = useBusyAssetsOptional()?.getBusyMessage(asset.id) ?? null;\n const openContextMenu = useItemContextMenuTrigger();\n\n const key = assetKey(asset.id);\n const selected = isSelected(key);\n\n // Plain click opens the asset details; pointer selection lives on the\n // checkbox only. Modifier clicks keep the selection semantics: shift selects\n // a range, cmd/ctrl toggles.\n //\n // The containment guard on this and the handler below is what keeps the\n // actions menu's portaled dialogs — React children of this card — from\n // opening the details drawer or toggling the selection.\n const handleCardClick = (e: React.MouseEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else if (e.metaKey || e.ctrlKey) {\n toggle(key);\n } else {\n onAssetItemClick(asset.id);\n }\n };\n\n // Space toggles selection (additive), Enter opens the details drawer.\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isEventFromWithin(e)) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n onAssetItemClick(asset.id);\n } else if (e.key === ' ') {\n e.preventDefault();\n toggle(key);\n }\n };\n\n const handleNameClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onAssetItemClick(asset.id);\n };\n\n // Same semantics as the table's row checkbox: Shift extends the range,\n // otherwise a plain additive toggle. Never bubbles into the card click.\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (e.shiftKey) {\n selectRange(orderedItemKeys, key);\n } else {\n toggle(key);\n }\n };\n\n return (\n <StyledCard\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n {...ASSET_DETAILS_TRIGGER_PROPS}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isBusy={busyMessage !== null}\n $isSelected={selected}\n tabIndex={0}\n role=\"listitem\"\n // Right-click opens this asset's own actions, or the selection's when it\n // is part of one. Still marked as \"not the background gesture\" so\n // MainAreaContextMenu's create menu stays out of it.\n data-native-context-menu\n onContextMenu={(e: React.MouseEvent) => {\n if (isEventFromWithin(e)) {\n openContextMenu?.(e, key, { kind: 'asset', asset, dragData });\n }\n }}\n onDragStart={(e) => e.preventDefault()}\n onClick={handleCardClick}\n onKeyDown={handleKeyDown}\n onPointerDown={(e: React.PointerEvent) => {\n if (isEventFromWithin(e)) {\n listeners?.onPointerDown?.(e);\n }\n }}\n >\n <StyledCardHeader>\n {canUpdate && (\n <CheckboxOverlay\n {...ASSET_ITEM_CONTROL_PROPS}\n onKeyDown={(e: React.KeyboardEvent) => e.stopPropagation()}\n >\n <Checkbox\n checked={selected}\n onClick={handleCheckboxClick}\n aria-label={formatMessage(\n {\n id: getTranslationKey('list.table.row.select'),\n defaultMessage: 'Select {name}',\n },\n { name: asset.name }\n )}\n />\n </CheckboxOverlay>\n )}\n <AssetPreview asset={asset} />\n {/* The header is the card's only positioned ancestor, and it's the part\n worth covering — the footer keeps the name legible while the preview\n is mid-replace. Below the checkbox overlay (z-index 1) would hide\n the spinner, so it sits above it. */}\n {busyMessage !== null ? <BusyOverlay zIndex={2}>{busyMessage}</BusyOverlay> : null}\n </StyledCardHeader>\n <CardBody>\n <CardFooter alignItems=\"center\" gap={2}>\n <FileTypeIcon>\n <TypeIcon width={20} height={20} />\n </FileTypeIcon>\n <NameButton type=\"button\" onClick={handleNameClick}>\n <FileName textColor=\"primary800\">{asset.name}</FileName>\n </NameButton>\n <Flex\n {...ASSET_ITEM_CONTROL_PROPS}\n onClick={stopCardEvent}\n onKeyDown={stopCardEvent}\n onPointerDown={stopCardEvent}\n >\n <AssetActionsMenu asset={asset} dragData={dragData} />\n </Flex>\n </CardFooter>\n </CardBody>\n </StyledCard>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AssetsGrid\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetsGridProps {\n assets: File[];\n folders?: Folder[];\n /** Keys of the rendered items, in render order. Owned by the view. */\n renderedKeys?: ItemKey[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nexport const AssetsGrid = ({\n assets,\n folders = [],\n renderedKeys,\n onAssetItemClick,\n}: AssetsGridProps) => {\n const totalItems = folders.length + assets.length;\n\n // Render order: folders always on top in the grid (mixing is table-only) —\n // range selection follows it.\n const orderedItemKeys: ItemKey[] = renderedKeys ?? buildRenderedKeys({ folders, assets });\n\n // The empty state is owned by the page (`AssetsView` renders `EmptyState`) — an\n // empty grid renders nothing at all.\n if (totalItems === 0) {\n return null;\n }\n\n return (\n <ItemsGrid role=\"list\" data-testid=\"assets-grid\">\n {folders.length > 0 && (\n <FoldersRow>\n <ItemsGrid>\n {folders.map((folder) => (\n <FolderCard\n folder={folder}\n orderedItemKeys={orderedItemKeys}\n key={`folder-${folder.id}`}\n />\n ))}\n </ItemsGrid>\n </FoldersRow>\n )}\n {assets.map((asset) => (\n <Flex key={asset.id} direction=\"column\" alignItems=\"stretch\">\n <AssetCard\n asset={asset}\n orderedItemKeys={orderedItemKeys}\n onAssetItemClick={onAssetItemClick}\n />\n </Flex>\n ))}\n </ItemsGrid>\n );\n};\n"],"names":["stopCardEvent","e","isEventFromWithin","stopPropagation","CheckboxOverlay","styled","Flex","theme","spaces","shadows","filterShadow","StyledCard","Card","$isSelected","colors","primary600","neutral200","$isMovePending","$isBusy","$isDragging","primary100","undefined","FoldersRow","Box","MIN_TILE_WIDTH","ItemsGrid","StyledFolderCard","borderRadius","neutral0","$isInvalidDropTarget","$isValidDropTarget","css","FolderIconContainer","neutral600","FolderName","TruncatedText","FolderCard","folder","orderedItemKeys","formatMessage","useIntl","navigateToFolder","useFolderNavigation","isMovePending","useAssetsDndOptional","isSelected","toggle","selectRange","useAssetSelection","canUpdate","useMediaLibraryPermissions","openContextMenu","useItemContextMenuTrigger","dragData","draggable","attributes","listeners","setNodeRef","setDragRef","isDragging","droppable","setDropRef","showValidDropHighlight","showInvalidDropCursor","useFolderDraggableDroppable","key","folderKey","id","node","handleClick","shiftKey","metaKey","ctrlKey","handleKeyDown","preventDefault","handleCheckboxClick","_jsxs","ref","onClick","onKeyDown","onPointerDown","role","tabIndex","data-native-context-menu","onContextMenu","kind","_jsx","Checkbox","checked","aria-label","getTranslationKey","defaultMessage","name","FolderIcon","width","height","textColor","FolderActionsMenu","PreviewContainer","neutral100","StyledImage","img","IconPreview","neutral500","AssetPreview","asset","alternativeText","ext","formats","mime","url","updatedAt","isLocal","isUrlSigned","includes","ASSET_TYPES","Image","cacheKey","Date","getTime","appendCacheBuster","raw","rawMediaURL","prefixFileUrlWithBackendUrl","thumbnail","mediaURL","src","alt","crossOrigin","onDragStart","DocIcon","getAssetIcon","justifyContent","alignItems","StyledCardHeader","CardHeader","CardFooter","FileTypeIcon","FileName","NameButton","button","AssetCard","onAssetItemClick","TypeIcon","useFileDraggable","busyMessage","useBusyAssetsOptional","getBusyMessage","assetKey","selected","handleCardClick","handleNameClick","ASSET_DETAILS_TRIGGER_PROPS","ASSET_ITEM_CONTROL_PROPS","BusyOverlay","zIndex","CardBody","gap","type","AssetActionsMenu","AssetsGrid","assets","folders","renderedKeys","totalItems","length","buildRenderedKeys","data-testid","map","direction"],"mappings":"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"}
@@ -21,6 +21,7 @@ import { BusyOverlay } from './BusyOverlay.mjs';
21
21
  import { useAssetsDndOptional } from './Dnd/AssetsDndProvider.mjs';
22
22
  import { useFolderDraggableDroppable, useFileDraggable } from './Dnd/useAssetDnd.mjs';
23
23
  import { FolderActionsMenu } from './FolderActionsMenu.mjs';
24
+ import { useItemContextMenuTrigger } from './ItemContextMenu.mjs';
24
25
 
25
26
  /* -------------------------------------------------------------------------------------------------
26
27
  * AssetsGrid
@@ -127,6 +128,7 @@ const FolderCard = ({ folder, orderedItemKeys })=>{
127
128
  };
128
129
  const { isSelected, toggle, selectRange } = useAssetSelection();
129
130
  const { canUpdate } = useMediaLibraryPermissions();
131
+ const openContextMenu = useItemContextMenuTrigger();
130
132
  const { dragData, draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging }, droppable: { setNodeRef: setDropRef }, showValidDropHighlight, showInvalidDropCursor } = useFolderDraggableDroppable(folder);
131
133
  const key = folderKey(folder.id);
132
134
  const setNodeRef = (node)=>{
@@ -191,9 +193,19 @@ const FolderCard = ({ folder, orderedItemKeys })=>{
191
193
  },
192
194
  role: "listitem",
193
195
  tabIndex: 0,
194
- // Right-clicking an item is not the background gesture: the folder keeps
195
- // the browser's own menu. See MainAreaContextMenu.
196
+ // Right-click opens this folder's own actions, or the selection's when it
197
+ // is part of one. Still marked as "not the background gesture" so
198
+ // MainAreaContextMenu's create menu stays out of it.
196
199
  "data-native-context-menu": true,
200
+ onContextMenu: (e)=>{
201
+ if (isEventFromWithin(e)) {
202
+ openContextMenu?.(e, key, {
203
+ kind: 'folder',
204
+ folder,
205
+ dragData
206
+ });
207
+ }
208
+ },
197
209
  children: [
198
210
  canUpdate && /*#__PURE__*/ jsx(Flex, {
199
211
  onKeyDown: (e)=>e.stopPropagation(),
@@ -353,6 +365,7 @@ const AssetCard = ({ asset, orderedItemKeys, onAssetItemClick })=>{
353
365
  const { isSelected, toggle, selectRange } = useAssetSelection();
354
366
  const { canUpdate } = useMediaLibraryPermissions();
355
367
  const busyMessage = useBusyAssetsOptional()?.getBusyMessage(asset.id) ?? null;
368
+ const openContextMenu = useItemContextMenuTrigger();
356
369
  const key = assetKey(asset.id);
357
370
  const selected = isSelected(key);
358
371
  // Plain click opens the asset details; pointer selection lives on the
@@ -412,9 +425,19 @@ const AssetCard = ({ asset, orderedItemKeys, onAssetItemClick })=>{
412
425
  $isSelected: selected,
413
426
  tabIndex: 0,
414
427
  role: "listitem",
415
- // Right-clicking an item is not the background gesture: the card keeps
416
- // the browser's own menu. See MainAreaContextMenu.
428
+ // Right-click opens this asset's own actions, or the selection's when it
429
+ // is part of one. Still marked as "not the background gesture" so
430
+ // MainAreaContextMenu's create menu stays out of it.
417
431
  "data-native-context-menu": true,
432
+ onContextMenu: (e)=>{
433
+ if (isEventFromWithin(e)) {
434
+ openContextMenu?.(e, key, {
435
+ kind: 'asset',
436
+ asset,
437
+ dragData
438
+ });
439
+ }
440
+ },
418
441
  onDragStart: (e)=>e.preventDefault(),
419
442
  onClick: handleCardClick,
420
443
  onKeyDown: handleKeyDown,