@strapi/upload 5.33.4 → 5.35.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 (183) hide show
  1. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +32 -3
  2. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  3. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +32 -3
  4. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  5. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
  6. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.mjs.map +1 -1
  7. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js +57 -0
  8. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js.map +1 -0
  9. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs +55 -0
  10. package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs.map +1 -0
  11. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +96 -20
  12. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
  13. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +98 -22
  14. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
  15. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.js +47 -0
  16. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.js.map +1 -1
  17. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.mjs +44 -1
  18. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.mjs.map +1 -1
  19. package/dist/admin/future/App.js +45 -0
  20. package/dist/admin/future/App.js.map +1 -0
  21. package/dist/admin/future/App.mjs +43 -0
  22. package/dist/admin/future/App.mjs.map +1 -0
  23. package/dist/admin/future/pages/AIGenerationPage.js +24 -0
  24. package/dist/admin/future/pages/AIGenerationPage.js.map +1 -0
  25. package/dist/admin/future/pages/AIGenerationPage.mjs +22 -0
  26. package/dist/admin/future/pages/AIGenerationPage.mjs.map +1 -0
  27. package/dist/admin/future/pages/MediaLibraryPage.js +119 -0
  28. package/dist/admin/future/pages/MediaLibraryPage.js.map +1 -0
  29. package/dist/admin/future/pages/MediaLibraryPage.mjs +98 -0
  30. package/dist/admin/future/pages/MediaLibraryPage.mjs.map +1 -0
  31. package/dist/admin/future/services/api.js +28 -0
  32. package/dist/admin/future/services/api.js.map +1 -0
  33. package/dist/admin/future/services/api.mjs +25 -0
  34. package/dist/admin/future/services/api.mjs.map +1 -0
  35. package/dist/admin/future/utils/translations.js +8 -0
  36. package/dist/admin/future/utils/translations.js.map +1 -0
  37. package/dist/admin/future/utils/translations.mjs +6 -0
  38. package/dist/admin/future/utils/translations.mjs.map +1 -0
  39. package/dist/admin/hooks/useAIMetadataJob.js +114 -0
  40. package/dist/admin/hooks/useAIMetadataJob.js.map +1 -0
  41. package/dist/admin/hooks/useAIMetadataJob.mjs +93 -0
  42. package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -0
  43. package/dist/admin/hooks/useEditAsset.js +1 -0
  44. package/dist/admin/hooks/useEditAsset.js.map +1 -1
  45. package/dist/admin/hooks/useEditAsset.mjs +1 -0
  46. package/dist/admin/hooks/useEditAsset.mjs.map +1 -1
  47. package/dist/admin/index.js +23 -4
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/index.mjs +24 -5
  50. package/dist/admin/index.mjs.map +1 -1
  51. package/dist/admin/package.json.js +6 -5
  52. package/dist/admin/package.json.js.map +1 -1
  53. package/dist/admin/package.json.mjs +6 -5
  54. package/dist/admin/package.json.mjs.map +1 -1
  55. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js +1 -0
  56. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  57. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs +1 -0
  58. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
  59. package/dist/admin/pages/App/components/Header.js +3 -0
  60. package/dist/admin/pages/App/components/Header.js.map +1 -1
  61. package/dist/admin/pages/App/components/Header.mjs +3 -0
  62. package/dist/admin/pages/App/components/Header.mjs.map +1 -1
  63. package/dist/admin/pages/SettingsPage/SettingsPage.js +252 -67
  64. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  65. package/dist/admin/pages/SettingsPage/SettingsPage.mjs +256 -71
  66. package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
  67. package/dist/admin/src/components/EditAssetDialog/PreviewBox/AssetPreview.d.ts +1 -2
  68. package/dist/admin/src/components/EditAssetDialog/PreviewBox/FocalPointActions.d.ts +7 -0
  69. package/dist/admin/src/components/EditAssetDialog/PreviewBox/PreviewBox.d.ts +6 -2
  70. package/dist/admin/src/components/EditAssetDialog/PreviewBox/PreviewComponents.d.ts +13 -0
  71. package/dist/admin/src/future/App.d.ts +1 -0
  72. package/dist/admin/src/future/pages/AIGenerationPage.d.ts +1 -0
  73. package/dist/admin/src/future/pages/MediaLibraryPage.d.ts +1 -0
  74. package/dist/admin/src/future/services/api.d.ts +6 -0
  75. package/dist/admin/src/future/services/settings.d.ts +2 -0
  76. package/dist/admin/src/future/utils/translations.d.ts +1 -0
  77. package/dist/admin/src/hooks/useAIMetadataJob.d.ts +9 -0
  78. package/dist/admin/translations/de.json.js +44 -1
  79. package/dist/admin/translations/de.json.js.map +1 -1
  80. package/dist/admin/translations/de.json.mjs +44 -1
  81. package/dist/admin/translations/de.json.mjs.map +1 -1
  82. package/dist/admin/translations/en.json.js +17 -0
  83. package/dist/admin/translations/en.json.js.map +1 -1
  84. package/dist/admin/translations/en.json.mjs +17 -0
  85. package/dist/admin/translations/en.json.mjs.map +1 -1
  86. package/dist/server/bootstrap.js +1 -0
  87. package/dist/server/bootstrap.js.map +1 -1
  88. package/dist/server/bootstrap.mjs +1 -0
  89. package/dist/server/bootstrap.mjs.map +1 -1
  90. package/dist/server/content-types/file.js +4 -0
  91. package/dist/server/content-types/file.js.map +1 -1
  92. package/dist/server/content-types/file.mjs +4 -0
  93. package/dist/server/content-types/file.mjs.map +1 -1
  94. package/dist/server/controllers/admin-file.js +86 -0
  95. package/dist/server/controllers/admin-file.js.map +1 -1
  96. package/dist/server/controllers/admin-file.mjs +86 -0
  97. package/dist/server/controllers/admin-file.mjs.map +1 -1
  98. package/dist/server/controllers/admin-upload.js +3 -23
  99. package/dist/server/controllers/admin-upload.js.map +1 -1
  100. package/dist/server/controllers/admin-upload.mjs +3 -23
  101. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  102. package/dist/server/controllers/validation/admin/upload.js +5 -0
  103. package/dist/server/controllers/validation/admin/upload.js.map +1 -1
  104. package/dist/server/controllers/validation/admin/upload.mjs +5 -0
  105. package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
  106. package/dist/server/controllers/validation/content-api/upload.js +6 -1
  107. package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
  108. package/dist/server/controllers/validation/content-api/upload.mjs +6 -1
  109. package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
  110. package/dist/server/models/ai-metadata-job.js +36 -0
  111. package/dist/server/models/ai-metadata-job.js.map +1 -0
  112. package/dist/server/models/ai-metadata-job.mjs +33 -0
  113. package/dist/server/models/ai-metadata-job.mjs.map +1 -0
  114. package/dist/server/register.js +3 -0
  115. package/dist/server/register.js.map +1 -1
  116. package/dist/server/register.mjs +3 -0
  117. package/dist/server/register.mjs.map +1 -1
  118. package/dist/server/routes/admin.js +46 -0
  119. package/dist/server/routes/admin.js.map +1 -1
  120. package/dist/server/routes/admin.mjs +46 -0
  121. package/dist/server/routes/admin.mjs.map +1 -1
  122. package/dist/server/services/ai-metadata-jobs.js +72 -0
  123. package/dist/server/services/ai-metadata-jobs.js.map +1 -0
  124. package/dist/server/services/ai-metadata-jobs.mjs +70 -0
  125. package/dist/server/services/ai-metadata-jobs.mjs.map +1 -0
  126. package/dist/server/services/ai-metadata.js +170 -20
  127. package/dist/server/services/ai-metadata.js.map +1 -1
  128. package/dist/server/services/ai-metadata.mjs +170 -20
  129. package/dist/server/services/ai-metadata.mjs.map +1 -1
  130. package/dist/server/services/index.js +3 -1
  131. package/dist/server/services/index.js.map +1 -1
  132. package/dist/server/services/index.mjs +3 -1
  133. package/dist/server/services/index.mjs.map +1 -1
  134. package/dist/server/services/upload.js +3 -1
  135. package/dist/server/services/upload.js.map +1 -1
  136. package/dist/server/services/upload.mjs +3 -1
  137. package/dist/server/services/upload.mjs.map +1 -1
  138. package/dist/server/src/bootstrap.d.ts.map +1 -1
  139. package/dist/server/src/content-types/file.d.ts +4 -0
  140. package/dist/server/src/content-types/file.d.ts.map +1 -1
  141. package/dist/server/src/content-types/index.d.ts +4 -0
  142. package/dist/server/src/content-types/index.d.ts.map +1 -1
  143. package/dist/server/src/controllers/admin-file.d.ts +3 -0
  144. package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
  145. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  146. package/dist/server/src/controllers/index.d.ts +3 -0
  147. package/dist/server/src/controllers/index.d.ts.map +1 -1
  148. package/dist/server/src/controllers/validation/admin/upload.d.ts +240 -0
  149. package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
  150. package/dist/server/src/controllers/validation/content-api/upload.d.ts +180 -0
  151. package/dist/server/src/controllers/validation/content-api/upload.d.ts.map +1 -1
  152. package/dist/server/src/index.d.ts +32 -2
  153. package/dist/server/src/index.d.ts.map +1 -1
  154. package/dist/server/src/models/ai-metadata-job.d.ts +5 -0
  155. package/dist/server/src/models/ai-metadata-job.d.ts.map +1 -0
  156. package/dist/server/src/models/index.d.ts +5 -0
  157. package/dist/server/src/models/index.d.ts.map +1 -0
  158. package/dist/server/src/register.d.ts.map +1 -1
  159. package/dist/server/src/routes/admin.d.ts.map +1 -1
  160. package/dist/server/src/services/ai-metadata-jobs.d.ts +14 -0
  161. package/dist/server/src/services/ai-metadata-jobs.d.ts.map +1 -0
  162. package/dist/server/src/services/ai-metadata.d.ts +25 -2
  163. package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
  164. package/dist/server/src/services/index.d.ts +25 -2
  165. package/dist/server/src/services/index.d.ts.map +1 -1
  166. package/dist/server/src/services/upload.d.ts +1 -1
  167. package/dist/server/src/services/upload.d.ts.map +1 -1
  168. package/dist/server/src/types.d.ts +6 -0
  169. package/dist/server/src/types.d.ts.map +1 -1
  170. package/dist/server/src/utils/images.d.ts +7 -0
  171. package/dist/server/src/utils/images.d.ts.map +1 -0
  172. package/dist/server/src/utils/index.d.ts +2 -0
  173. package/dist/server/src/utils/index.d.ts.map +1 -1
  174. package/dist/server/utils/images.js +35 -0
  175. package/dist/server/utils/images.js.map +1 -0
  176. package/dist/server/utils/images.mjs +33 -0
  177. package/dist/server/utils/images.mjs.map +1 -0
  178. package/dist/server/utils/index.js.map +1 -1
  179. package/dist/server/utils/index.mjs.map +1 -1
  180. package/dist/shared/contracts/ai-metadata-jobs.d.ts +53 -0
  181. package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -0
  182. package/dist/shared/contracts/files.d.ts +39 -0
  183. package/package.json +6 -5
@@ -0,0 +1,55 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { FocusTrap, Flex, IconButton } from '@strapi/design-system';
3
+ import { Cross, ArrowsCounterClockwise, Check } from '@strapi/icons';
4
+ import { useIntl } from 'react-intl';
5
+ import 'byte-size';
6
+ import 'date-fns';
7
+ import { getTrad } from '../../../utils/getTrad.mjs';
8
+ import 'qs';
9
+ import '../../../utils/typeFromMime.mjs';
10
+ import '../../../utils/urlYupSchema.mjs';
11
+ import { FocalPointActionRow } from './PreviewComponents.mjs';
12
+
13
+ const FocalPointActions = ({ onCancel, onValidate, onReset })=>{
14
+ const { formatMessage } = useIntl();
15
+ return /*#__PURE__*/ jsx(FocusTrap, {
16
+ onEscape: onCancel,
17
+ children: /*#__PURE__*/ jsx(FocalPointActionRow, {
18
+ justifyContent: "flex-end",
19
+ paddingLeft: 3,
20
+ paddingRight: 3,
21
+ children: /*#__PURE__*/ jsxs(Flex, {
22
+ gap: 1,
23
+ children: [
24
+ /*#__PURE__*/ jsx(IconButton, {
25
+ label: formatMessage({
26
+ id: getTrad('control-card.stop-focal-point'),
27
+ defaultMessage: 'Cancel focal point selection'
28
+ }),
29
+ onClick: onCancel,
30
+ children: /*#__PURE__*/ jsx(Cross, {})
31
+ }),
32
+ /*#__PURE__*/ jsx(IconButton, {
33
+ label: formatMessage({
34
+ id: getTrad('control-card.reset-focal-point'),
35
+ defaultMessage: 'Reset to center'
36
+ }),
37
+ onClick: onReset,
38
+ children: /*#__PURE__*/ jsx(ArrowsCounterClockwise, {})
39
+ }),
40
+ /*#__PURE__*/ jsx(IconButton, {
41
+ label: formatMessage({
42
+ id: getTrad('control-card.save-focal-point'),
43
+ defaultMessage: 'Save focal point'
44
+ }),
45
+ onClick: onValidate,
46
+ children: /*#__PURE__*/ jsx(Check, {})
47
+ })
48
+ ]
49
+ })
50
+ })
51
+ });
52
+ };
53
+
54
+ export { FocalPointActions };
55
+ //# sourceMappingURL=FocalPointActions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FocalPointActions.mjs","sources":["../../../../../admin/src/components/EditAssetDialog/PreviewBox/FocalPointActions.tsx"],"sourcesContent":["import { Flex, FocusTrap, IconButton } from '@strapi/design-system';\nimport { Check, Cross, ArrowsCounterClockwise } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { getTrad } from '../../../utils';\n\nimport { FocalPointActionRow } from './PreviewComponents';\n\ninterface FocalPointActionsProps {\n onCancel: () => void;\n onValidate: () => void;\n onReset: () => void;\n}\n\nexport const FocalPointActions = ({ onCancel, onValidate, onReset }: FocalPointActionsProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <FocusTrap onEscape={onCancel}>\n <FocalPointActionRow justifyContent=\"flex-end\" paddingLeft={3} paddingRight={3}>\n <Flex gap={1}>\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.stop-focal-point'),\n defaultMessage: 'Cancel focal point selection',\n })}\n onClick={onCancel}\n >\n <Cross />\n </IconButton>\n\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.reset-focal-point'),\n defaultMessage: 'Reset to center',\n })}\n onClick={onReset}\n >\n <ArrowsCounterClockwise />\n </IconButton>\n\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.save-focal-point'),\n defaultMessage: 'Save focal point',\n })}\n onClick={onValidate}\n >\n <Check />\n </IconButton>\n </Flex>\n </FocalPointActionRow>\n </FocusTrap>\n );\n};\n"],"names":["FocalPointActions","onCancel","onValidate","onReset","formatMessage","useIntl","_jsx","FocusTrap","onEscape","FocalPointActionRow","justifyContent","paddingLeft","paddingRight","_jsxs","Flex","gap","IconButton","label","id","getTrad","defaultMessage","onClick","Cross","ArrowsCounterClockwise","Check"],"mappings":";;;;;;;;;;;;AAcO,MAAMA,oBAAoB,CAAC,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,OAAO,EAA0B,GAAA;IACzF,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAE1B,IAAA,qBACEC,GAACC,CAAAA,SAAAA,EAAAA;QAAUC,QAAUP,EAAAA,QAAAA;AACnB,QAAA,QAAA,gBAAAK,GAACG,CAAAA,mBAAAA,EAAAA;YAAoBC,cAAe,EAAA,UAAA;YAAWC,WAAa,EAAA,CAAA;YAAGC,YAAc,EAAA,CAAA;AAC3E,YAAA,QAAA,gBAAAC,IAACC,CAAAA,IAAAA,EAAAA;gBAAKC,GAAK,EAAA,CAAA;;kCACTT,GAACU,CAAAA,UAAAA,EAAAA;AACCC,wBAAAA,KAAAA,EAAOb,aAAc,CAAA;AACnBc,4BAAAA,EAAAA,EAAIC,OAAQ,CAAA,+BAAA,CAAA;4BACZC,cAAgB,EAAA;AAClB,yBAAA,CAAA;wBACAC,OAASpB,EAAAA,QAAAA;AAET,wBAAA,QAAA,gBAAAK,GAACgB,CAAAA,KAAAA,EAAAA,EAAAA;;kCAGHhB,GAACU,CAAAA,UAAAA,EAAAA;AACCC,wBAAAA,KAAAA,EAAOb,aAAc,CAAA;AACnBc,4BAAAA,EAAAA,EAAIC,OAAQ,CAAA,gCAAA,CAAA;4BACZC,cAAgB,EAAA;AAClB,yBAAA,CAAA;wBACAC,OAASlB,EAAAA,OAAAA;AAET,wBAAA,QAAA,gBAAAG,GAACiB,CAAAA,sBAAAA,EAAAA,EAAAA;;kCAGHjB,GAACU,CAAAA,UAAAA,EAAAA;AACCC,wBAAAA,KAAAA,EAAOb,aAAc,CAAA;AACnBc,4BAAAA,EAAAA,EAAIC,OAAQ,CAAA,+BAAA,CAAA;4BACZC,cAAgB,EAAA;AAClB,yBAAA,CAAA;wBACAC,OAASnB,EAAAA,UAAAA;AAET,wBAAA,QAAA,gBAAAI,GAACkB,CAAAA,KAAAA,EAAAA,EAAAA;;;;;;AAMb;;;;"}
@@ -25,6 +25,7 @@ var UploadProgress = require('../../UploadProgress/UploadProgress.js');
25
25
  var RemoveAssetDialog = require('../RemoveAssetDialog.js');
26
26
  var AssetPreview = require('./AssetPreview.js');
27
27
  var CroppingActions = require('./CroppingActions.js');
28
+ var FocalPointActions = require('./FocalPointActions.js');
28
29
  var PreviewComponents = require('./PreviewComponents.js');
29
30
 
30
31
  function _interopNamespaceDefault(e) {
@@ -47,7 +48,7 @@ function _interopNamespaceDefault(e) {
47
48
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
48
49
 
49
50
  // TODO: find a better naming convention for the file that was an index file before
50
- const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCropFinish, onCropStart, onCropCancel, replacementFile, trackedLocation })=>{
51
+ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCropFinish, onCropStart, onCropCancel, replacementFile, trackedLocation, formFocalPoint, onFocalPointStart, onFocalPointFinish, onFocalPointCancel })=>{
51
52
  const CropperjsStyle = styledComponents.createGlobalStyle`${cropperjscss}`;
52
53
  const { trackUsage } = useTracking.useTracking();
53
54
  const previewRef = React__namespace.useRef(null);
@@ -59,6 +60,11 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
59
60
  const [showConfirmDialog, setShowConfirmDialog] = React__namespace.useState(false);
60
61
  const { crop, produceFile, stopCropping, isCropping, isCropperReady, width, height } = useCropImg.useCropImg();
61
62
  const { editAsset, error, isLoading, progress, cancel } = useEditAsset.useEditAsset();
63
+ const [isInFocalPointMode, setIsInFocalPointMode] = React__namespace.useState(false);
64
+ const [focalPoint, setFocalPoint] = React__namespace.useState(formFocalPoint ?? {
65
+ x: 50,
66
+ y: 50
67
+ });
62
68
  const { upload, isLoading: isLoadingUpload, cancel: cancelUpload, error: uploadError, progress: progressUpload } = useUpload.useUpload();
63
69
  React__namespace.useEffect(()=>{
64
70
  // Whenever a replacementUrl is set, make sure to permutate the real asset.url by
@@ -156,6 +162,42 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
156
162
  const handleCropStart = ()=>{
157
163
  setHasCropIntent(true);
158
164
  };
165
+ const calculateFocalPointFromEvent = (e)=>{
166
+ const { clientX, clientY } = e;
167
+ const rect = e.currentTarget.getBoundingClientRect();
168
+ const posX = clientX - rect.left;
169
+ const posY = clientY - rect.top;
170
+ return {
171
+ x: Number((posX / rect.width * 100).toFixed(2)),
172
+ y: Number((posY / rect.height * 100).toFixed(2))
173
+ };
174
+ };
175
+ const handleFocalPointClick = (e)=>{
176
+ if (!isInFocalPointMode) return;
177
+ setFocalPoint(calculateFocalPointFromEvent(e));
178
+ };
179
+ const handleFocalPointCancel = ()=>{
180
+ setIsInFocalPointMode(false);
181
+ setFocalPoint(formFocalPoint ?? {
182
+ x: 50,
183
+ y: 50
184
+ });
185
+ onFocalPointCancel();
186
+ };
187
+ const handleFocalPointStart = ()=>{
188
+ onFocalPointStart();
189
+ setIsInFocalPointMode(true);
190
+ };
191
+ const handleFocalPointValidate = ()=>{
192
+ setIsInFocalPointMode(false);
193
+ onFocalPointFinish(focalPoint);
194
+ };
195
+ const handleFocalPointReset = ()=>{
196
+ setFocalPoint({
197
+ x: 50,
198
+ y: 50
199
+ });
200
+ };
159
201
  return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
160
202
  children: [
161
203
  /*#__PURE__*/ jsxRuntime.jsx(CropperjsStyle, {}),
@@ -169,6 +211,11 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
169
211
  onDuplicate: asset.isLocal ? undefined : handleDuplication,
170
212
  onCancel: handleCropCancel
171
213
  }),
214
+ isInFocalPointMode && /*#__PURE__*/ jsxRuntime.jsx(FocalPointActions.FocalPointActions, {
215
+ onValidate: handleFocalPointValidate,
216
+ onCancel: handleFocalPointCancel,
217
+ onReset: handleFocalPointReset
218
+ }),
172
219
  /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.ActionRow, {
173
220
  paddingLeft: 3,
174
221
  paddingRight: 3,
@@ -202,6 +249,14 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
202
249
  }),
203
250
  onClick: handleCropStart,
204
251
  children: /*#__PURE__*/ jsxRuntime.jsx(icons.Crop, {})
252
+ }),
253
+ canUpdate && asset.mime?.includes(enums.AssetType.Image) && /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
254
+ label: formatMessage({
255
+ id: getTrad.getTrad('control-card.set-focal-point'),
256
+ defaultMessage: 'Set focal point'
257
+ }),
258
+ onClick: handleFocalPointStart,
259
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.PinMap, {})
205
260
  })
206
261
  ]
207
262
  })
@@ -222,37 +277,58 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
222
277
  progress: progressUpload
223
278
  })
224
279
  }),
225
- /*#__PURE__*/ jsxRuntime.jsx(AssetPreview.AssetPreview, {
226
- ref: previewRef,
227
- mime: asset.mime,
228
- name: asset.name,
229
- url: hasCropIntent ? assetUrl : thumbnailUrl,
230
- onLoad: ()=>{
231
- if (asset.isLocal || hasCropIntent) {
232
- setIsCropImageReady(true);
233
- }
234
- }
280
+ /*#__PURE__*/ jsxRuntime.jsxs(PreviewComponents.FocalPointImageWrapper, {
281
+ children: [
282
+ /*#__PURE__*/ jsxRuntime.jsx(AssetPreview.AssetPreview, {
283
+ ref: previewRef,
284
+ mime: asset.mime,
285
+ name: asset.name,
286
+ url: hasCropIntent ? assetUrl : thumbnailUrl,
287
+ onLoad: ()=>{
288
+ if (asset.isLocal || hasCropIntent) {
289
+ setIsCropImageReady(true);
290
+ }
291
+ },
292
+ onClick: handleFocalPointClick,
293
+ style: {
294
+ cursor: isInFocalPointMode ? 'crosshair' : undefined
295
+ }
296
+ }),
297
+ isInFocalPointMode && /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.FocalPointAim, {
298
+ $focalPoint: focalPoint,
299
+ children: /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.FocalPointHalo, {})
300
+ })
301
+ ]
235
302
  })
236
303
  ]
237
304
  }),
238
- /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.ActionRow, {
305
+ /*#__PURE__*/ jsxRuntime.jsxs(PreviewComponents.ActionRow, {
239
306
  paddingLeft: 2,
240
307
  paddingRight: 2,
241
308
  justifyContent: "flex-end",
242
- $blurry: isInCroppingMode,
243
- children: isInCroppingMode && width && height && /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.BadgeOverride, {
244
- background: "neutral900",
245
- color: "neutral0",
246
- children: width && height ? `${height}✕${width}` : 'N/A'
247
- })
309
+ $blurry: isInCroppingMode || isInFocalPointMode,
310
+ children: [
311
+ isInCroppingMode && width && height && /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.BadgeOverride, {
312
+ background: "neutral900",
313
+ color: "neutral0",
314
+ children: width && height ? `${height}✕${width}` : 'N/A'
315
+ }),
316
+ isInFocalPointMode && /*#__PURE__*/ jsxRuntime.jsx(PreviewComponents.BadgeOverride, {
317
+ background: "neutral900",
318
+ color: "neutral0",
319
+ children: `x: ${focalPoint.x}% | y: ${focalPoint.y}%`
320
+ })
321
+ ]
248
322
  })
249
323
  ]
250
324
  }),
251
325
  /*#__PURE__*/ jsxRuntime.jsx(RemoveAssetDialog.RemoveAssetDialog, {
252
326
  open: showConfirmDialog,
253
- onClose: ()=>{
327
+ onClose: (value)=>{
254
328
  setShowConfirmDialog(false);
255
- onDelete(null);
329
+ if (value === null) {
330
+ onDelete(null);
331
+ }
256
332
  },
257
333
  asset: asset
258
334
  })
@@ -1 +1 @@
1
- {"version":3,"file":"PreviewBox.js","sources":["../../../../../admin/src/components/EditAssetDialog/PreviewBox/PreviewBox.tsx"],"sourcesContent":["// TODO: find a better naming convention for the file that was an index file before\nimport * as React from 'react';\n\nimport { Flex, IconButton } from '@strapi/design-system';\nimport { Crop as Resize, Download as DownloadIcon, Trash } from '@strapi/icons';\nimport cropperjscss from 'cropperjs/dist/cropper.css?raw';\nimport { useIntl } from 'react-intl';\nimport { createGlobalStyle } from 'styled-components';\n\nimport { AssetType } from '../../../enums';\nimport { useCropImg } from '../../../hooks/useCropImg';\nimport { useEditAsset } from '../../../hooks/useEditAsset';\nimport { useTracking } from '../../../hooks/useTracking';\nimport { useUpload } from '../../../hooks/useUpload';\nimport { createAssetUrl, getTrad, downloadFile } from '../../../utils';\nimport { CopyLinkButton } from '../../CopyLinkButton/CopyLinkButton';\nimport { UploadProgress } from '../../UploadProgress/UploadProgress';\nimport { RemoveAssetDialog } from '../RemoveAssetDialog';\n\nimport { AssetPreview } from './AssetPreview';\nimport { CroppingActions } from './CroppingActions';\nimport {\n ActionRow,\n BadgeOverride,\n RelativeBox,\n UploadProgressWrapper,\n Wrapper,\n} from './PreviewComponents';\n\nimport type { File as FileDefinition, RawFile } from '../../../../../shared/contracts/files';\n\ninterface Asset extends Omit<FileDefinition, 'folder'> {\n isLocal?: boolean;\n rawFile?: RawFile;\n folder?: FileDefinition['folder'] & { id: number };\n}\n\ninterface PreviewBoxProps {\n asset: Asset;\n canUpdate: boolean;\n canCopyLink: boolean;\n canDownload: boolean;\n replacementFile?: File;\n onDelete: (asset?: Asset | null) => void;\n onCropFinish: () => void;\n onCropStart: () => void;\n onCropCancel: () => void;\n trackedLocation?: string;\n}\n\nexport const PreviewBox = ({\n asset,\n canUpdate,\n canCopyLink,\n canDownload,\n onDelete,\n onCropFinish,\n onCropStart,\n onCropCancel,\n replacementFile,\n trackedLocation,\n}: PreviewBoxProps) => {\n const CropperjsStyle = createGlobalStyle`${cropperjscss}`;\n const { trackUsage } = useTracking();\n const previewRef = React.useRef(null);\n const [isCropImageReady, setIsCropImageReady] = React.useState(false);\n const [hasCropIntent, setHasCropIntent] = React.useState<boolean | null>(null);\n const [assetUrl, setAssetUrl] = React.useState(createAssetUrl(asset, false));\n const [thumbnailUrl, setThumbnailUrl] = React.useState(createAssetUrl(asset, true));\n const { formatMessage } = useIntl();\n const [showConfirmDialog, setShowConfirmDialog] = React.useState(false);\n const { crop, produceFile, stopCropping, isCropping, isCropperReady, width, height } =\n useCropImg();\n const { editAsset, error, isLoading, progress, cancel } = useEditAsset();\n\n const {\n upload,\n isLoading: isLoadingUpload,\n cancel: cancelUpload,\n error: uploadError,\n progress: progressUpload,\n } = useUpload();\n\n React.useEffect(() => {\n // Whenever a replacementUrl is set, make sure to permutate the real asset.url by\n // the locally generated one\n if (replacementFile) {\n const fileLocalUrl = URL.createObjectURL(replacementFile);\n\n if (asset.isLocal) {\n asset.url = fileLocalUrl;\n }\n\n setAssetUrl(fileLocalUrl);\n setThumbnailUrl(fileLocalUrl);\n }\n }, [replacementFile, asset]);\n\n React.useEffect(() => {\n if (hasCropIntent === false) {\n stopCropping();\n onCropCancel();\n }\n }, [hasCropIntent, stopCropping, onCropCancel, onCropFinish]);\n\n React.useEffect(() => {\n if (hasCropIntent && isCropImageReady) {\n crop(previewRef.current!);\n onCropStart();\n }\n }, [isCropImageReady, hasCropIntent, onCropStart, crop]);\n\n const handleCropping = async () => {\n const nextAsset = { ...asset, width, height, folder: asset.folder?.id };\n const file = (await produceFile(nextAsset.name, nextAsset.mime!, nextAsset.updatedAt!)) as File;\n\n // Making sure that when persisting the new asset, the URL changes with width and height\n // So that the browser makes a request and handle the image caching correctly at the good size\n let optimizedCachingImage;\n let optimizedCachingThumbnailImage;\n\n if (asset.isLocal) {\n optimizedCachingImage = URL.createObjectURL(file);\n optimizedCachingThumbnailImage = optimizedCachingImage;\n asset.url = optimizedCachingImage;\n asset.rawFile = file;\n\n trackUsage('didCropFile', { duplicatedFile: null, location: trackedLocation! });\n } else {\n const updatedAsset = await editAsset(nextAsset, file);\n optimizedCachingImage = createAssetUrl(updatedAsset, false);\n optimizedCachingThumbnailImage = createAssetUrl(updatedAsset, true);\n\n trackUsage('didCropFile', { duplicatedFile: false, location: trackedLocation! });\n }\n\n setAssetUrl(optimizedCachingImage);\n setThumbnailUrl(optimizedCachingThumbnailImage);\n setHasCropIntent(false);\n };\n\n const isInCroppingMode = isCropping && !isLoading;\n\n const handleDuplication = async () => {\n const nextAsset = { ...asset, width, height };\n const file = (await produceFile(\n nextAsset.name,\n nextAsset.mime!,\n nextAsset.updatedAt!\n )) as RawFile;\n\n await upload({ name: file.name, rawFile: file }, asset.folder?.id ? asset.folder.id : null);\n\n trackUsage('didCropFile', { duplicatedFile: true, location: trackedLocation! });\n\n setHasCropIntent(false);\n onCropFinish();\n };\n\n const handleCropCancel = () => {\n setHasCropIntent(false);\n };\n\n const handleCropStart = () => {\n setHasCropIntent(true);\n };\n\n return (\n <>\n <CropperjsStyle />\n <RelativeBox hasRadius background=\"neutral150\" borderColor=\"neutral200\">\n {isCropperReady && isInCroppingMode && (\n <CroppingActions\n onValidate={handleCropping}\n onDuplicate={asset.isLocal ? undefined : handleDuplication}\n onCancel={handleCropCancel}\n />\n )}\n\n <ActionRow paddingLeft={3} paddingRight={3} justifyContent=\"flex-end\">\n <Flex gap={1}>\n {canUpdate && !asset.isLocal && (\n <IconButton\n label={formatMessage({\n id: 'global.delete',\n defaultMessage: 'Delete',\n })}\n onClick={() => setShowConfirmDialog(true)}\n >\n <Trash />\n </IconButton>\n )}\n\n {canDownload && (\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.download'),\n defaultMessage: 'Download',\n })}\n onClick={() => downloadFile(assetUrl!, asset.name)}\n >\n <DownloadIcon />\n </IconButton>\n )}\n\n {canCopyLink && <CopyLinkButton url={assetUrl!} />}\n\n {canUpdate && asset.mime?.includes(AssetType.Image) && (\n <IconButton\n label={formatMessage({ id: getTrad('control-card.crop'), defaultMessage: 'Crop' })}\n onClick={handleCropStart}\n >\n <Resize />\n </IconButton>\n )}\n </Flex>\n </ActionRow>\n\n <Wrapper>\n {/* This one is for editting an asset */}\n {isLoading && (\n <UploadProgressWrapper>\n <UploadProgress error={error} onCancel={cancel} progress={progress} />\n </UploadProgressWrapper>\n )}\n\n {/* This one is for duplicating an asset after cropping */}\n {isLoadingUpload && (\n <UploadProgressWrapper>\n <UploadProgress\n error={uploadError}\n onCancel={cancelUpload}\n progress={progressUpload}\n />\n </UploadProgressWrapper>\n )}\n\n <AssetPreview\n ref={previewRef}\n mime={asset.mime!}\n name={asset.name}\n url={hasCropIntent ? assetUrl! : thumbnailUrl!}\n onLoad={() => {\n if (asset.isLocal || hasCropIntent) {\n setIsCropImageReady(true);\n }\n }}\n />\n </Wrapper>\n\n <ActionRow\n paddingLeft={2}\n paddingRight={2}\n justifyContent=\"flex-end\"\n $blurry={isInCroppingMode}\n >\n {isInCroppingMode && width && height && (\n <BadgeOverride background=\"neutral900\" color=\"neutral0\">\n {width && height ? `${height}✕${width}` : 'N/A'}\n </BadgeOverride>\n )}\n </ActionRow>\n </RelativeBox>\n\n <RemoveAssetDialog\n open={showConfirmDialog}\n onClose={() => {\n setShowConfirmDialog(false);\n onDelete(null);\n }}\n asset={asset}\n />\n </>\n );\n};\n"],"names":["PreviewBox","asset","canUpdate","canCopyLink","canDownload","onDelete","onCropFinish","onCropStart","onCropCancel","replacementFile","trackedLocation","CropperjsStyle","createGlobalStyle","cropperjscss","trackUsage","useTracking","previewRef","React","useRef","isCropImageReady","setIsCropImageReady","useState","hasCropIntent","setHasCropIntent","assetUrl","setAssetUrl","createAssetUrl","thumbnailUrl","setThumbnailUrl","formatMessage","useIntl","showConfirmDialog","setShowConfirmDialog","crop","produceFile","stopCropping","isCropping","isCropperReady","width","height","useCropImg","editAsset","error","isLoading","progress","cancel","useEditAsset","upload","isLoadingUpload","cancelUpload","uploadError","progressUpload","useUpload","useEffect","fileLocalUrl","URL","createObjectURL","isLocal","url","current","handleCropping","nextAsset","folder","id","file","name","mime","updatedAt","optimizedCachingImage","optimizedCachingThumbnailImage","rawFile","duplicatedFile","location","updatedAsset","isInCroppingMode","handleDuplication","handleCropCancel","handleCropStart","_jsxs","_Fragment","_jsx","RelativeBox","hasRadius","background","borderColor","CroppingActions","onValidate","onDuplicate","undefined","onCancel","ActionRow","paddingLeft","paddingRight","justifyContent","Flex","gap","IconButton","label","defaultMessage","onClick","Trash","getTrad","downloadFile","DownloadIcon","CopyLinkButton","includes","AssetType","Image","Resize","Wrapper","UploadProgressWrapper","UploadProgress","AssetPreview","ref","onLoad","$blurry","BadgeOverride","color","RemoveAssetDialog","open","onClose"],"mappings":"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"}
1
+ {"version":3,"file":"PreviewBox.js","sources":["../../../../../admin/src/components/EditAssetDialog/PreviewBox/PreviewBox.tsx"],"sourcesContent":["// TODO: find a better naming convention for the file that was an index file before\nimport * as React from 'react';\n\nimport { Flex, IconButton } from '@strapi/design-system';\nimport { Crop as Resize, Download as DownloadIcon, Trash, PinMap } from '@strapi/icons';\nimport cropperjscss from 'cropperjs/dist/cropper.css?raw';\nimport { useIntl } from 'react-intl';\nimport { createGlobalStyle } from 'styled-components';\n\nimport { AssetType } from '../../../enums';\nimport { useCropImg } from '../../../hooks/useCropImg';\nimport { useEditAsset } from '../../../hooks/useEditAsset';\nimport { useTracking } from '../../../hooks/useTracking';\nimport { useUpload } from '../../../hooks/useUpload';\nimport { createAssetUrl, getTrad, downloadFile } from '../../../utils';\nimport { CopyLinkButton } from '../../CopyLinkButton/CopyLinkButton';\nimport { UploadProgress } from '../../UploadProgress/UploadProgress';\nimport { RemoveAssetDialog } from '../RemoveAssetDialog';\n\nimport { AssetPreview } from './AssetPreview';\nimport { CroppingActions } from './CroppingActions';\nimport { FocalPointActions } from './FocalPointActions';\nimport {\n ActionRow,\n BadgeOverride,\n RelativeBox,\n UploadProgressWrapper,\n Wrapper,\n FocalPointImageWrapper,\n FocalPointAim,\n FocalPointHalo,\n} from './PreviewComponents';\n\nimport type {\n File as FileDefinition,\n RawFile,\n FocalPoint,\n} from '../../../../../shared/contracts/files';\n\ninterface Asset extends Omit<FileDefinition, 'folder'> {\n isLocal?: boolean;\n rawFile?: RawFile;\n folder?: FileDefinition['folder'] & { id: number };\n}\n\ninterface PreviewBoxProps {\n asset: Asset;\n canUpdate: boolean;\n canCopyLink: boolean;\n canDownload: boolean;\n replacementFile?: File;\n onDelete: (asset?: Asset | null) => void;\n onCropFinish: () => void;\n onCropStart: () => void;\n onCropCancel: () => void;\n trackedLocation?: string;\n formFocalPoint?: FocalPoint | null;\n onFocalPointStart: () => void;\n onFocalPointFinish: (focalPoint: FocalPoint) => void;\n onFocalPointCancel: () => void;\n}\n\nexport const PreviewBox = ({\n asset,\n canUpdate,\n canCopyLink,\n canDownload,\n onDelete,\n onCropFinish,\n onCropStart,\n onCropCancel,\n replacementFile,\n trackedLocation,\n formFocalPoint,\n onFocalPointStart,\n onFocalPointFinish,\n onFocalPointCancel,\n}: PreviewBoxProps) => {\n const CropperjsStyle = createGlobalStyle`${cropperjscss}`;\n const { trackUsage } = useTracking();\n const previewRef = React.useRef(null);\n const [isCropImageReady, setIsCropImageReady] = React.useState(false);\n const [hasCropIntent, setHasCropIntent] = React.useState<boolean | null>(null);\n const [assetUrl, setAssetUrl] = React.useState(createAssetUrl(asset, false));\n const [thumbnailUrl, setThumbnailUrl] = React.useState(createAssetUrl(asset, true));\n const { formatMessage } = useIntl();\n const [showConfirmDialog, setShowConfirmDialog] = React.useState(false);\n const { crop, produceFile, stopCropping, isCropping, isCropperReady, width, height } =\n useCropImg();\n const { editAsset, error, isLoading, progress, cancel } = useEditAsset();\n const [isInFocalPointMode, setIsInFocalPointMode] = React.useState<boolean>(false);\n const [focalPoint, setFocalPoint] = React.useState<FocalPoint>(\n formFocalPoint ?? { x: 50, y: 50 }\n );\n\n const {\n upload,\n isLoading: isLoadingUpload,\n cancel: cancelUpload,\n error: uploadError,\n progress: progressUpload,\n } = useUpload();\n\n React.useEffect(() => {\n // Whenever a replacementUrl is set, make sure to permutate the real asset.url by\n // the locally generated one\n if (replacementFile) {\n const fileLocalUrl = URL.createObjectURL(replacementFile);\n\n if (asset.isLocal) {\n asset.url = fileLocalUrl;\n }\n\n setAssetUrl(fileLocalUrl);\n setThumbnailUrl(fileLocalUrl);\n }\n }, [replacementFile, asset]);\n\n React.useEffect(() => {\n if (hasCropIntent === false) {\n stopCropping();\n onCropCancel();\n }\n }, [hasCropIntent, stopCropping, onCropCancel, onCropFinish]);\n\n React.useEffect(() => {\n if (hasCropIntent && isCropImageReady) {\n crop(previewRef.current!);\n onCropStart();\n }\n }, [isCropImageReady, hasCropIntent, onCropStart, crop]);\n\n const handleCropping = async () => {\n const nextAsset = { ...asset, width, height, folder: asset.folder?.id };\n const file = (await produceFile(nextAsset.name, nextAsset.mime!, nextAsset.updatedAt!)) as File;\n\n // Making sure that when persisting the new asset, the URL changes with width and height\n // So that the browser makes a request and handle the image caching correctly at the good size\n let optimizedCachingImage;\n let optimizedCachingThumbnailImage;\n\n if (asset.isLocal) {\n optimizedCachingImage = URL.createObjectURL(file);\n optimizedCachingThumbnailImage = optimizedCachingImage;\n asset.url = optimizedCachingImage;\n asset.rawFile = file;\n\n trackUsage('didCropFile', { duplicatedFile: null, location: trackedLocation! });\n } else {\n const updatedAsset = await editAsset(nextAsset, file);\n optimizedCachingImage = createAssetUrl(updatedAsset, false);\n optimizedCachingThumbnailImage = createAssetUrl(updatedAsset, true);\n\n trackUsage('didCropFile', { duplicatedFile: false, location: trackedLocation! });\n }\n\n setAssetUrl(optimizedCachingImage);\n setThumbnailUrl(optimizedCachingThumbnailImage);\n setHasCropIntent(false);\n };\n\n const isInCroppingMode = isCropping && !isLoading;\n\n const handleDuplication = async () => {\n const nextAsset = { ...asset, width, height };\n const file = (await produceFile(\n nextAsset.name,\n nextAsset.mime!,\n nextAsset.updatedAt!\n )) as RawFile;\n\n await upload({ name: file.name, rawFile: file }, asset.folder?.id ? asset.folder.id : null);\n\n trackUsage('didCropFile', { duplicatedFile: true, location: trackedLocation! });\n\n setHasCropIntent(false);\n onCropFinish();\n };\n\n const handleCropCancel = () => {\n setHasCropIntent(false);\n };\n\n const handleCropStart = () => {\n setHasCropIntent(true);\n };\n\n const calculateFocalPointFromEvent = (e: React.MouseEvent<HTMLElement>): FocalPoint => {\n const { clientX, clientY } = e;\n const rect = e.currentTarget.getBoundingClientRect();\n const posX = clientX - rect.left;\n const posY = clientY - rect.top;\n\n return {\n x: Number(((posX / rect.width) * 100).toFixed(2)),\n y: Number(((posY / rect.height) * 100).toFixed(2)),\n };\n };\n\n const handleFocalPointClick = (e: React.MouseEvent<HTMLElement>) => {\n if (!isInFocalPointMode) return;\n setFocalPoint(calculateFocalPointFromEvent(e));\n };\n\n const handleFocalPointCancel = () => {\n setIsInFocalPointMode(false);\n setFocalPoint(formFocalPoint ?? { x: 50, y: 50 });\n onFocalPointCancel();\n };\n\n const handleFocalPointStart = () => {\n onFocalPointStart();\n setIsInFocalPointMode(true);\n };\n\n const handleFocalPointValidate = () => {\n setIsInFocalPointMode(false);\n onFocalPointFinish(focalPoint);\n };\n\n const handleFocalPointReset = () => {\n setFocalPoint({ x: 50, y: 50 });\n };\n\n return (\n <>\n <CropperjsStyle />\n <RelativeBox hasRadius background=\"neutral150\" borderColor=\"neutral200\">\n {isCropperReady && isInCroppingMode && (\n <CroppingActions\n onValidate={handleCropping}\n onDuplicate={asset.isLocal ? undefined : handleDuplication}\n onCancel={handleCropCancel}\n />\n )}\n\n {isInFocalPointMode && (\n <FocalPointActions\n onValidate={handleFocalPointValidate}\n onCancel={handleFocalPointCancel}\n onReset={handleFocalPointReset}\n />\n )}\n\n <ActionRow paddingLeft={3} paddingRight={3} justifyContent=\"flex-end\">\n <Flex gap={1}>\n {canUpdate && !asset.isLocal && (\n <IconButton\n label={formatMessage({\n id: 'global.delete',\n defaultMessage: 'Delete',\n })}\n onClick={() => setShowConfirmDialog(true)}\n >\n <Trash />\n </IconButton>\n )}\n\n {canDownload && (\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.download'),\n defaultMessage: 'Download',\n })}\n onClick={() => downloadFile(assetUrl!, asset.name)}\n >\n <DownloadIcon />\n </IconButton>\n )}\n\n {canCopyLink && <CopyLinkButton url={assetUrl!} />}\n\n {canUpdate && asset.mime?.includes(AssetType.Image) && (\n <IconButton\n label={formatMessage({ id: getTrad('control-card.crop'), defaultMessage: 'Crop' })}\n onClick={handleCropStart}\n >\n <Resize />\n </IconButton>\n )}\n\n {canUpdate && asset.mime?.includes(AssetType.Image) && (\n <IconButton\n label={formatMessage({\n id: getTrad('control-card.set-focal-point'),\n defaultMessage: 'Set focal point',\n })}\n onClick={handleFocalPointStart}\n >\n <PinMap />\n </IconButton>\n )}\n </Flex>\n </ActionRow>\n\n <Wrapper>\n {/* This one is for editting an asset */}\n {isLoading && (\n <UploadProgressWrapper>\n <UploadProgress error={error} onCancel={cancel} progress={progress} />\n </UploadProgressWrapper>\n )}\n\n {/* This one is for duplicating an asset after cropping */}\n {isLoadingUpload && (\n <UploadProgressWrapper>\n <UploadProgress\n error={uploadError}\n onCancel={cancelUpload}\n progress={progressUpload}\n />\n </UploadProgressWrapper>\n )}\n\n <FocalPointImageWrapper>\n <AssetPreview\n ref={previewRef}\n mime={asset.mime!}\n name={asset.name}\n url={hasCropIntent ? assetUrl! : thumbnailUrl!}\n onLoad={() => {\n if (asset.isLocal || hasCropIntent) {\n setIsCropImageReady(true);\n }\n }}\n onClick={handleFocalPointClick}\n style={{ cursor: isInFocalPointMode ? 'crosshair' : undefined }}\n />\n\n {/* Show the set focal point marker */}\n {isInFocalPointMode && (\n <FocalPointAim $focalPoint={focalPoint}>\n <FocalPointHalo />\n </FocalPointAim>\n )}\n </FocalPointImageWrapper>\n </Wrapper>\n\n <ActionRow\n paddingLeft={2}\n paddingRight={2}\n justifyContent=\"flex-end\"\n $blurry={isInCroppingMode || isInFocalPointMode}\n >\n {isInCroppingMode && width && height && (\n <BadgeOverride background=\"neutral900\" color=\"neutral0\">\n {width && height ? `${height}✕${width}` : 'N/A'}\n </BadgeOverride>\n )}\n {isInFocalPointMode && (\n <BadgeOverride background=\"neutral900\" color=\"neutral0\">\n {`x: ${focalPoint.x}% | y: ${focalPoint.y}%`}\n </BadgeOverride>\n )}\n </ActionRow>\n </RelativeBox>\n\n <RemoveAssetDialog\n open={showConfirmDialog}\n onClose={(value) => {\n setShowConfirmDialog(false);\n if (value === null) {\n onDelete(null);\n }\n }}\n asset={asset}\n />\n </>\n );\n};\n"],"names":["PreviewBox","asset","canUpdate","canCopyLink","canDownload","onDelete","onCropFinish","onCropStart","onCropCancel","replacementFile","trackedLocation","formFocalPoint","onFocalPointStart","onFocalPointFinish","onFocalPointCancel","CropperjsStyle","createGlobalStyle","cropperjscss","trackUsage","useTracking","previewRef","React","useRef","isCropImageReady","setIsCropImageReady","useState","hasCropIntent","setHasCropIntent","assetUrl","setAssetUrl","createAssetUrl","thumbnailUrl","setThumbnailUrl","formatMessage","useIntl","showConfirmDialog","setShowConfirmDialog","crop","produceFile","stopCropping","isCropping","isCropperReady","width","height","useCropImg","editAsset","error","isLoading","progress","cancel","useEditAsset","isInFocalPointMode","setIsInFocalPointMode","focalPoint","setFocalPoint","x","y","upload","isLoadingUpload","cancelUpload","uploadError","progressUpload","useUpload","useEffect","fileLocalUrl","URL","createObjectURL","isLocal","url","current","handleCropping","nextAsset","folder","id","file","name","mime","updatedAt","optimizedCachingImage","optimizedCachingThumbnailImage","rawFile","duplicatedFile","location","updatedAsset","isInCroppingMode","handleDuplication","handleCropCancel","handleCropStart","calculateFocalPointFromEvent","e","clientX","clientY","rect","currentTarget","getBoundingClientRect","posX","left","posY","top","Number","toFixed","handleFocalPointClick","handleFocalPointCancel","handleFocalPointStart","handleFocalPointValidate","handleFocalPointReset","_jsxs","_Fragment","_jsx","RelativeBox","hasRadius","background","borderColor","CroppingActions","onValidate","onDuplicate","undefined","onCancel","FocalPointActions","onReset","ActionRow","paddingLeft","paddingRight","justifyContent","Flex","gap","IconButton","label","defaultMessage","onClick","Trash","getTrad","downloadFile","DownloadIcon","CopyLinkButton","includes","AssetType","Image","Resize","PinMap","Wrapper","UploadProgressWrapper","UploadProgress","FocalPointImageWrapper","AssetPreview","ref","onLoad","style","cursor","FocalPointAim","$focalPoint","FocalPointHalo","$blurry","BadgeOverride","color","RemoveAssetDialog","open","onClose","value"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { Flex, IconButton } from '@strapi/design-system';
4
- import { Trash, Download, Crop } from '@strapi/icons';
4
+ import { Trash, Download, Crop, PinMap } from '@strapi/icons';
5
5
  import cropperjscss from 'cropperjs/dist/cropper.css?raw';
6
6
  import { useIntl } from 'react-intl';
7
7
  import { createGlobalStyle } from 'styled-components';
@@ -23,10 +23,11 @@ import { UploadProgress } from '../../UploadProgress/UploadProgress.mjs';
23
23
  import { RemoveAssetDialog } from '../RemoveAssetDialog.mjs';
24
24
  import { AssetPreview } from './AssetPreview.mjs';
25
25
  import { CroppingActions } from './CroppingActions.mjs';
26
- import { RelativeBox, ActionRow, Wrapper, UploadProgressWrapper, BadgeOverride } from './PreviewComponents.mjs';
26
+ import { FocalPointActions } from './FocalPointActions.mjs';
27
+ import { RelativeBox, ActionRow, Wrapper, UploadProgressWrapper, FocalPointImageWrapper, FocalPointAim, FocalPointHalo, BadgeOverride } from './PreviewComponents.mjs';
27
28
 
28
29
  // TODO: find a better naming convention for the file that was an index file before
29
- const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCropFinish, onCropStart, onCropCancel, replacementFile, trackedLocation })=>{
30
+ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCropFinish, onCropStart, onCropCancel, replacementFile, trackedLocation, formFocalPoint, onFocalPointStart, onFocalPointFinish, onFocalPointCancel })=>{
30
31
  const CropperjsStyle = createGlobalStyle`${cropperjscss}`;
31
32
  const { trackUsage } = useTracking();
32
33
  const previewRef = React.useRef(null);
@@ -38,6 +39,11 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
38
39
  const [showConfirmDialog, setShowConfirmDialog] = React.useState(false);
39
40
  const { crop, produceFile, stopCropping, isCropping, isCropperReady, width, height } = useCropImg();
40
41
  const { editAsset, error, isLoading, progress, cancel } = useEditAsset();
42
+ const [isInFocalPointMode, setIsInFocalPointMode] = React.useState(false);
43
+ const [focalPoint, setFocalPoint] = React.useState(formFocalPoint ?? {
44
+ x: 50,
45
+ y: 50
46
+ });
41
47
  const { upload, isLoading: isLoadingUpload, cancel: cancelUpload, error: uploadError, progress: progressUpload } = useUpload();
42
48
  React.useEffect(()=>{
43
49
  // Whenever a replacementUrl is set, make sure to permutate the real asset.url by
@@ -135,6 +141,42 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
135
141
  const handleCropStart = ()=>{
136
142
  setHasCropIntent(true);
137
143
  };
144
+ const calculateFocalPointFromEvent = (e)=>{
145
+ const { clientX, clientY } = e;
146
+ const rect = e.currentTarget.getBoundingClientRect();
147
+ const posX = clientX - rect.left;
148
+ const posY = clientY - rect.top;
149
+ return {
150
+ x: Number((posX / rect.width * 100).toFixed(2)),
151
+ y: Number((posY / rect.height * 100).toFixed(2))
152
+ };
153
+ };
154
+ const handleFocalPointClick = (e)=>{
155
+ if (!isInFocalPointMode) return;
156
+ setFocalPoint(calculateFocalPointFromEvent(e));
157
+ };
158
+ const handleFocalPointCancel = ()=>{
159
+ setIsInFocalPointMode(false);
160
+ setFocalPoint(formFocalPoint ?? {
161
+ x: 50,
162
+ y: 50
163
+ });
164
+ onFocalPointCancel();
165
+ };
166
+ const handleFocalPointStart = ()=>{
167
+ onFocalPointStart();
168
+ setIsInFocalPointMode(true);
169
+ };
170
+ const handleFocalPointValidate = ()=>{
171
+ setIsInFocalPointMode(false);
172
+ onFocalPointFinish(focalPoint);
173
+ };
174
+ const handleFocalPointReset = ()=>{
175
+ setFocalPoint({
176
+ x: 50,
177
+ y: 50
178
+ });
179
+ };
138
180
  return /*#__PURE__*/ jsxs(Fragment, {
139
181
  children: [
140
182
  /*#__PURE__*/ jsx(CropperjsStyle, {}),
@@ -148,6 +190,11 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
148
190
  onDuplicate: asset.isLocal ? undefined : handleDuplication,
149
191
  onCancel: handleCropCancel
150
192
  }),
193
+ isInFocalPointMode && /*#__PURE__*/ jsx(FocalPointActions, {
194
+ onValidate: handleFocalPointValidate,
195
+ onCancel: handleFocalPointCancel,
196
+ onReset: handleFocalPointReset
197
+ }),
151
198
  /*#__PURE__*/ jsx(ActionRow, {
152
199
  paddingLeft: 3,
153
200
  paddingRight: 3,
@@ -181,6 +228,14 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
181
228
  }),
182
229
  onClick: handleCropStart,
183
230
  children: /*#__PURE__*/ jsx(Crop, {})
231
+ }),
232
+ canUpdate && asset.mime?.includes(AssetType.Image) && /*#__PURE__*/ jsx(IconButton, {
233
+ label: formatMessage({
234
+ id: getTrad('control-card.set-focal-point'),
235
+ defaultMessage: 'Set focal point'
236
+ }),
237
+ onClick: handleFocalPointStart,
238
+ children: /*#__PURE__*/ jsx(PinMap, {})
184
239
  })
185
240
  ]
186
241
  })
@@ -201,37 +256,58 @@ const PreviewBox = ({ asset, canUpdate, canCopyLink, canDownload, onDelete, onCr
201
256
  progress: progressUpload
202
257
  })
203
258
  }),
204
- /*#__PURE__*/ jsx(AssetPreview, {
205
- ref: previewRef,
206
- mime: asset.mime,
207
- name: asset.name,
208
- url: hasCropIntent ? assetUrl : thumbnailUrl,
209
- onLoad: ()=>{
210
- if (asset.isLocal || hasCropIntent) {
211
- setIsCropImageReady(true);
212
- }
213
- }
259
+ /*#__PURE__*/ jsxs(FocalPointImageWrapper, {
260
+ children: [
261
+ /*#__PURE__*/ jsx(AssetPreview, {
262
+ ref: previewRef,
263
+ mime: asset.mime,
264
+ name: asset.name,
265
+ url: hasCropIntent ? assetUrl : thumbnailUrl,
266
+ onLoad: ()=>{
267
+ if (asset.isLocal || hasCropIntent) {
268
+ setIsCropImageReady(true);
269
+ }
270
+ },
271
+ onClick: handleFocalPointClick,
272
+ style: {
273
+ cursor: isInFocalPointMode ? 'crosshair' : undefined
274
+ }
275
+ }),
276
+ isInFocalPointMode && /*#__PURE__*/ jsx(FocalPointAim, {
277
+ $focalPoint: focalPoint,
278
+ children: /*#__PURE__*/ jsx(FocalPointHalo, {})
279
+ })
280
+ ]
214
281
  })
215
282
  ]
216
283
  }),
217
- /*#__PURE__*/ jsx(ActionRow, {
284
+ /*#__PURE__*/ jsxs(ActionRow, {
218
285
  paddingLeft: 2,
219
286
  paddingRight: 2,
220
287
  justifyContent: "flex-end",
221
- $blurry: isInCroppingMode,
222
- children: isInCroppingMode && width && height && /*#__PURE__*/ jsx(BadgeOverride, {
223
- background: "neutral900",
224
- color: "neutral0",
225
- children: width && height ? `${height}✕${width}` : 'N/A'
226
- })
288
+ $blurry: isInCroppingMode || isInFocalPointMode,
289
+ children: [
290
+ isInCroppingMode && width && height && /*#__PURE__*/ jsx(BadgeOverride, {
291
+ background: "neutral900",
292
+ color: "neutral0",
293
+ children: width && height ? `${height}✕${width}` : 'N/A'
294
+ }),
295
+ isInFocalPointMode && /*#__PURE__*/ jsx(BadgeOverride, {
296
+ background: "neutral900",
297
+ color: "neutral0",
298
+ children: `x: ${focalPoint.x}% | y: ${focalPoint.y}%`
299
+ })
300
+ ]
227
301
  })
228
302
  ]
229
303
  }),
230
304
  /*#__PURE__*/ jsx(RemoveAssetDialog, {
231
305
  open: showConfirmDialog,
232
- onClose: ()=>{
306
+ onClose: (value)=>{
233
307
  setShowConfirmDialog(false);
234
- onDelete(null);
308
+ if (value === null) {
309
+ onDelete(null);
310
+ }
235
311
  },
236
312
  asset: asset
237
313
  })