@strapi/upload 5.51.1 → 5.51.2

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 (262) hide show
  1. package/dist/admin/components/AssetCard/VideoPreview.js +1 -1
  2. package/dist/admin/components/AssetCard/VideoPreview.js.map +1 -1
  3. package/dist/admin/components/AssetCard/VideoPreview.mjs +1 -1
  4. package/dist/admin/components/AssetCard/VideoPreview.mjs.map +1 -1
  5. package/dist/admin/components/TableList/TableList.js +1 -1
  6. package/dist/admin/components/TableList/TableList.js.map +1 -1
  7. package/dist/admin/components/TableList/TableList.mjs +1 -1
  8. package/dist/admin/components/TableList/TableList.mjs.map +1 -1
  9. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js +21 -4
  10. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
  11. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs +21 -4
  12. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs.map +1 -1
  13. package/dist/admin/future/components/Drawer.js +3 -1
  14. package/dist/admin/future/components/Drawer.js.map +1 -1
  15. package/dist/admin/future/components/Drawer.mjs +3 -1
  16. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  17. package/dist/admin/future/components/UploadProgressDialog.js +200 -27
  18. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
  19. package/dist/admin/future/components/UploadProgressDialog.mjs +203 -30
  20. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
  21. package/dist/admin/future/hooks/useMediaLibraryPermissions.js +35 -0
  22. package/dist/admin/future/hooks/useMediaLibraryPermissions.js.map +1 -0
  23. package/dist/admin/future/hooks/useMediaLibraryPermissions.mjs +33 -0
  24. package/dist/admin/future/hooks/useMediaLibraryPermissions.mjs.map +1 -0
  25. package/dist/admin/future/pages/Assets/AssetsPage.js +203 -78
  26. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/AssetsPage.mjs +200 -75
  28. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +75 -32
  30. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  31. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +75 -32
  32. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  33. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +46 -19
  34. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  35. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +47 -20
  36. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  37. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +5 -2
  38. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +5 -2
  40. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +100 -0
  42. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -0
  43. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +98 -0
  44. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -0
  45. package/dist/admin/future/pages/Assets/components/AssetsTable.js +10 -4
  46. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  47. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +10 -4
  48. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  49. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +140 -22
  50. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +142 -24
  52. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/components/DateRangeCalendar.js +193 -0
  54. package/dist/admin/future/pages/Assets/components/DateRangeCalendar.js.map +1 -0
  55. package/dist/admin/future/pages/Assets/components/DateRangeCalendar.mjs +191 -0
  56. package/dist/admin/future/pages/Assets/components/DateRangeCalendar.mjs.map +1 -0
  57. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +18 -1
  58. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
  59. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +18 -1
  60. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
  61. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js +13 -3
  62. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
  63. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +13 -3
  64. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
  65. package/dist/admin/future/pages/Assets/components/EmptyState.js +62 -3
  66. package/dist/admin/future/pages/Assets/components/EmptyState.js.map +1 -1
  67. package/dist/admin/future/pages/Assets/components/EmptyState.mjs +62 -4
  68. package/dist/admin/future/pages/Assets/components/EmptyState.mjs.map +1 -1
  69. package/dist/admin/future/pages/Assets/components/FilterBadges.js +408 -0
  70. package/dist/admin/future/pages/Assets/components/FilterBadges.js.map +1 -0
  71. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs +406 -0
  72. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs.map +1 -0
  73. package/dist/admin/future/pages/Assets/components/FilterMenu.js +273 -0
  74. package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -0
  75. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +267 -0
  76. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -0
  77. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +76 -19
  78. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  79. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +78 -21
  80. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  81. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js +33 -0
  82. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js.map +1 -0
  83. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs +31 -0
  84. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs.map +1 -0
  85. package/dist/admin/future/pages/Assets/components/SortMenu.js +21 -32
  86. package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
  87. package/dist/admin/future/pages/Assets/components/SortMenu.mjs +22 -33
  88. package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
  89. package/dist/admin/future/pages/Assets/hooks/useAssetSearch.js +40 -0
  90. package/dist/admin/future/pages/Assets/hooks/useAssetSearch.js.map +1 -0
  91. package/dist/admin/future/pages/Assets/hooks/useAssetSearch.mjs +38 -0
  92. package/dist/admin/future/pages/Assets/hooks/useAssetSearch.mjs.map +1 -0
  93. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +21 -5
  94. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  95. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +21 -5
  96. package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  97. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js +33 -12
  98. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  99. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs +33 -12
  100. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  101. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +40 -4
  102. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
  103. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +40 -4
  104. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
  105. package/dist/admin/future/pages/Assets/hooks/useListFilters.js +168 -0
  106. package/dist/admin/future/pages/Assets/hooks/useListFilters.js.map +1 -0
  107. package/dist/admin/future/pages/Assets/hooks/useListFilters.mjs +162 -0
  108. package/dist/admin/future/pages/Assets/hooks/useListFilters.mjs.map +1 -0
  109. package/dist/admin/future/pages/Assets/utils/buildAssetFilters.js +201 -0
  110. package/dist/admin/future/pages/Assets/utils/buildAssetFilters.js.map +1 -0
  111. package/dist/admin/future/pages/Assets/utils/buildAssetFilters.mjs +198 -0
  112. package/dist/admin/future/pages/Assets/utils/buildAssetFilters.mjs.map +1 -0
  113. package/dist/admin/future/pages/Assets/utils/listQueryKey.js +2 -2
  114. package/dist/admin/future/pages/Assets/utils/listQueryKey.js.map +1 -1
  115. package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs +2 -2
  116. package/dist/admin/future/pages/Assets/utils/listQueryKey.mjs.map +1 -1
  117. package/dist/admin/future/services/api.js +163 -28
  118. package/dist/admin/future/services/api.js.map +1 -1
  119. package/dist/admin/future/services/api.mjs +163 -30
  120. package/dist/admin/future/services/api.mjs.map +1 -1
  121. package/dist/admin/future/services/assets.js +29 -17
  122. package/dist/admin/future/services/assets.js.map +1 -1
  123. package/dist/admin/future/services/assets.mjs +29 -17
  124. package/dist/admin/future/services/assets.mjs.map +1 -1
  125. package/dist/admin/future/services/folders.js +29 -17
  126. package/dist/admin/future/services/folders.js.map +1 -1
  127. package/dist/admin/future/services/folders.mjs +29 -17
  128. package/dist/admin/future/services/folders.mjs.map +1 -1
  129. package/dist/admin/future/services/settings.js +10 -3
  130. package/dist/admin/future/services/settings.js.map +1 -1
  131. package/dist/admin/future/services/settings.mjs +10 -3
  132. package/dist/admin/future/services/settings.mjs.map +1 -1
  133. package/dist/admin/future/store/uploadProgress.js +109 -2
  134. package/dist/admin/future/store/uploadProgress.js.map +1 -1
  135. package/dist/admin/future/store/uploadProgress.mjs +105 -3
  136. package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
  137. package/dist/admin/future/utils/searchQueryParam.js +11 -0
  138. package/dist/admin/future/utils/searchQueryParam.js.map +1 -0
  139. package/dist/admin/future/utils/searchQueryParam.mjs +9 -0
  140. package/dist/admin/future/utils/searchQueryParam.mjs.map +1 -0
  141. package/dist/admin/hooks/useSelectionState.js +2 -4
  142. package/dist/admin/hooks/useSelectionState.js.map +1 -1
  143. package/dist/admin/hooks/useSelectionState.mjs +2 -4
  144. package/dist/admin/hooks/useSelectionState.mjs.map +1 -1
  145. package/dist/admin/shared/constants.js +43 -0
  146. package/dist/admin/shared/constants.js.map +1 -0
  147. package/dist/admin/shared/constants.mjs +38 -0
  148. package/dist/admin/shared/constants.mjs.map +1 -0
  149. package/dist/admin/src/future/hooks/useMediaLibraryPermissions.d.ts +21 -0
  150. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetCropEditor.d.ts +7 -1
  151. package/dist/admin/src/future/pages/Assets/components/AssetsSearchInput.d.ts +5 -0
  152. package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +14 -1
  153. package/dist/admin/src/future/pages/Assets/components/DateRangeCalendar.d.ts +8 -0
  154. package/dist/admin/src/future/pages/Assets/components/DropZone/UploadDropZoneContext.d.ts +8 -1
  155. package/dist/admin/src/future/pages/Assets/components/EmptyState.d.ts +18 -1
  156. package/dist/admin/src/future/pages/Assets/components/FilterBadges.d.ts +6 -0
  157. package/dist/admin/src/future/pages/Assets/components/FilterMenu.d.ts +22 -0
  158. package/dist/admin/src/future/pages/Assets/components/FolderTree/FolderTree.d.ts +13 -4
  159. package/dist/admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.d.ts +16 -0
  160. package/dist/admin/src/future/pages/Assets/components/SortMenu.d.ts +6 -0
  161. package/dist/admin/src/future/pages/Assets/hooks/useAssetSearch.d.ts +12 -0
  162. package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +8 -1
  163. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +13 -3
  164. package/dist/admin/src/future/pages/Assets/hooks/useListFilters.d.ts +69 -0
  165. package/dist/admin/src/future/pages/Assets/utils/buildAssetFilters.d.ts +46 -0
  166. package/dist/admin/src/future/pages/Assets/utils/listQueryKey.d.ts +3 -4
  167. package/dist/admin/src/future/services/api.d.ts +53 -5
  168. package/dist/admin/src/future/services/assets.d.ts +9 -1
  169. package/dist/admin/src/future/services/folders.d.ts +3 -0
  170. package/dist/admin/src/future/services/settings.d.ts +2 -2
  171. package/dist/admin/src/future/store/uploadProgress.d.ts +83 -1
  172. package/dist/admin/src/future/utils/searchQueryParam.d.ts +7 -0
  173. package/dist/admin/src/hooks/useAiAvailability.d.ts +1 -1
  174. package/dist/admin/src/hooks/useEditAsset.d.ts +4 -4
  175. package/dist/admin/src/hooks/useEditFolder.d.ts +4 -4
  176. package/dist/admin/src/hooks/useSettings.d.ts +1 -0
  177. package/dist/admin/src/hooks/useTracking.d.ts +1 -1
  178. package/dist/admin/src/hooks/useUpload.d.ts +1 -1
  179. package/dist/admin/translations/en.json.js +53 -3
  180. package/dist/admin/translations/en.json.js.map +1 -1
  181. package/dist/admin/translations/en.json.mjs +53 -3
  182. package/dist/admin/translations/en.json.mjs.map +1 -1
  183. package/dist/admin/utils/urlYupSchema.js +33 -9
  184. package/dist/admin/utils/urlYupSchema.js.map +1 -1
  185. package/dist/admin/utils/urlYupSchema.mjs +33 -9
  186. package/dist/admin/utils/urlYupSchema.mjs.map +1 -1
  187. package/dist/server/config.js +13 -5
  188. package/dist/server/config.js.map +1 -1
  189. package/dist/server/config.mjs +13 -5
  190. package/dist/server/config.mjs.map +1 -1
  191. package/dist/server/constants.js.map +1 -1
  192. package/dist/server/constants.mjs.map +1 -1
  193. package/dist/server/controllers/admin-file.js +30 -0
  194. package/dist/server/controllers/admin-file.js.map +1 -1
  195. package/dist/server/controllers/admin-file.mjs +30 -0
  196. package/dist/server/controllers/admin-file.mjs.map +1 -1
  197. package/dist/server/controllers/admin-settings.js +20 -2
  198. package/dist/server/controllers/admin-settings.js.map +1 -1
  199. package/dist/server/controllers/admin-settings.mjs +21 -3
  200. package/dist/server/controllers/admin-settings.mjs.map +1 -1
  201. package/dist/server/controllers/content-api.js +1 -2
  202. package/dist/server/controllers/content-api.js.map +1 -1
  203. package/dist/server/controllers/content-api.mjs +2 -2
  204. package/dist/server/controllers/content-api.mjs.map +1 -1
  205. package/dist/server/controllers/validation/admin/ai-metadata.js +12 -0
  206. package/dist/server/controllers/validation/admin/ai-metadata.js.map +1 -0
  207. package/dist/server/controllers/validation/admin/ai-metadata.mjs +10 -0
  208. package/dist/server/controllers/validation/admin/ai-metadata.mjs.map +1 -0
  209. package/dist/server/controllers/validation/admin/settings.js +4 -1
  210. package/dist/server/controllers/validation/admin/settings.js.map +1 -1
  211. package/dist/server/controllers/validation/admin/settings.mjs +1 -1
  212. package/dist/server/controllers/validation/admin/settings.mjs.map +1 -1
  213. package/dist/server/routes/admin.js +18 -0
  214. package/dist/server/routes/admin.js.map +1 -1
  215. package/dist/server/routes/admin.mjs +18 -0
  216. package/dist/server/routes/admin.mjs.map +1 -1
  217. package/dist/server/services/ai-metadata.js +108 -11
  218. package/dist/server/services/ai-metadata.js.map +1 -1
  219. package/dist/server/services/ai-metadata.mjs +108 -11
  220. package/dist/server/services/ai-metadata.mjs.map +1 -1
  221. package/dist/server/services/file.js +86 -13
  222. package/dist/server/services/file.js.map +1 -1
  223. package/dist/server/services/file.mjs +87 -14
  224. package/dist/server/services/file.mjs.map +1 -1
  225. package/dist/server/services/image-manipulation.js +4 -4
  226. package/dist/server/services/image-manipulation.js.map +1 -1
  227. package/dist/server/services/image-manipulation.mjs +4 -4
  228. package/dist/server/services/image-manipulation.mjs.map +1 -1
  229. package/dist/server/shared/constants.js +43 -0
  230. package/dist/server/shared/constants.js.map +1 -0
  231. package/dist/server/shared/constants.mjs +38 -0
  232. package/dist/server/shared/constants.mjs.map +1 -0
  233. package/dist/server/src/config.d.ts +2 -0
  234. package/dist/server/src/config.d.ts.map +1 -1
  235. package/dist/server/src/constants.d.ts +2 -1
  236. package/dist/server/src/constants.d.ts.map +1 -1
  237. package/dist/server/src/controllers/admin-file.d.ts +10 -0
  238. package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
  239. package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
  240. package/dist/server/src/controllers/index.d.ts +1 -0
  241. package/dist/server/src/controllers/index.d.ts.map +1 -1
  242. package/dist/server/src/controllers/validation/admin/ai-metadata.d.ts +2 -0
  243. package/dist/server/src/controllers/validation/admin/ai-metadata.d.ts.map +1 -0
  244. package/dist/server/src/controllers/validation/admin/settings.d.ts +1 -1
  245. package/dist/server/src/controllers/validation/admin/settings.d.ts.map +1 -1
  246. package/dist/server/src/index.d.ts +7 -1
  247. package/dist/server/src/index.d.ts.map +1 -1
  248. package/dist/server/src/routes/admin.d.ts.map +1 -1
  249. package/dist/server/src/services/ai-metadata.d.ts +19 -0
  250. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  251. package/dist/server/src/services/file.d.ts +12 -2
  252. package/dist/server/src/services/file.d.ts.map +1 -1
  253. package/dist/server/src/services/index.d.ts +4 -1
  254. package/dist/server/src/services/index.d.ts.map +1 -1
  255. package/dist/server/src/types.d.ts +3 -0
  256. package/dist/server/src/types.d.ts.map +1 -1
  257. package/dist/shared/constants.d.ts +35 -0
  258. package/dist/shared/constants.d.ts.map +1 -0
  259. package/dist/shared/contracts/files.d.ts +25 -0
  260. package/dist/shared/contracts/files.d.ts.map +1 -1
  261. package/dist/shared/contracts/settings.d.ts +7 -0
  262. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"AssetCropEditor.js","sources":["../../../../../../../admin/src/future/pages/Assets/components/AssetDetails/AssetCropEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport {\n Box,\n Button,\n Field,\n Flex,\n FocusTrap,\n IconButton,\n NumberInput,\n Portal,\n Typography,\n} from '@strapi/design-system';\nimport { ArrowsHorizontal, ArrowsVertical, Crop, Link } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, useTheme } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../utils/files';\nimport { getTranslationKey } from '../../../../utils/translations';\n\nimport { resolveCornerResize, useCropImg } from './useCropImg';\n\nimport type {\n AssetWithPopulatedCreatedBy,\n FocalPoint,\n} from '../../../../../../../shared/contracts/files';\n\nconst FOCAL_DIAMETER_REM = 5.6;\nconst HANDLE_PX = 12;\n\n/* -------------------------------------------------------------------------------------------------\n * Styled\n * -----------------------------------------------------------------------------------------------*/\n\n// Full-viewport takeover with a small inset so the editor reads as a card.\nconst Overlay = styled(Flex)`\n position: fixed;\n z-index: 1200;\n flex-direction: column;\n top: ${({ theme }) => theme.spaces[1]};\n left: ${({ theme }) => theme.spaces[1]};\n right: ${({ theme }) => theme.spaces[1]};\n bottom: ${({ theme }) => theme.spaces[1]};\n border-radius: ${({ theme }) => theme.borderRadius};\n border: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n`;\n\nconst HeaderBar = styled(Flex)`\n width: 100%;\n gap: ${({ theme }) => theme.spaces[2]};\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[5]}`};\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n`;\n\n// Fills the remaining space between header/footer; checkerboard pattern.\nconst Body = styled(Box)`\n width: 100%;\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n background: repeating-conic-gradient(\n ${({ theme }) => theme.colors.neutral100} 0% 25%,\n ${({ theme }) => theme.colors.neutral0} 0% 50%\n )\n 50% / 20px 20px;\n`;\n\n// Wrapper sized to the image's natural aspect ratio so the <img> inside fills\n// it without letterboxing. Percentage-based positioning of the crop overlay\n// then maps directly to natural-px coordinates.\nconst CropArea = styled.div<{ $aspect?: number }>`\n position: relative;\n max-width: 100%;\n max-height: 100%;\n ${({ $aspect }) => ($aspect ? `aspect-ratio: ${$aspect};` : '')}\n\n img {\n display: block;\n width: 100%;\n height: 100%;\n user-select: none;\n -webkit-user-drag: none;\n }\n`;\n\n// Crop selection rectangle, positioned by % of CropArea. Inverts the dim\n// outside via box-shadow so the focused area shows full color.\nconst CropOverlay = styled.div`\n position: absolute;\n border: 1px dashed ${({ theme }) => theme.colors.primary600};\n box-shadow: 0 0 0 9999px rgba(33, 33, 52, 0.5);\n cursor: move;\n`;\n\nconst ResizeHandle = styled.button<{ $cursor: string }>`\n position: absolute;\n width: ${HANDLE_PX}px;\n height: ${HANDLE_PX}px;\n margin: -${HANDLE_PX / 2}px;\n padding: 0;\n border: 1px solid ${({ theme }) => theme.colors.primary600};\n border-radius: 2px;\n background: ${({ theme }) => theme.colors.neutral0};\n cursor: ${({ $cursor }) => $cursor};\n`;\n\nconst FocalPointHandle = styled.button`\n position: absolute;\n width: ${FOCAL_DIAMETER_REM}rem;\n height: ${FOCAL_DIAMETER_REM}rem;\n margin: ${-FOCAL_DIAMETER_REM / 2}rem 0 0 ${-FOCAL_DIAMETER_REM / 2}rem;\n border-radius: 50%;\n border: 1px solid ${({ theme }) => theme.colors.neutral800};\n background: transparent;\n cursor: grab;\n padding: 0;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.16);\n transform: translate(-50%, -50%);\n }\n &::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: ${({ theme }) => theme.colors.neutral800};\n transform: translate(-50%, -50%);\n }\n\n &:active {\n cursor: grabbing;\n }\n`;\n\nconst InfoBox = styled(Box)`\n position: absolute;\n right: ${({ theme }) => theme.spaces[1]};\n bottom: ${({ theme }) => theme.spaces[1]};\n width: 100%;\n max-width: 32rem;\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) =>\n theme.colorScheme === 'dark' ? theme.colors.neutral150 : theme.colors.neutral900};\n z-index: 20;\n`;\n\nconst FooterBar = styled(Flex)`\n width: 100%;\n justify-content: space-between;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[5]}`};\n border-top: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n`;\n\nconst FieldRow = styled(Field.Root)`\n flex-direction: row;\n align-items: center;\n`;\n\nconst FieldNumberInput = styled(NumberInput)`\n width: 8.4rem;\n`;\n\nconst LabelIcon = styled(Field.Label)`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.6rem;\n height: 1.6rem;\n`;\n\nconst BackgroundPreserveRatioContainer = styled(Box)`\n position: absolute;\n top: 50%;\n left: 0;\n transform: translateY(-50%);\n\n svg {\n display: block;\n }\n`;\n\nconst BackgroundPreserveRatio = () => (\n <BackgroundPreserveRatioContainer>\n <svg width=\"17\" height=\"49\" viewBox=\"0 0 17 49\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M0.5 0.5H8.5C12.9183 0.5 16.5 4.08172 16.5 8.5M0.5 48.5H8.5C12.9183 48.5 16.5 44.9183 16.5 40.5\"\n stroke=\"#666687\"\n strokeLinecap=\"round\"\n />\n </svg>\n </BackgroundPreserveRatioContainer>\n);\n\n/* -------------------------------------------------------------------------------------------------\n * AssetCropEditor\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetCropEditorProps {\n asset: AssetWithPopulatedCreatedBy;\n isBusy?: boolean;\n onClose: () => void;\n onApply: (file: globalThis.File, focalPoint: FocalPoint) => void;\n onSaveAsCopy: (file: globalThis.File, focalPoint: FocalPoint) => void;\n}\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br';\n\nexport const AssetCropEditor = ({\n asset,\n isBusy = false,\n onClose,\n onApply,\n onSaveAsCopy,\n}: AssetCropEditorProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n // The InfoBox is a fixed dark surface in both themes, so its text can't use a\n // single neutral token (those invert with the scheme). Pick the scheme's white\n // and a muted grey explicitly.\n const theme = useTheme();\n const isDark = theme.colorScheme === 'dark';\n const infoTextColor = isDark ? 'neutral1000' : 'neutral0';\n const infoMutedColor = isDark ? 'neutral600' : 'neutral200';\n const imgRef = React.useRef<HTMLImageElement>(null);\n const cropAreaRef = React.useRef<HTMLDivElement>(null);\n\n const {\n init,\n crop,\n naturalSize,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n width,\n height,\n } = useCropImg();\n\n const [aspectLocked, setAspectLocked] = React.useState(false);\n // Focal point as a percentage of the crop area (matches the {x,y} contract).\n const [focal, setFocal] = React.useState<FocalPoint>(asset.focalPoint ?? { x: 50, y: 50 });\n\n // Append `updatedAt` as a cache-buster: a replaced asset is served at the same\n // URL, so without this, reopening the editor shows the browser-cached old image\n // (mirrors AssetPreview).\n const rawImageUrl = prefixFileUrlWithBackendUrl(asset.url) as string;\n const cacheKey = asset.updatedAt ? new Date(asset.updatedAt).getTime() : undefined;\n const imageUrl =\n cacheKey !== undefined\n ? `${rawImageUrl}${rawImageUrl.includes('?') ? '&' : '?'}v=${cacheKey}`\n : rawImageUrl;\n\n const handleImageLoad = () => {\n if (imgRef.current) {\n init(imgRef.current);\n }\n };\n\n // Map a pointer event to natural-px coordinates inside the image.\n const pointerToNatural = (event: PointerEvent | React.PointerEvent) => {\n const rect = cropAreaRef.current?.getBoundingClientRect();\n if (!rect || !naturalSize.width || !naturalSize.height) return null;\n const ratioX = naturalSize.width / rect.width;\n const ratioY = naturalSize.height / rect.height;\n return {\n x: (event.clientX - rect.left) * ratioX,\n y: (event.clientY - rect.top) * ratioY,\n };\n };\n\n // Drag the entire crop rectangle.\n const handleMovePointerDown = (event: React.PointerEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const start = pointerToNatural(event);\n if (!start) return;\n const startCrop = { ...crop };\n const move = (e: PointerEvent) => {\n const next = pointerToNatural(e);\n if (!next) return;\n setCropPosition({\n x: startCrop.x + (next.x - start.x),\n y: startCrop.y + (next.y - start.y),\n });\n };\n const up = () => {\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n };\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n };\n\n // Resize from a corner; the opposite corner stays anchored.\n const handleResizePointerDown = (corner: Corner) => (event: React.PointerEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const startCrop = { ...crop };\n const anchorX =\n corner === 'tl' || corner === 'bl' ? startCrop.x + startCrop.width : startCrop.x;\n const anchorY =\n corner === 'tl' || corner === 'tr' ? startCrop.y + startCrop.height : startCrop.y;\n const move = (e: PointerEvent) => {\n const point = pointerToNatural(e);\n if (!point) return;\n const {\n x,\n y,\n width: w,\n height: h,\n } = resolveCornerResize({\n anchorX,\n anchorY,\n point,\n aspectRatio: aspectLocked ? aspectRatio : null,\n });\n setCropPosition({ x, y });\n setCropSize({ width: w, height: h });\n };\n const up = () => {\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n };\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n };\n\n const toggleAspectLock = () => {\n setAspectLocked((locked) => {\n const next = !locked;\n setAspectRatio(next && height ? width / height : null);\n return next;\n });\n };\n\n // Drag the focal handle within the crop rectangle, clamped 0–100.\n const handleFocalPointerDown = (event: React.PointerEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const move = (e: PointerEvent) => {\n const point = pointerToNatural(e);\n if (!point) return;\n // Convert pointer to a percentage of the current crop area.\n const px = ((point.x - crop.x) / crop.width) * 100;\n const py = ((point.y - crop.y) / crop.height) * 100;\n setFocal({\n x: Math.round(Math.min(100, Math.max(0, px))),\n y: Math.round(Math.min(100, Math.max(0, py))),\n });\n };\n const up = () => {\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n };\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n };\n\n const focalPxX = Math.round((focal.x / 100) * width);\n const focalPxY = Math.round((focal.y / 100) * height);\n\n const setFocalPx = (axis: 'x' | 'y', value: number) => {\n const dim = axis === 'x' ? width : height;\n if (!dim) return;\n const pct = Math.min(100, Math.max(0, (value / dim) * 100));\n setFocal((prev) => ({ ...prev, [axis]: Math.round(pct) }));\n };\n\n const cropPercents =\n naturalSize.width && naturalSize.height\n ? {\n left: (crop.x / naturalSize.width) * 100,\n top: (crop.y / naturalSize.height) * 100,\n width: (crop.width / naturalSize.width) * 100,\n height: (crop.height / naturalSize.height) * 100,\n }\n : null;\n\n // The crop is only usable once the image has loaded and `init()` has seeded\n // the natural size. Until then the produce/export path would reject.\n const isReady = cropPercents !== null;\n\n const handleAction = async (action: 'apply' | 'copy') => {\n if (!isReady) return;\n\n let file: globalThis.File;\n try {\n file = await produceFile(asset.name, asset.mime ?? 'image/png', asset.updatedAt);\n } catch {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: getTranslationKey('asset-details.crop.export-error'),\n defaultMessage: 'Could not process the cropped image.',\n }),\n });\n return;\n }\n\n const roundedFocal = { x: Math.round(focal.x), y: Math.round(focal.y) };\n if (action === 'apply') {\n onApply(file, roundedFocal);\n } else {\n onSaveAsCopy(file, roundedFocal);\n }\n };\n\n return (\n <Portal>\n <FocusTrap onEscape={onClose}>\n <Overlay>\n <HeaderBar alignItems=\"center\">\n <Crop aria-hidden />\n <Typography variant=\"omega\" fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('asset-details.crop.title'),\n defaultMessage: 'Crop & Focus area',\n })}\n </Typography>\n </HeaderBar>\n\n <Body>\n <CropArea\n ref={cropAreaRef}\n $aspect={\n naturalSize.width && naturalSize.height\n ? naturalSize.width / naturalSize.height\n : undefined\n }\n >\n <img\n ref={imgRef}\n src={imageUrl}\n alt={asset.name}\n crossOrigin=\"anonymous\"\n onLoad={handleImageLoad}\n draggable={false}\n />\n\n {cropPercents ? (\n <CropOverlay\n style={{\n left: `${cropPercents.left}%`,\n top: `${cropPercents.top}%`,\n width: `${cropPercents.width}%`,\n height: `${cropPercents.height}%`,\n }}\n onPointerDown={handleMovePointerDown}\n >\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.top-left'),\n defaultMessage: 'Resize top-left',\n })}\n $cursor=\"nwse-resize\"\n style={{ left: 0, top: 0 }}\n onPointerDown={handleResizePointerDown('tl')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.top-right'),\n defaultMessage: 'Resize top-right',\n })}\n $cursor=\"nesw-resize\"\n style={{ right: 0, top: 0 }}\n onPointerDown={handleResizePointerDown('tr')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.bottom-left'),\n defaultMessage: 'Resize bottom-left',\n })}\n $cursor=\"nesw-resize\"\n style={{ left: 0, bottom: 0 }}\n onPointerDown={handleResizePointerDown('bl')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.bottom-right'),\n defaultMessage: 'Resize bottom-right',\n })}\n $cursor=\"nwse-resize\"\n style={{ right: 0, bottom: 0 }}\n onPointerDown={handleResizePointerDown('br')}\n />\n\n <FocalPointHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-point'),\n defaultMessage: 'Focal point',\n })}\n style={{ left: `${focal.x}%`, top: `${focal.y}%` }}\n onPointerDown={handleFocalPointerDown}\n />\n </CropOverlay>\n ) : null}\n </CropArea>\n\n <InfoBox>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={1} paddingBottom={3}>\n <Typography variant=\"omega\" fontWeight=\"bold\" textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.title'),\n defaultMessage: 'Crop & Focus area',\n })}\n </Typography>\n <Typography variant=\"pi\" textColor={infoMutedColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.hint'),\n defaultMessage:\n 'Set the crop area with the rectangle. Pin the always-visible area with the circle.',\n })}\n </Typography>\n </Flex>\n\n <Flex gap={6} alignItems=\"center\">\n <Flex alignItems=\"center\" gap={2}>\n <Flex direction=\"column\" gap={2}>\n <FieldRow name=\"crop-width\" gap={2}>\n <LabelIcon textColor={infoTextColor}>\n <ArrowsHorizontal />\n </LabelIcon>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.width'),\n defaultMessage: 'Width (px)',\n })}\n value={width}\n min={1}\n max={naturalSize.width || undefined}\n onValueChange={(next) => {\n if (next !== undefined) setCropSize({ width: next });\n }}\n />\n </FieldRow>\n <FieldRow name=\"crop-height\" gap={2}>\n <LabelIcon textColor={infoTextColor}>\n <ArrowsVertical />\n </LabelIcon>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.height'),\n defaultMessage: 'Height (px)',\n })}\n value={height}\n min={1}\n max={naturalSize.height || undefined}\n onValueChange={(next) => {\n if (next !== undefined) setCropSize({ height: next });\n }}\n />\n </FieldRow>\n </Flex>\n\n <Flex position=\"relative\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('asset-details.crop.aspect-lock'),\n defaultMessage: 'Lock aspect ratio',\n })}\n variant={aspectLocked ? 'secondary' : 'ghost'}\n onClick={toggleAspectLock}\n >\n <Link />\n </IconButton>\n <BackgroundPreserveRatio />\n </Flex>\n </Flex>\n\n <Flex direction=\"column\" gap={2} marginLeft={'auto'}>\n <FieldRow name=\"focal-x\" gap={2}>\n <Field.Label textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.focal-x-axis'),\n defaultMessage: 'X',\n })}\n </Field.Label>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-x'),\n defaultMessage: 'Focal point X (px)',\n })}\n value={focalPxX}\n onValueChange={(next) => {\n if (next !== undefined) setFocalPx('x', next);\n }}\n />\n </FieldRow>\n <FieldRow name=\"focal-y\" gap={2}>\n <Field.Label textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.focal-y-axis'),\n defaultMessage: 'Y',\n })}\n </Field.Label>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-y'),\n defaultMessage: 'Focal point Y (px)',\n })}\n value={focalPxY}\n onValueChange={(next) => {\n if (next !== undefined) setFocalPx('y', next);\n }}\n />\n </FieldRow>\n </Flex>\n </Flex>\n </InfoBox>\n </Body>\n\n <FooterBar alignItems=\"center\">\n <Button variant=\"tertiary\" onClick={onClose} disabled={isBusy}>\n {formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}\n </Button>\n <Flex gap={2}>\n <Button\n variant=\"secondary\"\n onClick={() => handleAction('copy')}\n loading={isBusy}\n disabled={!isReady}\n >\n {formatMessage({\n id: getTranslationKey('asset-details.crop.save-as-copy'),\n defaultMessage: 'Save as copy',\n })}\n </Button>\n <Button\n variant=\"default\"\n onClick={() => handleAction('apply')}\n loading={isBusy}\n disabled={!isReady}\n >\n {formatMessage({\n id: getTranslationKey('asset-details.crop.apply'),\n defaultMessage: 'Apply',\n })}\n </Button>\n </Flex>\n </FooterBar>\n </Overlay>\n </FocusTrap>\n </Portal>\n );\n};\n"],"names":["FOCAL_DIAMETER_REM","HANDLE_PX","Overlay","styled","Flex","theme","spaces","borderRadius","colors","neutral150","neutral0","HeaderBar","Body","Box","neutral100","CropArea","div","$aspect","CropOverlay","primary600","ResizeHandle","button","$cursor","FocalPointHandle","neutral800","InfoBox","colorScheme","neutral900","FooterBar","FieldRow","Field","Root","FieldNumberInput","NumberInput","LabelIcon","Label","BackgroundPreserveRatioContainer","BackgroundPreserveRatio","_jsx","svg","width","height","viewBox","fill","xmlns","path","d","stroke","strokeLinecap","AssetCropEditor","asset","isBusy","onClose","onApply","onSaveAsCopy","formatMessage","useIntl","toggleNotification","useNotification","useTheme","isDark","infoTextColor","infoMutedColor","imgRef","React","useRef","cropAreaRef","init","crop","naturalSize","aspectRatio","setCropSize","setCropPosition","setAspectRatio","produceFile","useCropImg","aspectLocked","setAspectLocked","useState","focal","setFocal","focalPoint","x","y","rawImageUrl","prefixFileUrlWithBackendUrl","url","cacheKey","updatedAt","Date","getTime","undefined","imageUrl","includes","handleImageLoad","current","pointerToNatural","event","rect","getBoundingClientRect","ratioX","ratioY","clientX","left","clientY","top","handleMovePointerDown","preventDefault","stopPropagation","start","startCrop","move","e","next","up","window","removeEventListener","addEventListener","handleResizePointerDown","corner","anchorX","anchorY","point","w","h","resolveCornerResize","toggleAspectLock","locked","handleFocalPointerDown","px","py","Math","round","min","max","focalPxX","focalPxY","setFocalPx","axis","value","dim","pct","prev","cropPercents","isReady","handleAction","action","file","name","mime","type","message","id","getTranslationKey","defaultMessage","roundedFocal","Portal","FocusTrap","onEscape","_jsxs","alignItems","Crop","aria-hidden","Typography","variant","fontWeight","ref","img","src","alt","crossOrigin","onLoad","draggable","style","onPointerDown","aria-label","right","bottom","direction","gap","paddingBottom","textColor","ArrowsHorizontal","onValueChange","ArrowsVertical","position","IconButton","label","onClick","Link","marginLeft","Button","disabled","loading"],"mappings":"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"}
1
+ {"version":3,"file":"AssetCropEditor.js","sources":["../../../../../../../admin/src/future/pages/Assets/components/AssetDetails/AssetCropEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport {\n Box,\n Button,\n Field,\n Flex,\n FocusTrap,\n IconButton,\n NumberInput,\n Portal,\n Typography,\n} from '@strapi/design-system';\nimport { ArrowsHorizontal, ArrowsVertical, Crop, Link } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, useTheme } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../utils/files';\nimport { getTranslationKey } from '../../../../utils/translations';\n\nimport { resolveCornerResize, useCropImg } from './useCropImg';\n\nimport type {\n AssetWithPopulatedCreatedBy,\n FocalPoint,\n} from '../../../../../../../shared/contracts/files';\n\nconst FOCAL_DIAMETER_REM = 5.6;\nconst HANDLE_PX = 12;\n\n/* -------------------------------------------------------------------------------------------------\n * Styled\n * -----------------------------------------------------------------------------------------------*/\n\n// Full-viewport takeover with a small inset so the editor reads as a card.\nconst Overlay = styled(Flex)`\n position: fixed;\n z-index: 1200;\n flex-direction: column;\n top: ${({ theme }) => theme.spaces[1]};\n left: ${({ theme }) => theme.spaces[1]};\n right: ${({ theme }) => theme.spaces[1]};\n bottom: ${({ theme }) => theme.spaces[1]};\n border-radius: ${({ theme }) => theme.borderRadius};\n border: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n /* Focused programmatically on open (tabIndex -1) — no visible ring needed. */\n outline: none;\n`;\n\nconst HeaderBar = styled(Flex)`\n width: 100%;\n gap: ${({ theme }) => theme.spaces[2]};\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[5]}`};\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n`;\n\n// Fills the remaining space between header/footer; checkerboard pattern.\n// The horizontal padding keeps the image off the viewport edges — the corner\n// handles overhang the image by half their size, and on narrow (mobile)\n// screens an edge-to-edge image leaves nothing to grab.\nconst Body = styled(Box)`\n width: 100%;\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n padding: 0 ${({ theme }) => theme.spaces[4]};\n background: repeating-conic-gradient(\n ${({ theme }) => theme.colors.neutral100} 0% 25%,\n ${({ theme }) => theme.colors.neutral0} 0% 50%\n )\n 50% / 20px 20px;\n`;\n\n// Wrapper sized to the image's natural aspect ratio so the <img> inside fills\n// it without letterboxing. Percentage-based positioning of the crop overlay\n// then maps directly to natural-px coordinates.\nconst CropArea = styled.div<{ $aspect?: number }>`\n position: relative;\n max-width: 100%;\n max-height: 100%;\n ${({ $aspect }) => ($aspect ? `aspect-ratio: ${$aspect};` : '')}\n\n img {\n display: block;\n width: 100%;\n height: 100%;\n user-select: none;\n -webkit-user-drag: none;\n }\n`;\n\n// Crop selection rectangle, positioned by % of CropArea. Inverts the dim\n// outside via box-shadow so the focused area shows full color.\nconst CropOverlay = styled.div`\n position: absolute;\n border: 1px dashed ${({ theme }) => theme.colors.primary600};\n box-shadow: 0 0 0 9999px rgba(33, 33, 52, 0.5);\n cursor: move;\n /* Without this, touch browsers claim the gesture for scrolling and fire\n pointercancel mid-drag — the crop drag dies while the finger is down. */\n touch-action: none;\n`;\n\nconst ResizeHandle = styled.button<{ $cursor: string }>`\n position: absolute;\n width: ${HANDLE_PX}px;\n height: ${HANDLE_PX}px;\n margin: -${HANDLE_PX / 2}px;\n padding: 0;\n border: 1px solid ${({ theme }) => theme.colors.primary600};\n border-radius: 2px;\n background: ${({ theme }) => theme.colors.neutral0};\n cursor: ${({ $cursor }) => $cursor};\n touch-action: none;\n`;\n\nconst FocalPointHandle = styled.button`\n position: absolute;\n width: ${FOCAL_DIAMETER_REM}rem;\n height: ${FOCAL_DIAMETER_REM}rem;\n margin: ${-FOCAL_DIAMETER_REM / 2}rem 0 0 ${-FOCAL_DIAMETER_REM / 2}rem;\n border-radius: 50%;\n border: 1px solid ${({ theme }) => theme.colors.neutral800};\n background: transparent;\n cursor: grab;\n padding: 0;\n touch-action: none;\n\n &::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.16);\n transform: translate(-50%, -50%);\n }\n &::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: ${({ theme }) => theme.colors.neutral800};\n transform: translate(-50%, -50%);\n }\n\n &:active {\n cursor: grabbing;\n }\n`;\n\nconst InfoBox = styled(Box)`\n position: absolute;\n right: ${({ theme }) => theme.spaces[1]};\n bottom: ${({ theme }) => theme.spaces[1]};\n width: 100%;\n max-width: 32rem;\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) =>\n theme.colorScheme === 'dark' ? theme.colors.neutral150 : theme.colors.neutral900};\n z-index: 20;\n`;\n\nconst FooterBar = styled(Flex)`\n width: 100%;\n justify-content: space-between;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[5]}`};\n border-top: 1px solid ${({ theme }) => theme.colors.neutral150};\n background: ${({ theme }) => theme.colors.neutral0};\n`;\n\nconst FieldRow = styled(Field.Root)`\n flex-direction: row;\n align-items: center;\n`;\n\nconst FieldNumberInput = styled(NumberInput)`\n width: 8.4rem;\n`;\n\nconst LabelIcon = styled(Field.Label)`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.6rem;\n height: 1.6rem;\n`;\n\nconst BackgroundPreserveRatioContainer = styled(Box)`\n position: absolute;\n top: 50%;\n left: 0;\n transform: translateY(-50%);\n\n svg {\n display: block;\n }\n`;\n\nconst BackgroundPreserveRatio = () => (\n <BackgroundPreserveRatioContainer>\n <svg width=\"17\" height=\"49\" viewBox=\"0 0 17 49\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M0.5 0.5H8.5C12.9183 0.5 16.5 4.08172 16.5 8.5M0.5 48.5H8.5C12.9183 48.5 16.5 44.9183 16.5 40.5\"\n stroke=\"#666687\"\n strokeLinecap=\"round\"\n />\n </svg>\n </BackgroundPreserveRatioContainer>\n);\n\n/* -------------------------------------------------------------------------------------------------\n * AssetCropEditor\n * -----------------------------------------------------------------------------------------------*/\n\ninterface AssetCropEditorProps {\n asset: AssetWithPopulatedCreatedBy;\n isBusy?: boolean;\n onClose: () => void;\n onApply: (file: globalThis.File, focalPoint: FocalPoint) => void;\n onSaveAsCopy: (file: globalThis.File, focalPoint: FocalPoint) => void;\n /**\n * \"Save as copy\" creates a new asset (`assets.create`), a different permission\n * from cropping in place (`assets.update`). Hidden when the user lacks it, so\n * an update-only role can't trigger a 403.\n */\n canSaveAsCopy: boolean;\n}\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br';\n\nexport const AssetCropEditor = ({\n asset,\n isBusy = false,\n onClose,\n onApply,\n onSaveAsCopy,\n canSaveAsCopy,\n}: AssetCropEditorProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n // The InfoBox is a fixed dark surface in both themes, so its text can't use a\n // single neutral token (those invert with the scheme). Pick the scheme's white\n // and a muted grey explicitly.\n const theme = useTheme();\n const isDark = theme.colorScheme === 'dark';\n const infoTextColor = isDark ? 'neutral1000' : 'neutral0';\n const infoMutedColor = isDark ? 'neutral600' : 'neutral200';\n const imgRef = React.useRef<HTMLImageElement>(null);\n const cropAreaRef = React.useRef<HTMLDivElement>(null);\n const overlayRef = React.useRef<HTMLDivElement>(null);\n\n // FocusTrap's auto-focus lands on the first focusable element — the crop\n // width NumberInput — which pops the keyboard on mobile the moment the\n // editor opens. Focus the (tabIndex -1) overlay instead: keyboard users are\n // one Tab away from the first control, Escape still reaches the trap.\n React.useEffect(() => {\n overlayRef.current?.focus();\n }, []);\n\n const {\n init,\n crop,\n naturalSize,\n aspectRatio,\n setCropSize,\n setCropPosition,\n setAspectRatio,\n produceFile,\n width,\n height,\n } = useCropImg();\n\n const [aspectLocked, setAspectLocked] = React.useState(false);\n // Focal point as a percentage of the crop area (matches the {x,y} contract).\n const [focal, setFocal] = React.useState<FocalPoint>(asset.focalPoint ?? { x: 50, y: 50 });\n\n // Append `updatedAt` as a cache-buster: a replaced asset is served at the same\n // URL, so without this, reopening the editor shows the browser-cached old image\n // (mirrors AssetPreview).\n const rawImageUrl = prefixFileUrlWithBackendUrl(asset.url) as string;\n const cacheKey = asset.updatedAt ? new Date(asset.updatedAt).getTime() : undefined;\n const imageUrl =\n cacheKey !== undefined\n ? `${rawImageUrl}${rawImageUrl.includes('?') ? '&' : '?'}v=${cacheKey}`\n : rawImageUrl;\n\n const handleImageLoad = () => {\n if (imgRef.current) {\n init(imgRef.current);\n }\n };\n\n // Map a pointer event to natural-px coordinates inside the image.\n const pointerToNatural = (event: PointerEvent | React.PointerEvent) => {\n const rect = cropAreaRef.current?.getBoundingClientRect();\n if (!rect || !naturalSize.width || !naturalSize.height) return null;\n const ratioX = naturalSize.width / rect.width;\n const ratioY = naturalSize.height / rect.height;\n return {\n x: (event.clientX - rect.left) * ratioX,\n y: (event.clientY - rect.top) * ratioY,\n };\n };\n\n // Teardown for the drag currently in flight, so it can be run both on pointer\n // release AND on unmount. Without the unmount path, closing the editor mid-drag\n // (Escape, drawer close, a re-render dropping the overlay) would never fire a\n // pointer event, leaking the window listeners and letting a stale `onMove`\n // call `setCropPosition` on an unmounted component.\n const activeDragCleanupRef = React.useRef<(() => void) | null>(null);\n\n React.useEffect(() => {\n return () => {\n activeDragCleanupRef.current?.();\n };\n }, []);\n\n // Track a pointer drag until the pointer is released or the browser cancels\n // it. The pointer is captured so the drag follows the finger even once it\n // leaves the (12px) handle it started on, and pointercancel is treated as\n // release so an interrupted touch never leaves stale window listeners.\n const trackPointerDrag = (event: React.PointerEvent, onMove: (e: PointerEvent) => void) => {\n event.preventDefault();\n event.stopPropagation();\n const { pointerId } = event;\n try {\n event.currentTarget.setPointerCapture(pointerId);\n } catch {\n // Unsupported environment (jsdom) — window listeners still track the drag.\n }\n const move = (e: PointerEvent) => {\n if (e.pointerId !== pointerId) return;\n onMove(e);\n };\n const cleanup = () => {\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', end);\n window.removeEventListener('pointercancel', end);\n activeDragCleanupRef.current = null;\n };\n const end = (e: PointerEvent) => {\n if (e.pointerId !== pointerId) return;\n cleanup();\n };\n // Only one drag is ever live at a time; tear down any previous one first.\n activeDragCleanupRef.current?.();\n activeDragCleanupRef.current = cleanup;\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', end);\n window.addEventListener('pointercancel', end);\n };\n\n // Drag the entire crop rectangle.\n const handleMovePointerDown = (event: React.PointerEvent) => {\n const start = pointerToNatural(event);\n if (!start) return;\n const startCrop = { ...crop };\n trackPointerDrag(event, (e) => {\n const next = pointerToNatural(e);\n if (!next) return;\n setCropPosition({\n x: startCrop.x + (next.x - start.x),\n y: startCrop.y + (next.y - start.y),\n });\n });\n };\n\n // Resize from a corner; the opposite corner stays anchored.\n const handleResizePointerDown = (corner: Corner) => (event: React.PointerEvent) => {\n const startCrop = { ...crop };\n const anchorX =\n corner === 'tl' || corner === 'bl' ? startCrop.x + startCrop.width : startCrop.x;\n const anchorY =\n corner === 'tl' || corner === 'tr' ? startCrop.y + startCrop.height : startCrop.y;\n trackPointerDrag(event, (e) => {\n const point = pointerToNatural(e);\n if (!point) return;\n const {\n x,\n y,\n width: w,\n height: h,\n } = resolveCornerResize({\n anchorX,\n anchorY,\n point,\n aspectRatio: aspectLocked ? aspectRatio : null,\n });\n setCropPosition({ x, y });\n setCropSize({ width: w, height: h });\n });\n };\n\n const toggleAspectLock = () => {\n setAspectLocked((locked) => {\n const next = !locked;\n setAspectRatio(next && height ? width / height : null);\n return next;\n });\n };\n\n // Drag the focal handle within the crop rectangle, clamped 0–100.\n const handleFocalPointerDown = (event: React.PointerEvent) => {\n trackPointerDrag(event, (e) => {\n const point = pointerToNatural(e);\n if (!point) return;\n // Convert pointer to a percentage of the current crop area.\n const px = ((point.x - crop.x) / crop.width) * 100;\n const py = ((point.y - crop.y) / crop.height) * 100;\n setFocal({\n x: Math.round(Math.min(100, Math.max(0, px))),\n y: Math.round(Math.min(100, Math.max(0, py))),\n });\n });\n };\n\n const focalPxX = Math.round((focal.x / 100) * width);\n const focalPxY = Math.round((focal.y / 100) * height);\n\n const setFocalPx = (axis: 'x' | 'y', value: number) => {\n const dim = axis === 'x' ? width : height;\n if (!dim) return;\n const pct = Math.min(100, Math.max(0, (value / dim) * 100));\n setFocal((prev) => ({ ...prev, [axis]: Math.round(pct) }));\n };\n\n const cropPercents =\n naturalSize.width && naturalSize.height\n ? {\n left: (crop.x / naturalSize.width) * 100,\n top: (crop.y / naturalSize.height) * 100,\n width: (crop.width / naturalSize.width) * 100,\n height: (crop.height / naturalSize.height) * 100,\n }\n : null;\n\n // The crop is only usable once the image has loaded and `init()` has seeded\n // the natural size. Until then the produce/export path would reject.\n const isReady = cropPercents !== null;\n\n const handleAction = async (action: 'apply' | 'copy') => {\n if (!isReady) return;\n\n let file: globalThis.File;\n try {\n file = await produceFile(asset.name, asset.mime ?? 'image/png', asset.updatedAt);\n } catch {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: getTranslationKey('asset-details.crop.export-error'),\n defaultMessage: 'Could not process the cropped image.',\n }),\n });\n return;\n }\n\n const roundedFocal = { x: Math.round(focal.x), y: Math.round(focal.y) };\n if (action === 'apply') {\n onApply(file, roundedFocal);\n } else {\n onSaveAsCopy(file, roundedFocal);\n }\n };\n\n return (\n <Portal>\n <FocusTrap onEscape={onClose} skipAutoFocus>\n <Overlay ref={overlayRef} tabIndex={-1}>\n <HeaderBar alignItems=\"center\">\n <Crop aria-hidden />\n <Typography variant=\"omega\" fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('asset-details.crop.title'),\n defaultMessage: 'Crop & Focus area',\n })}\n </Typography>\n </HeaderBar>\n\n <Body>\n <CropArea\n ref={cropAreaRef}\n $aspect={\n naturalSize.width && naturalSize.height\n ? naturalSize.width / naturalSize.height\n : undefined\n }\n >\n <img\n ref={imgRef}\n src={imageUrl}\n alt={asset.name}\n crossOrigin=\"anonymous\"\n onLoad={handleImageLoad}\n draggable={false}\n />\n\n {cropPercents ? (\n <CropOverlay\n style={{\n left: `${cropPercents.left}%`,\n top: `${cropPercents.top}%`,\n width: `${cropPercents.width}%`,\n height: `${cropPercents.height}%`,\n }}\n onPointerDown={handleMovePointerDown}\n >\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.top-left'),\n defaultMessage: 'Resize top-left',\n })}\n $cursor=\"nwse-resize\"\n style={{ left: 0, top: 0 }}\n onPointerDown={handleResizePointerDown('tl')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.top-right'),\n defaultMessage: 'Resize top-right',\n })}\n $cursor=\"nesw-resize\"\n style={{ right: 0, top: 0 }}\n onPointerDown={handleResizePointerDown('tr')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.bottom-left'),\n defaultMessage: 'Resize bottom-left',\n })}\n $cursor=\"nesw-resize\"\n style={{ left: 0, bottom: 0 }}\n onPointerDown={handleResizePointerDown('bl')}\n />\n <ResizeHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.resize.bottom-right'),\n defaultMessage: 'Resize bottom-right',\n })}\n $cursor=\"nwse-resize\"\n style={{ right: 0, bottom: 0 }}\n onPointerDown={handleResizePointerDown('br')}\n />\n\n <FocalPointHandle\n type=\"button\"\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-point'),\n defaultMessage: 'Focal point',\n })}\n style={{ left: `${focal.x}%`, top: `${focal.y}%` }}\n onPointerDown={handleFocalPointerDown}\n />\n </CropOverlay>\n ) : null}\n </CropArea>\n\n <InfoBox>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={1} paddingBottom={3}>\n <Typography variant=\"omega\" fontWeight=\"bold\" textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.title'),\n defaultMessage: 'Crop & Focus area',\n })}\n </Typography>\n <Typography variant=\"pi\" textColor={infoMutedColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.hint'),\n defaultMessage:\n 'Set the crop area with the rectangle. Pin the always-visible area with the circle.',\n })}\n </Typography>\n </Flex>\n\n <Flex gap={6} alignItems=\"center\">\n <Flex alignItems=\"center\" gap={2}>\n <Flex direction=\"column\" gap={2}>\n <FieldRow name=\"crop-width\" gap={2}>\n <LabelIcon textColor={infoTextColor}>\n <ArrowsHorizontal />\n </LabelIcon>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.width'),\n defaultMessage: 'Width (px)',\n })}\n value={width}\n min={1}\n max={naturalSize.width || undefined}\n onValueChange={(next) => {\n if (next !== undefined) setCropSize({ width: next });\n }}\n />\n </FieldRow>\n <FieldRow name=\"crop-height\" gap={2}>\n <LabelIcon textColor={infoTextColor}>\n <ArrowsVertical />\n </LabelIcon>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.height'),\n defaultMessage: 'Height (px)',\n })}\n value={height}\n min={1}\n max={naturalSize.height || undefined}\n onValueChange={(next) => {\n if (next !== undefined) setCropSize({ height: next });\n }}\n />\n </FieldRow>\n </Flex>\n\n <Flex position=\"relative\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('asset-details.crop.aspect-lock'),\n defaultMessage: 'Lock aspect ratio',\n })}\n variant={aspectLocked ? 'secondary' : 'ghost'}\n onClick={toggleAspectLock}\n >\n <Link />\n </IconButton>\n <BackgroundPreserveRatio />\n </Flex>\n </Flex>\n\n <Flex direction=\"column\" gap={2} marginLeft={'auto'}>\n <FieldRow name=\"focal-x\" gap={2}>\n <Field.Label textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.focal-x-axis'),\n defaultMessage: 'X',\n })}\n </Field.Label>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-x'),\n defaultMessage: 'Focal point X (px)',\n })}\n value={focalPxX}\n onValueChange={(next) => {\n if (next !== undefined) setFocalPx('x', next);\n }}\n />\n </FieldRow>\n <FieldRow name=\"focal-y\" gap={2}>\n <Field.Label textColor={infoTextColor}>\n {formatMessage({\n id: getTranslationKey('asset-details.crop.focal-y-axis'),\n defaultMessage: 'Y',\n })}\n </Field.Label>\n <FieldNumberInput\n aria-label={formatMessage({\n id: getTranslationKey('asset-details.crop.focal-y'),\n defaultMessage: 'Focal point Y (px)',\n })}\n value={focalPxY}\n onValueChange={(next) => {\n if (next !== undefined) setFocalPx('y', next);\n }}\n />\n </FieldRow>\n </Flex>\n </Flex>\n </InfoBox>\n </Body>\n\n <FooterBar alignItems=\"center\">\n <Button variant=\"tertiary\" onClick={onClose} disabled={isBusy}>\n {formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}\n </Button>\n <Flex gap={2}>\n {canSaveAsCopy && (\n <Button\n variant=\"secondary\"\n onClick={() => handleAction('copy')}\n loading={isBusy}\n disabled={!isReady}\n >\n {formatMessage({\n id: getTranslationKey('asset-details.crop.save-as-copy'),\n defaultMessage: 'Save as copy',\n })}\n </Button>\n )}\n <Button\n variant=\"default\"\n onClick={() => handleAction('apply')}\n loading={isBusy}\n disabled={!isReady}\n >\n {formatMessage({\n id: getTranslationKey('asset-details.crop.apply'),\n defaultMessage: 'Apply',\n })}\n </Button>\n </Flex>\n </FooterBar>\n </Overlay>\n </FocusTrap>\n </Portal>\n );\n};\n"],"names":["FOCAL_DIAMETER_REM","HANDLE_PX","Overlay","styled","Flex","theme","spaces","borderRadius","colors","neutral150","neutral0","HeaderBar","Body","Box","neutral100","CropArea","div","$aspect","CropOverlay","primary600","ResizeHandle","button","$cursor","FocalPointHandle","neutral800","InfoBox","colorScheme","neutral900","FooterBar","FieldRow","Field","Root","FieldNumberInput","NumberInput","LabelIcon","Label","BackgroundPreserveRatioContainer","BackgroundPreserveRatio","_jsx","svg","width","height","viewBox","fill","xmlns","path","d","stroke","strokeLinecap","AssetCropEditor","asset","isBusy","onClose","onApply","onSaveAsCopy","canSaveAsCopy","formatMessage","useIntl","toggleNotification","useNotification","useTheme","isDark","infoTextColor","infoMutedColor","imgRef","React","useRef","cropAreaRef","overlayRef","useEffect","current","focus","init","crop","naturalSize","aspectRatio","setCropSize","setCropPosition","setAspectRatio","produceFile","useCropImg","aspectLocked","setAspectLocked","useState","focal","setFocal","focalPoint","x","y","rawImageUrl","prefixFileUrlWithBackendUrl","url","cacheKey","updatedAt","Date","getTime","undefined","imageUrl","includes","handleImageLoad","pointerToNatural","event","rect","getBoundingClientRect","ratioX","ratioY","clientX","left","clientY","top","activeDragCleanupRef","trackPointerDrag","onMove","preventDefault","stopPropagation","pointerId","currentTarget","setPointerCapture","move","e","cleanup","window","removeEventListener","end","addEventListener","handleMovePointerDown","start","startCrop","next","handleResizePointerDown","corner","anchorX","anchorY","point","w","h","resolveCornerResize","toggleAspectLock","locked","handleFocalPointerDown","px","py","Math","round","min","max","focalPxX","focalPxY","setFocalPx","axis","value","dim","pct","prev","cropPercents","isReady","handleAction","action","file","name","mime","type","message","id","getTranslationKey","defaultMessage","roundedFocal","Portal","FocusTrap","onEscape","skipAutoFocus","_jsxs","ref","tabIndex","alignItems","Crop","aria-hidden","Typography","variant","fontWeight","img","src","alt","crossOrigin","onLoad","draggable","style","onPointerDown","aria-label","right","bottom","direction","gap","paddingBottom","textColor","ArrowsHorizontal","onValueChange","ArrowsVertical","position","IconButton","label","onClick","Link","marginLeft","Button","disabled","loading"],"mappings":"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"}
@@ -25,6 +25,8 @@ const Overlay = styled(Flex)`
25
25
  border-radius: ${({ theme })=>theme.borderRadius};
26
26
  border: 1px solid ${({ theme })=>theme.colors.neutral150};
27
27
  background: ${({ theme })=>theme.colors.neutral0};
28
+ /* Focused programmatically on open (tabIndex -1) — no visible ring needed. */
29
+ outline: none;
28
30
  `;
29
31
  const HeaderBar = styled(Flex)`
30
32
  width: 100%;
@@ -34,6 +36,9 @@ const HeaderBar = styled(Flex)`
34
36
  background: ${({ theme })=>theme.colors.neutral0};
35
37
  `;
36
38
  // Fills the remaining space between header/footer; checkerboard pattern.
39
+ // The horizontal padding keeps the image off the viewport edges — the corner
40
+ // handles overhang the image by half their size, and on narrow (mobile)
41
+ // screens an edge-to-edge image leaves nothing to grab.
37
42
  const Body = styled(Box)`
38
43
  width: 100%;
39
44
  position: relative;
@@ -43,6 +48,7 @@ const Body = styled(Box)`
43
48
  align-items: center;
44
49
  justify-content: center;
45
50
  overflow: hidden;
51
+ padding: 0 ${({ theme })=>theme.spaces[4]};
46
52
  background: repeating-conic-gradient(
47
53
  ${({ theme })=>theme.colors.neutral100} 0% 25%,
48
54
  ${({ theme })=>theme.colors.neutral0} 0% 50%
@@ -73,6 +79,9 @@ const CropOverlay = styled.div`
73
79
  border: 1px dashed ${({ theme })=>theme.colors.primary600};
74
80
  box-shadow: 0 0 0 9999px rgba(33, 33, 52, 0.5);
75
81
  cursor: move;
82
+ /* Without this, touch browsers claim the gesture for scrolling and fire
83
+ pointercancel mid-drag — the crop drag dies while the finger is down. */
84
+ touch-action: none;
76
85
  `;
77
86
  const ResizeHandle = styled.button`
78
87
  position: absolute;
@@ -84,6 +93,7 @@ const ResizeHandle = styled.button`
84
93
  border-radius: 2px;
85
94
  background: ${({ theme })=>theme.colors.neutral0};
86
95
  cursor: ${({ $cursor })=>$cursor};
96
+ touch-action: none;
87
97
  `;
88
98
  const FocalPointHandle = styled.button`
89
99
  position: absolute;
@@ -95,6 +105,7 @@ const FocalPointHandle = styled.button`
95
105
  background: transparent;
96
106
  cursor: grab;
97
107
  padding: 0;
108
+ touch-action: none;
98
109
 
99
110
  &::before {
100
111
  content: '';
@@ -179,7 +190,7 @@ const BackgroundPreserveRatio = ()=>/*#__PURE__*/ jsx(BackgroundPreserveRatioCon
179
190
  })
180
191
  })
181
192
  });
182
- const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy })=>{
193
+ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy, canSaveAsCopy })=>{
183
194
  const { formatMessage } = useIntl();
184
195
  const { toggleNotification } = useNotification();
185
196
  // The InfoBox is a fixed dark surface in both themes, so its text can't use a
@@ -191,6 +202,14 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
191
202
  const infoMutedColor = isDark ? 'neutral600' : 'neutral200';
192
203
  const imgRef = React.useRef(null);
193
204
  const cropAreaRef = React.useRef(null);
205
+ const overlayRef = React.useRef(null);
206
+ // FocusTrap's auto-focus lands on the first focusable element — the crop
207
+ // width NumberInput — which pops the keyboard on mobile the moment the
208
+ // editor opens. Focus the (tabIndex -1) overlay instead: keyboard users are
209
+ // one Tab away from the first control, Escape still reaches the trap.
210
+ React.useEffect(()=>{
211
+ overlayRef.current?.focus();
212
+ }, []);
194
213
  const { init, crop, naturalSize, aspectRatio, setCropSize, setCropPosition, setAspectRatio, produceFile, width, height } = useCropImg();
195
214
  const [aspectLocked, setAspectLocked] = React.useState(false);
196
215
  // Focal point as a percentage of the crop area (matches the {x,y} contract).
@@ -220,40 +239,75 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
220
239
  y: (event.clientY - rect.top) * ratioY
221
240
  };
222
241
  };
223
- // Drag the entire crop rectangle.
224
- const handleMovePointerDown = (event)=>{
242
+ // Teardown for the drag currently in flight, so it can be run both on pointer
243
+ // release AND on unmount. Without the unmount path, closing the editor mid-drag
244
+ // (Escape, drawer close, a re-render dropping the overlay) would never fire a
245
+ // pointer event, leaking the window listeners and letting a stale `onMove`
246
+ // call `setCropPosition` on an unmounted component.
247
+ const activeDragCleanupRef = React.useRef(null);
248
+ React.useEffect(()=>{
249
+ return ()=>{
250
+ activeDragCleanupRef.current?.();
251
+ };
252
+ }, []);
253
+ // Track a pointer drag until the pointer is released or the browser cancels
254
+ // it. The pointer is captured so the drag follows the finger even once it
255
+ // leaves the (12px) handle it started on, and pointercancel is treated as
256
+ // release so an interrupted touch never leaves stale window listeners.
257
+ const trackPointerDrag = (event, onMove)=>{
225
258
  event.preventDefault();
226
259
  event.stopPropagation();
260
+ const { pointerId } = event;
261
+ try {
262
+ event.currentTarget.setPointerCapture(pointerId);
263
+ } catch {
264
+ // Unsupported environment (jsdom) — window listeners still track the drag.
265
+ }
266
+ const move = (e)=>{
267
+ if (e.pointerId !== pointerId) return;
268
+ onMove(e);
269
+ };
270
+ const cleanup = ()=>{
271
+ window.removeEventListener('pointermove', move);
272
+ window.removeEventListener('pointerup', end);
273
+ window.removeEventListener('pointercancel', end);
274
+ activeDragCleanupRef.current = null;
275
+ };
276
+ const end = (e)=>{
277
+ if (e.pointerId !== pointerId) return;
278
+ cleanup();
279
+ };
280
+ // Only one drag is ever live at a time; tear down any previous one first.
281
+ activeDragCleanupRef.current?.();
282
+ activeDragCleanupRef.current = cleanup;
283
+ window.addEventListener('pointermove', move);
284
+ window.addEventListener('pointerup', end);
285
+ window.addEventListener('pointercancel', end);
286
+ };
287
+ // Drag the entire crop rectangle.
288
+ const handleMovePointerDown = (event)=>{
227
289
  const start = pointerToNatural(event);
228
290
  if (!start) return;
229
291
  const startCrop = {
230
292
  ...crop
231
293
  };
232
- const move = (e)=>{
294
+ trackPointerDrag(event, (e)=>{
233
295
  const next = pointerToNatural(e);
234
296
  if (!next) return;
235
297
  setCropPosition({
236
298
  x: startCrop.x + (next.x - start.x),
237
299
  y: startCrop.y + (next.y - start.y)
238
300
  });
239
- };
240
- const up = ()=>{
241
- window.removeEventListener('pointermove', move);
242
- window.removeEventListener('pointerup', up);
243
- };
244
- window.addEventListener('pointermove', move);
245
- window.addEventListener('pointerup', up);
301
+ });
246
302
  };
247
303
  // Resize from a corner; the opposite corner stays anchored.
248
304
  const handleResizePointerDown = (corner)=>(event)=>{
249
- event.preventDefault();
250
- event.stopPropagation();
251
305
  const startCrop = {
252
306
  ...crop
253
307
  };
254
308
  const anchorX = corner === 'tl' || corner === 'bl' ? startCrop.x + startCrop.width : startCrop.x;
255
309
  const anchorY = corner === 'tl' || corner === 'tr' ? startCrop.y + startCrop.height : startCrop.y;
256
- const move = (e)=>{
310
+ trackPointerDrag(event, (e)=>{
257
311
  const point = pointerToNatural(e);
258
312
  if (!point) return;
259
313
  const { x, y, width: w, height: h } = resolveCornerResize({
@@ -270,13 +324,7 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
270
324
  width: w,
271
325
  height: h
272
326
  });
273
- };
274
- const up = ()=>{
275
- window.removeEventListener('pointermove', move);
276
- window.removeEventListener('pointerup', up);
277
- };
278
- window.addEventListener('pointermove', move);
279
- window.addEventListener('pointerup', up);
327
+ });
280
328
  };
281
329
  const toggleAspectLock = ()=>{
282
330
  setAspectLocked((locked)=>{
@@ -287,9 +335,7 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
287
335
  };
288
336
  // Drag the focal handle within the crop rectangle, clamped 0–100.
289
337
  const handleFocalPointerDown = (event)=>{
290
- event.preventDefault();
291
- event.stopPropagation();
292
- const move = (e)=>{
338
+ trackPointerDrag(event, (e)=>{
293
339
  const point = pointerToNatural(e);
294
340
  if (!point) return;
295
341
  // Convert pointer to a percentage of the current crop area.
@@ -299,13 +345,7 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
299
345
  x: Math.round(Math.min(100, Math.max(0, px))),
300
346
  y: Math.round(Math.min(100, Math.max(0, py)))
301
347
  });
302
- };
303
- const up = ()=>{
304
- window.removeEventListener('pointermove', move);
305
- window.removeEventListener('pointerup', up);
306
- };
307
- window.addEventListener('pointermove', move);
308
- window.addEventListener('pointerup', up);
348
+ });
309
349
  };
310
350
  const focalPxX = Math.round(focal.x / 100 * width);
311
351
  const focalPxY = Math.round(focal.y / 100 * height);
@@ -355,7 +395,10 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
355
395
  return /*#__PURE__*/ jsx(Portal, {
356
396
  children: /*#__PURE__*/ jsx(FocusTrap, {
357
397
  onEscape: onClose,
398
+ skipAutoFocus: true,
358
399
  children: /*#__PURE__*/ jsxs(Overlay, {
400
+ ref: overlayRef,
401
+ tabIndex: -1,
359
402
  children: [
360
403
  /*#__PURE__*/ jsxs(HeaderBar, {
361
404
  alignItems: "center",
@@ -644,7 +687,7 @@ const AssetCropEditor = ({ asset, isBusy = false, onClose, onApply, onSaveAsCopy
644
687
  /*#__PURE__*/ jsxs(Flex, {
645
688
  gap: 2,
646
689
  children: [
647
- /*#__PURE__*/ jsx(Button, {
690
+ canSaveAsCopy && /*#__PURE__*/ jsx(Button, {
648
691
  variant: "secondary",
649
692
  onClick: ()=>handleAction('copy'),
650
693
  loading: isBusy,