@strapi/upload 5.59.0 → 5.60.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 (231) hide show
  1. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js +434 -0
  2. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.js.map +1 -0
  3. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs +432 -0
  4. package/dist/admin/components/AssetPickerDialog/AssetPickerDialog.mjs.map +1 -0
  5. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js +91 -0
  6. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.js.map +1 -0
  7. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs +89 -0
  8. package/dist/admin/components/AssetPickerDialog/FolderBreadcrumbs.mjs.map +1 -0
  9. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js +178 -0
  10. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.js.map +1 -0
  11. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs +175 -0
  12. package/dist/admin/components/AssetPickerDialog/PickerSelectionProvider.mjs.map +1 -0
  13. package/dist/admin/components/AssetPickerDialog/SortableSelection.js +143 -0
  14. package/dist/admin/components/AssetPickerDialog/SortableSelection.js.map +1 -0
  15. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs +141 -0
  16. package/dist/admin/components/AssetPickerDialog/SortableSelection.mjs.map +1 -0
  17. package/dist/admin/components/AssetPickerDialog/pickerSelection.js +49 -0
  18. package/dist/admin/components/AssetPickerDialog/pickerSelection.js.map +1 -0
  19. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs +41 -0
  20. package/dist/admin/components/AssetPickerDialog/pickerSelection.mjs.map +1 -0
  21. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +4 -3
  22. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -1
  23. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +4 -3
  24. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -1
  25. package/dist/admin/components/MediaLibraryInput/AssetCard.js +240 -0
  26. package/dist/admin/components/MediaLibraryInput/AssetCard.js.map +1 -0
  27. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs +237 -0
  28. package/dist/admin/components/MediaLibraryInput/AssetCard.mjs.map +1 -0
  29. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js +161 -0
  30. package/dist/admin/components/MediaLibraryInput/AssetCarousel.js.map +1 -0
  31. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs +159 -0
  32. package/dist/admin/components/MediaLibraryInput/AssetCarousel.mjs.map +1 -0
  33. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +76 -49
  34. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -1
  35. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +77 -50
  36. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -1
  37. package/dist/admin/components/MediaLibraryInput/AssetPreview.js +109 -0
  38. package/dist/admin/components/MediaLibraryInput/AssetPreview.js.map +1 -0
  39. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs +106 -0
  40. package/dist/admin/components/MediaLibraryInput/AssetPreview.mjs.map +1 -0
  41. package/dist/admin/components/MediaLibraryInput/AssetRow.js +146 -79
  42. package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -1
  43. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +148 -82
  44. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -1
  45. package/dist/admin/components/MediaLibraryInput/FieldControls.js +32 -0
  46. package/dist/admin/components/MediaLibraryInput/FieldControls.js.map +1 -0
  47. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs +29 -0
  48. package/dist/admin/components/MediaLibraryInput/FieldControls.mjs.map +1 -0
  49. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +130 -88
  50. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
  51. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +129 -91
  52. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
  53. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js +42 -0
  54. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.js.map +1 -0
  55. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs +40 -0
  56. package/dist/admin/components/MediaLibraryInput/UploadProgressBar.mjs.map +1 -0
  57. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js +122 -0
  58. package/dist/admin/components/MediaLibraryInput/useFieldUploads.js.map +1 -0
  59. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs +120 -0
  60. package/dist/admin/components/MediaLibraryInput/useFieldUploads.mjs.map +1 -0
  61. package/dist/admin/components/UploadProgressDialog.js +2 -1
  62. package/dist/admin/components/UploadProgressDialog.js.map +1 -1
  63. package/dist/admin/components/UploadProgressDialog.mjs +2 -1
  64. package/dist/admin/components/UploadProgressDialog.mjs.map +1 -1
  65. package/dist/admin/hooks/useMediaLibraryPermissions.js +12 -2
  66. package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
  67. package/dist/admin/hooks/useMediaLibraryPermissions.mjs +12 -2
  68. package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
  69. package/dist/admin/pages/Assets/AssetsPage.js +13 -302
  70. package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
  71. package/dist/admin/pages/Assets/AssetsPage.mjs +11 -280
  72. package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
  73. package/dist/admin/pages/Assets/components/AssetsGrid.js +142 -31
  74. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  75. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +145 -34
  76. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  77. package/dist/admin/pages/Assets/components/AssetsSearchInput.js +43 -2
  78. package/dist/admin/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  79. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs +45 -4
  80. package/dist/admin/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  81. package/dist/admin/pages/Assets/components/AssetsTable.js +58 -34
  82. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  83. package/dist/admin/pages/Assets/components/AssetsTable.mjs +60 -36
  84. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  85. package/dist/admin/pages/Assets/components/AssetsView.js +145 -0
  86. package/dist/admin/pages/Assets/components/AssetsView.js.map +1 -0
  87. package/dist/admin/pages/Assets/components/AssetsView.mjs +143 -0
  88. package/dist/admin/pages/Assets/components/AssetsView.mjs.map +1 -0
  89. package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +1 -1
  90. package/dist/admin/pages/Assets/components/BusyOverlay.mjs +1 -1
  91. package/dist/admin/pages/Assets/components/Dnd/DragOverlayChip.mjs +1 -1
  92. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js +40 -0
  93. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.js.map +1 -0
  94. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs +38 -0
  95. package/dist/admin/pages/Assets/components/Dnd/ReorderHandle.mjs.map +1 -0
  96. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js +29 -0
  97. package/dist/admin/pages/Assets/components/Dnd/assetSortable.js.map +1 -0
  98. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs +24 -0
  99. package/dist/admin/pages/Assets/components/Dnd/assetSortable.mjs.map +1 -0
  100. package/dist/admin/pages/Assets/components/Dnd/dndIds.js +5 -0
  101. package/dist/admin/pages/Assets/components/Dnd/dndIds.js.map +1 -1
  102. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs +5 -1
  103. package/dist/admin/pages/Assets/components/Dnd/dndIds.mjs.map +1 -1
  104. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js +41 -13
  105. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  106. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs +41 -13
  107. package/dist/admin/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  108. package/dist/admin/pages/Assets/components/FilterBadges.mjs +2 -2
  109. package/dist/admin/pages/Assets/components/FilterMenu.mjs +2 -2
  110. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js +274 -55
  111. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  112. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs +277 -59
  113. package/dist/admin/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  114. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js +32 -0
  115. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.js.map +1 -0
  116. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs +29 -0
  117. package/dist/admin/pages/Assets/components/FolderTree/collapsedBranch.mjs.map +1 -0
  118. package/dist/admin/pages/Assets/components/ViewToggle.js +126 -0
  119. package/dist/admin/pages/Assets/components/ViewToggle.js.map +1 -0
  120. package/dist/admin/pages/Assets/components/ViewToggle.mjs +104 -0
  121. package/dist/admin/pages/Assets/components/ViewToggle.mjs.map +1 -0
  122. package/dist/admin/pages/Assets/hooks/useAssetSearch.js +2 -2
  123. package/dist/admin/pages/Assets/hooks/useAssetSearch.js.map +1 -1
  124. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs +2 -2
  125. package/dist/admin/pages/Assets/hooks/useAssetSearch.mjs.map +1 -1
  126. package/dist/admin/pages/Assets/hooks/useAssetSelection.js +19 -1
  127. package/dist/admin/pages/Assets/hooks/useAssetSelection.js.map +1 -1
  128. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs +20 -3
  129. package/dist/admin/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
  130. package/dist/admin/pages/Assets/hooks/useAssetsList.js +87 -0
  131. package/dist/admin/pages/Assets/hooks/useAssetsList.js.map +1 -0
  132. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs +85 -0
  133. package/dist/admin/pages/Assets/hooks/useAssetsList.mjs.map +1 -0
  134. package/dist/admin/pages/Assets/hooks/useBusyAssets.mjs +1 -1
  135. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js +2 -1
  136. package/dist/admin/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  137. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs +3 -2
  138. package/dist/admin/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  139. package/dist/admin/pages/Assets/hooks/useListFilters.js +2 -1
  140. package/dist/admin/pages/Assets/hooks/useListFilters.js.map +1 -1
  141. package/dist/admin/pages/Assets/hooks/useListFilters.mjs +3 -2
  142. package/dist/admin/pages/Assets/hooks/useListFilters.mjs.map +1 -1
  143. package/dist/admin/pages/Assets/hooks/useListQueryParams.js +80 -0
  144. package/dist/admin/pages/Assets/hooks/useListQueryParams.js.map +1 -0
  145. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs +77 -0
  146. package/dist/admin/pages/Assets/hooks/useListQueryParams.mjs.map +1 -0
  147. package/dist/admin/pages/Assets/hooks/useListSettings.js +32 -0
  148. package/dist/admin/pages/Assets/hooks/useListSettings.js.map +1 -0
  149. package/dist/admin/pages/Assets/hooks/useListSettings.mjs +29 -0
  150. package/dist/admin/pages/Assets/hooks/useListSettings.mjs.map +1 -0
  151. package/dist/admin/pages/Assets/hooks/useListSort.js +2 -1
  152. package/dist/admin/pages/Assets/hooks/useListSort.js.map +1 -1
  153. package/dist/admin/pages/Assets/hooks/useListSort.mjs +3 -2
  154. package/dist/admin/pages/Assets/hooks/useListSort.mjs.map +1 -1
  155. package/dist/admin/services/api.js +92 -7
  156. package/dist/admin/services/api.js.map +1 -1
  157. package/dist/admin/services/api.mjs +91 -9
  158. package/dist/admin/services/api.mjs.map +1 -1
  159. package/dist/admin/src/components/AssetPickerDialog/AssetPickerDialog.d.ts +19 -0
  160. package/dist/admin/src/components/AssetPickerDialog/FolderBreadcrumbs.d.ts +10 -0
  161. package/dist/admin/src/components/AssetPickerDialog/PickerSelectionProvider.d.ts +28 -0
  162. package/dist/admin/src/components/AssetPickerDialog/SortableSelection.d.ts +12 -0
  163. package/dist/admin/src/components/AssetPickerDialog/pickerSelection.d.ts +26 -0
  164. package/dist/admin/src/components/MediaLibraryInput/AssetCard.d.ts +25 -0
  165. package/dist/admin/src/components/MediaLibraryInput/AssetCarousel.d.ts +16 -0
  166. package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +11 -3
  167. package/dist/admin/src/components/MediaLibraryInput/AssetPreview.d.ts +17 -0
  168. package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +13 -3
  169. package/dist/admin/src/components/MediaLibraryInput/FieldControls.d.ts +19 -0
  170. package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +3 -1
  171. package/dist/admin/src/components/MediaLibraryInput/UploadProgressBar.d.ts +7 -0
  172. package/dist/admin/src/components/MediaLibraryInput/useFieldUploads.d.ts +31 -0
  173. package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +2 -0
  174. package/dist/admin/src/pages/Assets/components/AssetsGrid.d.ts +3 -1
  175. package/dist/admin/src/pages/Assets/components/AssetsSearchInput.d.ts +11 -1
  176. package/dist/admin/src/pages/Assets/components/AssetsView.d.ts +29 -0
  177. package/dist/admin/src/pages/Assets/components/Dnd/ReorderHandle.d.ts +12 -0
  178. package/dist/admin/src/pages/Assets/components/Dnd/assetSortable.d.ts +37 -0
  179. package/dist/admin/src/pages/Assets/components/Dnd/dndIds.d.ts +5 -0
  180. package/dist/admin/src/pages/Assets/components/Dnd/useAssetDnd.d.ts +23 -2
  181. package/dist/admin/src/pages/Assets/components/FolderTree/FolderTree.d.ts +1 -0
  182. package/dist/admin/src/pages/Assets/components/FolderTree/collapsedBranch.d.ts +21 -0
  183. package/dist/admin/src/pages/Assets/components/ViewToggle.d.ts +8 -0
  184. package/dist/admin/src/pages/Assets/hooks/useAssetSelection.d.ts +26 -0
  185. package/dist/admin/src/pages/Assets/hooks/useAssetsList.d.ts +30 -0
  186. package/dist/admin/src/pages/Assets/hooks/useListQueryParams.d.ts +27 -0
  187. package/dist/admin/src/pages/Assets/hooks/useListSettings.d.ts +29 -0
  188. package/dist/admin/src/services/api.d.ts +24 -1
  189. package/dist/admin/src/store/uploadProgress.d.ts +14 -1
  190. package/dist/admin/src/utils/findFolderPath.d.ts +6 -0
  191. package/dist/admin/src/utils/isAllowedAssetType.d.ts +14 -0
  192. package/dist/admin/store/uploadProgress.js +30 -3
  193. package/dist/admin/store/uploadProgress.js.map +1 -1
  194. package/dist/admin/store/uploadProgress.mjs +29 -4
  195. package/dist/admin/store/uploadProgress.mjs.map +1 -1
  196. package/dist/admin/translations/en.json.js +20 -0
  197. package/dist/admin/translations/en.json.js.map +1 -1
  198. package/dist/admin/translations/en.json.mjs +20 -0
  199. package/dist/admin/translations/en.json.mjs.map +1 -1
  200. package/dist/admin/utils/findFolderPath.js +26 -0
  201. package/dist/admin/utils/findFolderPath.js.map +1 -0
  202. package/dist/admin/utils/findFolderPath.mjs +24 -0
  203. package/dist/admin/utils/findFolderPath.mjs.map +1 -0
  204. package/dist/admin/utils/isAllowedAssetType.js +33 -0
  205. package/dist/admin/utils/isAllowedAssetType.js.map +1 -0
  206. package/dist/admin/utils/isAllowedAssetType.mjs +31 -0
  207. package/dist/admin/utils/isAllowedAssetType.mjs.map +1 -0
  208. package/dist/server/controllers/admin-settings.js +5 -1
  209. package/dist/server/controllers/admin-settings.js.map +1 -1
  210. package/dist/server/controllers/admin-settings.mjs +5 -1
  211. package/dist/server/controllers/admin-settings.mjs.map +1 -1
  212. package/dist/server/services/image-manipulation.js +2 -2
  213. package/dist/server/services/image-manipulation.js.map +1 -1
  214. package/dist/server/services/image-manipulation.mjs +2 -2
  215. package/dist/server/services/image-manipulation.mjs.map +1 -1
  216. package/dist/server/services/upload.js.map +1 -1
  217. package/dist/server/services/upload.mjs.map +1 -1
  218. package/dist/server/src/controllers/admin-settings.d.ts.map +1 -1
  219. package/dist/server/src/index.d.ts +1 -1
  220. package/dist/server/src/services/extensions/utils.d.ts +11 -11
  221. package/dist/server/src/services/image-manipulation.d.ts +1 -1
  222. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  223. package/dist/server/src/services/index.d.ts +1 -1
  224. package/dist/server/src/types.d.ts +63 -12
  225. package/dist/server/src/types.d.ts.map +1 -1
  226. package/package.json +8 -6
  227. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +0 -45
  228. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +0 -1
  229. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +0 -43
  230. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +0 -1
  231. package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +0 -10
@@ -0,0 +1,161 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+ var strapiAdmin = require('@strapi/admin/strapi-admin');
6
+ var designSystem = require('@strapi/design-system');
7
+ var icons = require('@strapi/icons');
8
+ var reactIntl = require('react-intl');
9
+ var styledComponents = require('styled-components');
10
+ var translations = require('../../utils/translations.js');
11
+
12
+ /** Narrowest a card and the tile get side by side before stacking, in px. */ const MIN_CARD_WIDTH = 130;
13
+ /**
14
+ * Narrowest a card gets when two share the row, in px. Wider than the single
15
+ * card's, so the row drops to one card before names are cut to a few letters.
16
+ */ const MIN_CARD_WIDTH_FOR_TWO = 180;
17
+ const GAP = 16;
18
+ const MAX_CARDS = 2;
19
+ const Container = styledComponents.styled(designSystem.Box)`
20
+ background: ${({ theme })=>theme.colors.neutral100};
21
+ border: 1px solid ${({ theme })=>theme.colors.neutral200};
22
+ border-radius: ${({ theme })=>theme.borderRadius};
23
+ `;
24
+ const Track = styledComponents.styled.div`
25
+ display: grid;
26
+ grid-template-columns: repeat(${({ $columns })=>$columns}, minmax(0, 1fr));
27
+ gap: ${GAP}px;
28
+ `;
29
+ const Cards = styledComponents.styled.div`
30
+ position: relative;
31
+ display: grid;
32
+ grid-column: span ${({ $columns })=>$columns};
33
+ grid-template-columns: repeat(${({ $columns })=>$columns}, minmax(0, 1fr));
34
+ gap: ${GAP}px;
35
+ `;
36
+ const Arrow = styledComponents.styled(designSystem.Box)`
37
+ position: absolute;
38
+ top: 50%;
39
+ transform: translateY(-50%);
40
+ z-index: 1;
41
+ ${({ $side })=>$side === 'start' ? 'left: -1.6rem;' : 'right: -1.6rem;'}
42
+
43
+ button {
44
+ border-radius: 50%;
45
+ box-shadow: ${({ theme })=>theme.shadows.filterShadow};
46
+ }
47
+ `;
48
+ /**
49
+ * How the row fits the field. The edit layout's size sets it: a third of the
50
+ * form stacks one card over the drop zone, a full-width field shows two cards
51
+ * beside it, anything in between one. Mobile always shows one card, stacked on
52
+ * a phone. The measured width can only take cards away, for a field squeezed
53
+ * by a narrow component.
54
+ */ const getRowLayout = ({ width, layoutSize, isMobile, isPhone })=>{
55
+ const isNarrowLayout = isPhone || layoutSize !== undefined && layoutSize <= 4;
56
+ const maxCards = isMobile || layoutSize !== undefined && layoutSize < 12 ? 1 : MAX_CARDS;
57
+ // Unmeasured: no layout yet, or no `ResizeObserver`.
58
+ const isMeasured = width > 0;
59
+ const fitsCardAndTile = !isMeasured || width >= 2 * MIN_CARD_WIDTH + GAP;
60
+ const fitsTwoCardsAndTile = !isMeasured || width >= 3 * MIN_CARD_WIDTH_FOR_TWO + 2 * GAP;
61
+ if (isNarrowLayout || !fitsCardAndTile) {
62
+ return {
63
+ cards: 1,
64
+ isStacked: true
65
+ };
66
+ }
67
+ return {
68
+ cards: fitsTwoCardsAndTile ? maxCards : 1,
69
+ isStacked: false
70
+ };
71
+ };
72
+ /**
73
+ * A single row of cards followed by the drop tile. When the field holds more
74
+ * than fit, arrows page through the cards and the tile stays put.
75
+ */ const AssetCarousel = ({ children, renderDropZone, layoutSize })=>{
76
+ const { formatMessage } = reactIntl.useIntl();
77
+ const theme = styledComponents.useTheme();
78
+ const isMobile = strapiAdmin.useIsMobile();
79
+ const isPhone = !strapiAdmin.useMediaQuery(theme.breakpoints.small);
80
+ const trackRef = React.useRef(null);
81
+ const [width, setWidth] = React.useState(0);
82
+ const [start, setStart] = React.useState(0);
83
+ const cards = React.Children.toArray(children);
84
+ const { cards: cardsPerRow, isStacked } = getRowLayout({
85
+ width,
86
+ layoutSize,
87
+ isMobile,
88
+ isPhone
89
+ });
90
+ const maxStart = Math.max(cards.length - cardsPerRow, 0);
91
+ const firstVisible = Math.min(start, maxStart);
92
+ // Fewer cards than fit leave the tile right after them, not at the far end.
93
+ const visibleCount = Math.min(cards.length, cardsPerRow);
94
+ React.useLayoutEffect(()=>{
95
+ const track = trackRef.current;
96
+ if (!track || typeof ResizeObserver === 'undefined') {
97
+ return undefined;
98
+ }
99
+ const observer = new ResizeObserver(([entry])=>setWidth(entry.contentRect.width));
100
+ observer.observe(track);
101
+ return ()=>observer.disconnect();
102
+ }, []);
103
+ // A card added at the end (a new upload) is scrolled into view.
104
+ const previousCount = React.useRef(cards.length);
105
+ React.useEffect(()=>{
106
+ if (cards.length > previousCount.current) {
107
+ setStart(maxStart);
108
+ }
109
+ previousCount.current = cards.length;
110
+ }, [
111
+ cards.length,
112
+ maxStart
113
+ ]);
114
+ return /*#__PURE__*/ jsxRuntime.jsxs(Container, {
115
+ padding: 4,
116
+ children: [
117
+ /*#__PURE__*/ jsxRuntime.jsxs(Track, {
118
+ ref: trackRef,
119
+ $columns: isStacked ? 1 : cardsPerRow + 1,
120
+ children: [
121
+ /*#__PURE__*/ jsxRuntime.jsxs(Cards, {
122
+ $columns: visibleCount,
123
+ children: [
124
+ cards.slice(firstVisible, firstVisible + cardsPerRow),
125
+ firstVisible > 0 && /*#__PURE__*/ jsxRuntime.jsx(Arrow, {
126
+ $side: "start",
127
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
128
+ onClick: ()=>setStart(firstVisible - 1),
129
+ label: formatMessage({
130
+ id: translations.getTranslationKey('mediaLibraryInput.actions.previousSlide'),
131
+ defaultMessage: 'Previous slide'
132
+ }),
133
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.ChevronLeft, {})
134
+ })
135
+ }),
136
+ firstVisible < maxStart && /*#__PURE__*/ jsxRuntime.jsx(Arrow, {
137
+ $side: "end",
138
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.IconButton, {
139
+ onClick: ()=>setStart(firstVisible + 1),
140
+ label: formatMessage({
141
+ id: translations.getTranslationKey('mediaLibraryInput.actions.nextSlide'),
142
+ defaultMessage: 'Next slide'
143
+ }),
144
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.ChevronRight, {})
145
+ })
146
+ })
147
+ ]
148
+ }),
149
+ !isStacked && renderDropZone('tile')
150
+ ]
151
+ }),
152
+ isStacked && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
153
+ paddingTop: 4,
154
+ children: renderDropZone('stacked')
155
+ })
156
+ ]
157
+ });
158
+ };
159
+
160
+ exports.AssetCarousel = AssetCarousel;
161
+ //# sourceMappingURL=AssetCarousel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetCarousel.js","sources":["../../../../admin/src/components/MediaLibraryInput/AssetCarousel.tsx"],"sourcesContent":["import { Children, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react';\n\nimport { useIsMobile, useMediaQuery } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton } from '@strapi/design-system';\nimport { ChevronLeft, ChevronRight } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, useTheme } from 'styled-components';\n\nimport { getTranslationKey } from '../../utils/translations';\n\nimport type { ZoneVariant } from './AssetDropZone';\n\n/** Narrowest a card and the tile get side by side before stacking, in px. */\nconst MIN_CARD_WIDTH = 130;\n/**\n * Narrowest a card gets when two share the row, in px. Wider than the single\n * card's, so the row drops to one card before names are cut to a few letters.\n */\nconst MIN_CARD_WIDTH_FOR_TWO = 180;\nconst GAP = 16;\nconst MAX_CARDS = 2;\n\nconst Container = styled(Box)`\n background: ${({ theme }) => theme.colors.neutral100};\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n`;\n\nconst Track = styled.div<{ $columns: number }>`\n display: grid;\n grid-template-columns: repeat(${({ $columns }) => $columns}, minmax(0, 1fr));\n gap: ${GAP}px;\n`;\n\nconst Cards = styled.div<{ $columns: number }>`\n position: relative;\n display: grid;\n grid-column: span ${({ $columns }) => $columns};\n grid-template-columns: repeat(${({ $columns }) => $columns}, minmax(0, 1fr));\n gap: ${GAP}px;\n`;\n\nconst Arrow = styled(Box)<{ $side: 'start' | 'end' }>`\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n ${({ $side }) => ($side === 'start' ? 'left: -1.6rem;' : 'right: -1.6rem;')}\n\n button {\n border-radius: 50%;\n box-shadow: ${({ theme }) => theme.shadows.filterShadow};\n }\n`;\n\ninterface RowLayout {\n /** Cards per row, the drop zone not included. */\n cards: number;\n /** Too narrow for a card and the tile side by side: the drop zone goes below. */\n isStacked: boolean;\n}\n\n/**\n * How the row fits the field. The edit layout's size sets it: a third of the\n * form stacks one card over the drop zone, a full-width field shows two cards\n * beside it, anything in between one. Mobile always shows one card, stacked on\n * a phone. The measured width can only take cards away, for a field squeezed\n * by a narrow component.\n */\nconst getRowLayout = ({\n width,\n layoutSize,\n isMobile,\n isPhone,\n}: {\n width: number;\n layoutSize?: number;\n /** Below the tablet breakpoint: one card, whatever the layout says. */\n isMobile: boolean;\n /** Below the small breakpoint: the drop zone goes under the card. */\n isPhone: boolean;\n}): RowLayout => {\n const isNarrowLayout = isPhone || (layoutSize !== undefined && layoutSize <= 4);\n const maxCards = isMobile || (layoutSize !== undefined && layoutSize < 12) ? 1 : MAX_CARDS;\n\n // Unmeasured: no layout yet, or no `ResizeObserver`.\n const isMeasured = width > 0;\n const fitsCardAndTile = !isMeasured || width >= 2 * MIN_CARD_WIDTH + GAP;\n const fitsTwoCardsAndTile = !isMeasured || width >= 3 * MIN_CARD_WIDTH_FOR_TWO + 2 * GAP;\n\n if (isNarrowLayout || !fitsCardAndTile) {\n return { cards: 1, isStacked: true };\n }\n\n return { cards: fitsTwoCardsAndTile ? maxCards : 1, isStacked: false };\n};\n\ninterface AssetCarouselProps {\n /** One card per asset or upload, in field order. */\n children: ReactNode;\n /** Always shown: after the cards, or below them on a narrow field. */\n renderDropZone: (variant: Exclude<ZoneVariant, 'bar'>) => ReactNode;\n /** The field's width in the edit layout, out of 12, when the host knows it. */\n layoutSize?: number;\n}\n\n/**\n * A single row of cards followed by the drop tile. When the field holds more\n * than fit, arrows page through the cards and the tile stays put.\n */\nexport const AssetCarousel = ({ children, renderDropZone, layoutSize }: AssetCarouselProps) => {\n const { formatMessage } = useIntl();\n const theme = useTheme();\n const isMobile = useIsMobile();\n const isPhone = !useMediaQuery(theme.breakpoints.small);\n const trackRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n const [start, setStart] = useState(0);\n\n const cards = Children.toArray(children);\n const { cards: cardsPerRow, isStacked } = getRowLayout({ width, layoutSize, isMobile, isPhone });\n const maxStart = Math.max(cards.length - cardsPerRow, 0);\n const firstVisible = Math.min(start, maxStart);\n // Fewer cards than fit leave the tile right after them, not at the far end.\n const visibleCount = Math.min(cards.length, cardsPerRow);\n\n useLayoutEffect(() => {\n const track = trackRef.current;\n\n if (!track || typeof ResizeObserver === 'undefined') {\n return undefined;\n }\n\n const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));\n observer.observe(track);\n\n return () => observer.disconnect();\n }, []);\n\n // A card added at the end (a new upload) is scrolled into view.\n const previousCount = useRef(cards.length);\n useEffect(() => {\n if (cards.length > previousCount.current) {\n setStart(maxStart);\n }\n previousCount.current = cards.length;\n }, [cards.length, maxStart]);\n\n return (\n <Container padding={4}>\n <Track ref={trackRef} $columns={isStacked ? 1 : cardsPerRow + 1}>\n <Cards $columns={visibleCount}>\n {cards.slice(firstVisible, firstVisible + cardsPerRow)}\n\n {firstVisible > 0 && (\n <Arrow $side=\"start\">\n <IconButton\n onClick={() => setStart(firstVisible - 1)}\n label={formatMessage({\n id: getTranslationKey('mediaLibraryInput.actions.previousSlide'),\n defaultMessage: 'Previous slide',\n })}\n >\n <ChevronLeft />\n </IconButton>\n </Arrow>\n )}\n\n {firstVisible < maxStart && (\n <Arrow $side=\"end\">\n <IconButton\n onClick={() => setStart(firstVisible + 1)}\n label={formatMessage({\n id: getTranslationKey('mediaLibraryInput.actions.nextSlide'),\n defaultMessage: 'Next slide',\n })}\n >\n <ChevronRight />\n </IconButton>\n </Arrow>\n )}\n </Cards>\n {!isStacked && renderDropZone('tile')}\n </Track>\n {isStacked && <Box paddingTop={4}>{renderDropZone('stacked')}</Box>}\n </Container>\n );\n};\n"],"names":["MIN_CARD_WIDTH","MIN_CARD_WIDTH_FOR_TWO","GAP","MAX_CARDS","Container","styled","Box","theme","colors","neutral100","neutral200","borderRadius","Track","div","$columns","Cards","Arrow","$side","shadows","filterShadow","getRowLayout","width","layoutSize","isMobile","isPhone","isNarrowLayout","undefined","maxCards","isMeasured","fitsCardAndTile","fitsTwoCardsAndTile","cards","isStacked","AssetCarousel","children","renderDropZone","formatMessage","useIntl","useTheme","useIsMobile","useMediaQuery","breakpoints","small","trackRef","useRef","setWidth","useState","start","setStart","Children","toArray","cardsPerRow","maxStart","Math","max","length","firstVisible","min","visibleCount","useLayoutEffect","track","current","ResizeObserver","observer","entry","contentRect","observe","disconnect","previousCount","useEffect","_jsxs","padding","ref","slice","_jsx","IconButton","onClick","label","id","getTranslationKey","defaultMessage","ChevronLeft","ChevronRight","paddingTop"],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useRef, useState, Children, useLayoutEffect, useEffect } from 'react';
3
+ import { useIsMobile, useMediaQuery } from '@strapi/admin/strapi-admin';
4
+ import { Box, IconButton } from '@strapi/design-system';
5
+ import { ChevronLeft, ChevronRight } from '@strapi/icons';
6
+ import { useIntl } from 'react-intl';
7
+ import { styled, useTheme } from 'styled-components';
8
+ import { getTranslationKey } from '../../utils/translations.mjs';
9
+
10
+ /** Narrowest a card and the tile get side by side before stacking, in px. */ const MIN_CARD_WIDTH = 130;
11
+ /**
12
+ * Narrowest a card gets when two share the row, in px. Wider than the single
13
+ * card's, so the row drops to one card before names are cut to a few letters.
14
+ */ const MIN_CARD_WIDTH_FOR_TWO = 180;
15
+ const GAP = 16;
16
+ const MAX_CARDS = 2;
17
+ const Container = styled(Box)`
18
+ background: ${({ theme })=>theme.colors.neutral100};
19
+ border: 1px solid ${({ theme })=>theme.colors.neutral200};
20
+ border-radius: ${({ theme })=>theme.borderRadius};
21
+ `;
22
+ const Track = styled.div`
23
+ display: grid;
24
+ grid-template-columns: repeat(${({ $columns })=>$columns}, minmax(0, 1fr));
25
+ gap: ${GAP}px;
26
+ `;
27
+ const Cards = styled.div`
28
+ position: relative;
29
+ display: grid;
30
+ grid-column: span ${({ $columns })=>$columns};
31
+ grid-template-columns: repeat(${({ $columns })=>$columns}, minmax(0, 1fr));
32
+ gap: ${GAP}px;
33
+ `;
34
+ const Arrow = styled(Box)`
35
+ position: absolute;
36
+ top: 50%;
37
+ transform: translateY(-50%);
38
+ z-index: 1;
39
+ ${({ $side })=>$side === 'start' ? 'left: -1.6rem;' : 'right: -1.6rem;'}
40
+
41
+ button {
42
+ border-radius: 50%;
43
+ box-shadow: ${({ theme })=>theme.shadows.filterShadow};
44
+ }
45
+ `;
46
+ /**
47
+ * How the row fits the field. The edit layout's size sets it: a third of the
48
+ * form stacks one card over the drop zone, a full-width field shows two cards
49
+ * beside it, anything in between one. Mobile always shows one card, stacked on
50
+ * a phone. The measured width can only take cards away, for a field squeezed
51
+ * by a narrow component.
52
+ */ const getRowLayout = ({ width, layoutSize, isMobile, isPhone })=>{
53
+ const isNarrowLayout = isPhone || layoutSize !== undefined && layoutSize <= 4;
54
+ const maxCards = isMobile || layoutSize !== undefined && layoutSize < 12 ? 1 : MAX_CARDS;
55
+ // Unmeasured: no layout yet, or no `ResizeObserver`.
56
+ const isMeasured = width > 0;
57
+ const fitsCardAndTile = !isMeasured || width >= 2 * MIN_CARD_WIDTH + GAP;
58
+ const fitsTwoCardsAndTile = !isMeasured || width >= 3 * MIN_CARD_WIDTH_FOR_TWO + 2 * GAP;
59
+ if (isNarrowLayout || !fitsCardAndTile) {
60
+ return {
61
+ cards: 1,
62
+ isStacked: true
63
+ };
64
+ }
65
+ return {
66
+ cards: fitsTwoCardsAndTile ? maxCards : 1,
67
+ isStacked: false
68
+ };
69
+ };
70
+ /**
71
+ * A single row of cards followed by the drop tile. When the field holds more
72
+ * than fit, arrows page through the cards and the tile stays put.
73
+ */ const AssetCarousel = ({ children, renderDropZone, layoutSize })=>{
74
+ const { formatMessage } = useIntl();
75
+ const theme = useTheme();
76
+ const isMobile = useIsMobile();
77
+ const isPhone = !useMediaQuery(theme.breakpoints.small);
78
+ const trackRef = useRef(null);
79
+ const [width, setWidth] = useState(0);
80
+ const [start, setStart] = useState(0);
81
+ const cards = Children.toArray(children);
82
+ const { cards: cardsPerRow, isStacked } = getRowLayout({
83
+ width,
84
+ layoutSize,
85
+ isMobile,
86
+ isPhone
87
+ });
88
+ const maxStart = Math.max(cards.length - cardsPerRow, 0);
89
+ const firstVisible = Math.min(start, maxStart);
90
+ // Fewer cards than fit leave the tile right after them, not at the far end.
91
+ const visibleCount = Math.min(cards.length, cardsPerRow);
92
+ useLayoutEffect(()=>{
93
+ const track = trackRef.current;
94
+ if (!track || typeof ResizeObserver === 'undefined') {
95
+ return undefined;
96
+ }
97
+ const observer = new ResizeObserver(([entry])=>setWidth(entry.contentRect.width));
98
+ observer.observe(track);
99
+ return ()=>observer.disconnect();
100
+ }, []);
101
+ // A card added at the end (a new upload) is scrolled into view.
102
+ const previousCount = useRef(cards.length);
103
+ useEffect(()=>{
104
+ if (cards.length > previousCount.current) {
105
+ setStart(maxStart);
106
+ }
107
+ previousCount.current = cards.length;
108
+ }, [
109
+ cards.length,
110
+ maxStart
111
+ ]);
112
+ return /*#__PURE__*/ jsxs(Container, {
113
+ padding: 4,
114
+ children: [
115
+ /*#__PURE__*/ jsxs(Track, {
116
+ ref: trackRef,
117
+ $columns: isStacked ? 1 : cardsPerRow + 1,
118
+ children: [
119
+ /*#__PURE__*/ jsxs(Cards, {
120
+ $columns: visibleCount,
121
+ children: [
122
+ cards.slice(firstVisible, firstVisible + cardsPerRow),
123
+ firstVisible > 0 && /*#__PURE__*/ jsx(Arrow, {
124
+ $side: "start",
125
+ children: /*#__PURE__*/ jsx(IconButton, {
126
+ onClick: ()=>setStart(firstVisible - 1),
127
+ label: formatMessage({
128
+ id: getTranslationKey('mediaLibraryInput.actions.previousSlide'),
129
+ defaultMessage: 'Previous slide'
130
+ }),
131
+ children: /*#__PURE__*/ jsx(ChevronLeft, {})
132
+ })
133
+ }),
134
+ firstVisible < maxStart && /*#__PURE__*/ jsx(Arrow, {
135
+ $side: "end",
136
+ children: /*#__PURE__*/ jsx(IconButton, {
137
+ onClick: ()=>setStart(firstVisible + 1),
138
+ label: formatMessage({
139
+ id: getTranslationKey('mediaLibraryInput.actions.nextSlide'),
140
+ defaultMessage: 'Next slide'
141
+ }),
142
+ children: /*#__PURE__*/ jsx(ChevronRight, {})
143
+ })
144
+ })
145
+ ]
146
+ }),
147
+ !isStacked && renderDropZone('tile')
148
+ ]
149
+ }),
150
+ isStacked && /*#__PURE__*/ jsx(Box, {
151
+ paddingTop: 4,
152
+ children: renderDropZone('stacked')
153
+ })
154
+ ]
155
+ });
156
+ };
157
+
158
+ export { AssetCarousel };
159
+ //# sourceMappingURL=AssetCarousel.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetCarousel.mjs","sources":["../../../../admin/src/components/MediaLibraryInput/AssetCarousel.tsx"],"sourcesContent":["import { Children, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react';\n\nimport { useIsMobile, useMediaQuery } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton } from '@strapi/design-system';\nimport { ChevronLeft, ChevronRight } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, useTheme } from 'styled-components';\n\nimport { getTranslationKey } from '../../utils/translations';\n\nimport type { ZoneVariant } from './AssetDropZone';\n\n/** Narrowest a card and the tile get side by side before stacking, in px. */\nconst MIN_CARD_WIDTH = 130;\n/**\n * Narrowest a card gets when two share the row, in px. Wider than the single\n * card's, so the row drops to one card before names are cut to a few letters.\n */\nconst MIN_CARD_WIDTH_FOR_TWO = 180;\nconst GAP = 16;\nconst MAX_CARDS = 2;\n\nconst Container = styled(Box)`\n background: ${({ theme }) => theme.colors.neutral100};\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n`;\n\nconst Track = styled.div<{ $columns: number }>`\n display: grid;\n grid-template-columns: repeat(${({ $columns }) => $columns}, minmax(0, 1fr));\n gap: ${GAP}px;\n`;\n\nconst Cards = styled.div<{ $columns: number }>`\n position: relative;\n display: grid;\n grid-column: span ${({ $columns }) => $columns};\n grid-template-columns: repeat(${({ $columns }) => $columns}, minmax(0, 1fr));\n gap: ${GAP}px;\n`;\n\nconst Arrow = styled(Box)<{ $side: 'start' | 'end' }>`\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n ${({ $side }) => ($side === 'start' ? 'left: -1.6rem;' : 'right: -1.6rem;')}\n\n button {\n border-radius: 50%;\n box-shadow: ${({ theme }) => theme.shadows.filterShadow};\n }\n`;\n\ninterface RowLayout {\n /** Cards per row, the drop zone not included. */\n cards: number;\n /** Too narrow for a card and the tile side by side: the drop zone goes below. */\n isStacked: boolean;\n}\n\n/**\n * How the row fits the field. The edit layout's size sets it: a third of the\n * form stacks one card over the drop zone, a full-width field shows two cards\n * beside it, anything in between one. Mobile always shows one card, stacked on\n * a phone. The measured width can only take cards away, for a field squeezed\n * by a narrow component.\n */\nconst getRowLayout = ({\n width,\n layoutSize,\n isMobile,\n isPhone,\n}: {\n width: number;\n layoutSize?: number;\n /** Below the tablet breakpoint: one card, whatever the layout says. */\n isMobile: boolean;\n /** Below the small breakpoint: the drop zone goes under the card. */\n isPhone: boolean;\n}): RowLayout => {\n const isNarrowLayout = isPhone || (layoutSize !== undefined && layoutSize <= 4);\n const maxCards = isMobile || (layoutSize !== undefined && layoutSize < 12) ? 1 : MAX_CARDS;\n\n // Unmeasured: no layout yet, or no `ResizeObserver`.\n const isMeasured = width > 0;\n const fitsCardAndTile = !isMeasured || width >= 2 * MIN_CARD_WIDTH + GAP;\n const fitsTwoCardsAndTile = !isMeasured || width >= 3 * MIN_CARD_WIDTH_FOR_TWO + 2 * GAP;\n\n if (isNarrowLayout || !fitsCardAndTile) {\n return { cards: 1, isStacked: true };\n }\n\n return { cards: fitsTwoCardsAndTile ? maxCards : 1, isStacked: false };\n};\n\ninterface AssetCarouselProps {\n /** One card per asset or upload, in field order. */\n children: ReactNode;\n /** Always shown: after the cards, or below them on a narrow field. */\n renderDropZone: (variant: Exclude<ZoneVariant, 'bar'>) => ReactNode;\n /** The field's width in the edit layout, out of 12, when the host knows it. */\n layoutSize?: number;\n}\n\n/**\n * A single row of cards followed by the drop tile. When the field holds more\n * than fit, arrows page through the cards and the tile stays put.\n */\nexport const AssetCarousel = ({ children, renderDropZone, layoutSize }: AssetCarouselProps) => {\n const { formatMessage } = useIntl();\n const theme = useTheme();\n const isMobile = useIsMobile();\n const isPhone = !useMediaQuery(theme.breakpoints.small);\n const trackRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n const [start, setStart] = useState(0);\n\n const cards = Children.toArray(children);\n const { cards: cardsPerRow, isStacked } = getRowLayout({ width, layoutSize, isMobile, isPhone });\n const maxStart = Math.max(cards.length - cardsPerRow, 0);\n const firstVisible = Math.min(start, maxStart);\n // Fewer cards than fit leave the tile right after them, not at the far end.\n const visibleCount = Math.min(cards.length, cardsPerRow);\n\n useLayoutEffect(() => {\n const track = trackRef.current;\n\n if (!track || typeof ResizeObserver === 'undefined') {\n return undefined;\n }\n\n const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));\n observer.observe(track);\n\n return () => observer.disconnect();\n }, []);\n\n // A card added at the end (a new upload) is scrolled into view.\n const previousCount = useRef(cards.length);\n useEffect(() => {\n if (cards.length > previousCount.current) {\n setStart(maxStart);\n }\n previousCount.current = cards.length;\n }, [cards.length, maxStart]);\n\n return (\n <Container padding={4}>\n <Track ref={trackRef} $columns={isStacked ? 1 : cardsPerRow + 1}>\n <Cards $columns={visibleCount}>\n {cards.slice(firstVisible, firstVisible + cardsPerRow)}\n\n {firstVisible > 0 && (\n <Arrow $side=\"start\">\n <IconButton\n onClick={() => setStart(firstVisible - 1)}\n label={formatMessage({\n id: getTranslationKey('mediaLibraryInput.actions.previousSlide'),\n defaultMessage: 'Previous slide',\n })}\n >\n <ChevronLeft />\n </IconButton>\n </Arrow>\n )}\n\n {firstVisible < maxStart && (\n <Arrow $side=\"end\">\n <IconButton\n onClick={() => setStart(firstVisible + 1)}\n label={formatMessage({\n id: getTranslationKey('mediaLibraryInput.actions.nextSlide'),\n defaultMessage: 'Next slide',\n })}\n >\n <ChevronRight />\n </IconButton>\n </Arrow>\n )}\n </Cards>\n {!isStacked && renderDropZone('tile')}\n </Track>\n {isStacked && <Box paddingTop={4}>{renderDropZone('stacked')}</Box>}\n </Container>\n );\n};\n"],"names":["MIN_CARD_WIDTH","MIN_CARD_WIDTH_FOR_TWO","GAP","MAX_CARDS","Container","styled","Box","theme","colors","neutral100","neutral200","borderRadius","Track","div","$columns","Cards","Arrow","$side","shadows","filterShadow","getRowLayout","width","layoutSize","isMobile","isPhone","isNarrowLayout","undefined","maxCards","isMeasured","fitsCardAndTile","fitsTwoCardsAndTile","cards","isStacked","AssetCarousel","children","renderDropZone","formatMessage","useIntl","useTheme","useIsMobile","useMediaQuery","breakpoints","small","trackRef","useRef","setWidth","useState","start","setStart","Children","toArray","cardsPerRow","maxStart","Math","max","length","firstVisible","min","visibleCount","useLayoutEffect","track","current","ResizeObserver","observer","entry","contentRect","observe","disconnect","previousCount","useEffect","_jsxs","padding","ref","slice","_jsx","IconButton","onClick","label","id","getTranslationKey","defaultMessage","ChevronLeft","ChevronRight","paddingTop"],"mappings":"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"}
@@ -8,50 +8,79 @@ var reactIntl = require('react-intl');
8
8
  var styledComponents = require('styled-components');
9
9
  var translations = require('../../utils/translations.js');
10
10
 
11
- const Zone = styledComponents.styled.button`
11
+ const DRAG_FRAME_COLORS = {
12
+ accept: {
13
+ border: 'primary600',
14
+ background: 'primary100'
15
+ },
16
+ reject: {
17
+ border: 'neutral300',
18
+ background: 'neutral150'
19
+ }
20
+ };
21
+ const Zone = styledComponents.styled.div`
12
22
  position: relative;
13
23
  display: flex;
14
- flex-direction: column;
15
24
  align-items: center;
16
- justify-content: center;
17
- gap: ${({ theme })=>theme.spaces[2]};
25
+ gap: ${({ theme })=>theme.spaces[4]};
18
26
  width: 100%;
19
- min-height: 12rem;
20
- padding: ${({ theme })=>theme.spaces[6]};
21
- border: 1px solid ${({ theme })=>theme.colors.neutral200};
22
27
  border-radius: ${({ theme })=>theme.borderRadius};
23
- background: ${({ theme })=>theme.colors.neutral100};
24
- cursor: pointer;
28
+ text-align: ${({ $variant })=>$variant === 'bar' ? 'start' : 'center'};
25
29
 
26
- // Only while a file is dragged over the zone: it marks where the file will
27
- // land, so it has nothing to say to a pointer that is merely passing through.
28
- // Drawn inside rather than on the box itself, so the field keeps its own
29
- // outline and the invitation reads as an area to drop into.
30
- &::after {
31
- content: '';
32
- position: absolute;
33
- inset: ${({ theme })=>theme.spaces[2]} ${({ theme })=>theme.spaces[4]};
34
- border: 1px dashed ${({ theme })=>theme.colors.primary600};
35
- border-radius: ${({ theme })=>theme.borderRadius};
36
- opacity: ${({ $isDragging })=>$isDragging ? 1 : 0};
37
- pointer-events: none;
38
- }
30
+ ${({ $variant, theme })=>$variant !== 'bar' ? `
31
+ flex-direction: column;
32
+ justify-content: center;
33
+ height: 100%;
34
+ min-height: ${$variant === 'tile' ? '20.8rem' : 'auto'};
35
+ padding: ${theme.spaces[4]};
36
+ border: 1px dashed ${theme.colors.neutral300};
37
+ background: ${theme.colors.neutral0};
38
+ ` : `
39
+ min-height: 7.2rem;
40
+ padding: ${theme.spaces[4]};
41
+ border: 1px solid ${theme.colors.neutral200};
42
+ background: ${theme.colors.neutral100};
43
+ `}
39
44
 
40
- &[aria-disabled='true'] {
41
- cursor: not-allowed;
42
- }
45
+ // Only while a file is dragged over the zone: a solid frame inset from the
46
+ // zone's own border marks where the file will land, greyed out when it can't.
47
+ ${({ $dragState, theme })=>$dragState !== 'idle' && `
48
+ &::after {
49
+ content: '';
50
+ position: absolute;
51
+ inset: ${theme.spaces[2]};
52
+ border: 1px solid ${theme.colors[DRAG_FRAME_COLORS[$dragState].border]};
53
+ border-radius: ${theme.borderRadius};
54
+ background: ${theme.colors[DRAG_FRAME_COLORS[$dragState].background]};
55
+ pointer-events: none;
56
+ }
43
57
 
44
- &:focus-visible {
45
- outline: 2px solid ${({ theme })=>theme.colors.primary600};
46
- outline-offset: 2px;
58
+ & > * {
59
+ z-index: 1;
60
+ }
61
+ `}
62
+
63
+ &[data-disabled='true'] {
64
+ cursor: not-allowed;
47
65
  }
48
66
  `;
67
+ const IconFrame = styledComponents.styled(designSystem.Flex)`
68
+ flex-shrink: 0;
69
+ width: 4rem;
70
+ height: 4rem;
71
+ border-radius: ${({ theme })=>theme.borderRadius};
72
+ background: ${({ theme })=>theme.colors.neutral200};
73
+ color: ${({ theme })=>theme.colors.neutral500};
74
+ `;
49
75
  /**
50
- * The field's own drop target. Deliberately not the Media Library page's
76
+ * The field's own drop target. It only takes drops: browsing and picking files
77
+ * go through the "Add asset" menu, so the field has one way in, not two.
78
+ *
79
+ * Deliberately not the Media Library page's
51
80
  * `UploadDropZoneProvider`: that one covers a whole route and paints a
52
81
  * full-surface overlay, where this has to stay inside one field on a form that
53
82
  * may hold several of them.
54
- */ const AssetDropZone = ({ disabled = false, onClick, onDropFiles })=>{
83
+ */ const AssetDropZone = ({ variant = 'bar', disabled = false, onDropFiles })=>{
55
84
  const { formatMessage } = reactIntl.useIntl();
56
85
  const [isDragging, setIsDragging] = React.useState(false);
57
86
  // Drag events fire on descendants too, so a plain boolean flickers as the
@@ -59,14 +88,12 @@ const Zone = styledComponents.styled.button`
59
88
  const dragDepth = React.useRef(0);
60
89
  const handleDragEnter = React.useCallback((event)=>{
61
90
  event.preventDefault();
62
- if (disabled || !event.dataTransfer.types.includes('Files')) {
91
+ if (!event.dataTransfer.types.includes('Files')) {
63
92
  return;
64
93
  }
65
94
  dragDepth.current += 1;
66
95
  setIsDragging(true);
67
- }, [
68
- disabled
69
- ]);
96
+ }, []);
70
97
  const handleDragLeave = React.useCallback((event)=>{
71
98
  event.preventDefault();
72
99
  dragDepth.current -= 1;
@@ -77,8 +104,11 @@ const Zone = styledComponents.styled.button`
77
104
  }, []);
78
105
  const handleDragOver = React.useCallback((event)=>{
79
106
  event.preventDefault();
80
- event.dataTransfer.dropEffect = 'copy';
81
- }, []);
107
+ // `none` shows the no-drop cursor, and the browser then fires no `drop`.
108
+ event.dataTransfer.dropEffect = disabled ? 'none' : 'copy';
109
+ }, [
110
+ disabled
111
+ ]);
82
112
  const handleDrop = React.useCallback((event)=>{
83
113
  event.preventDefault();
84
114
  dragDepth.current = 0;
@@ -95,30 +125,27 @@ const Zone = styledComponents.styled.button`
95
125
  onDropFiles
96
126
  ]);
97
127
  return /*#__PURE__*/ jsxRuntime.jsxs(Zone, {
98
- type: "button",
99
- $isDragging: isDragging,
100
- "aria-disabled": disabled,
101
- onClick: ()=>!disabled && onClick(),
128
+ $dragState: isDragging ? disabled ? 'reject' : 'accept' : 'idle',
129
+ $variant: variant,
130
+ "data-disabled": disabled,
102
131
  onDragEnter: handleDragEnter,
103
132
  onDragLeave: handleDragLeave,
104
133
  onDragOver: handleDragOver,
105
134
  onDrop: handleDrop,
106
135
  children: [
107
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
136
+ /*#__PURE__*/ jsxRuntime.jsx(IconFrame, {
108
137
  justifyContent: "center",
109
- color: disabled ? 'neutral500' : 'primary600',
110
- children: /*#__PURE__*/ jsxRuntime.jsx(icons.PlusCircle, {
111
- width: "3.2rem",
112
- height: "3.2rem"
138
+ alignItems: "center",
139
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.Images, {
140
+ width: "2.4rem",
141
+ height: "2.4rem"
113
142
  })
114
143
  }),
115
144
  /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
116
145
  textColor: "neutral600",
117
- fontWeight: "bold",
118
- variant: "pi",
119
146
  children: formatMessage({
120
- id: translations.getTranslationKey('mediaLibraryInput.placeholder'),
121
- defaultMessage: 'Click to add an asset or drag and drop one in this area'
147
+ id: translations.getTranslationKey('content-manager.input.placeholder'),
148
+ defaultMessage: 'Drag & drop an asset here'
122
149
  })
123
150
  })
124
151
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"AssetDropZone.js","sources":["../../../../admin/src/components/MediaLibraryInput/AssetDropZone.tsx"],"sourcesContent":["import { useCallback, useRef, useState, type DragEvent } from 'react';\n\nimport { Flex, Typography } from '@strapi/design-system';\nimport { PlusCircle } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../utils/translations';\n\nconst Zone = styled.button<{ $isDragging: boolean }>`\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: ${({ theme }) => theme.spaces[2]};\n width: 100%;\n min-height: 12rem;\n padding: ${({ theme }) => theme.spaces[6]};\n border: 1px solid ${({ theme }) => theme.colors.neutral200};\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral100};\n cursor: pointer;\n\n // Only while a file is dragged over the zone: it marks where the file will\n // land, so it has nothing to say to a pointer that is merely passing through.\n // Drawn inside rather than on the box itself, so the field keeps its own\n // outline and the invitation reads as an area to drop into.\n &::after {\n content: '';\n position: absolute;\n inset: ${({ theme }) => theme.spaces[2]} ${({ theme }) => theme.spaces[4]};\n border: 1px dashed ${({ theme }) => theme.colors.primary600};\n border-radius: ${({ theme }) => theme.borderRadius};\n opacity: ${({ $isDragging }) => ($isDragging ? 1 : 0)};\n pointer-events: none;\n }\n\n &[aria-disabled='true'] {\n cursor: not-allowed;\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: 2px;\n }\n`;\n\ninterface AssetDropZoneProps {\n disabled?: boolean;\n onClick: () => void;\n onDropFiles: (files: globalThis.File[]) => void;\n}\n\n/**\n * The field's own drop target. Deliberately not the Media Library page's\n * `UploadDropZoneProvider`: that one covers a whole route and paints a\n * full-surface overlay, where this has to stay inside one field on a form that\n * may hold several of them.\n */\nexport const AssetDropZone = ({ disabled = false, onClick, onDropFiles }: AssetDropZoneProps) => {\n const { formatMessage } = useIntl();\n const [isDragging, setIsDragging] = useState(false);\n // Drag events fire on descendants too, so a plain boolean flickers as the\n // pointer crosses the icon or the label. Counting enter/leave pairs doesn't.\n const dragDepth = useRef(0);\n\n const handleDragEnter = useCallback(\n (event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n if (disabled || !event.dataTransfer.types.includes('Files')) {\n return;\n }\n dragDepth.current += 1;\n setIsDragging(true);\n },\n [disabled]\n );\n\n const handleDragLeave = useCallback((event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n dragDepth.current -= 1;\n if (dragDepth.current <= 0) {\n dragDepth.current = 0;\n setIsDragging(false);\n }\n }, []);\n\n const handleDragOver = useCallback((event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n }, []);\n\n const handleDrop = useCallback(\n (event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n dragDepth.current = 0;\n setIsDragging(false);\n\n if (disabled) {\n return;\n }\n\n const files = Array.from(event.dataTransfer.files ?? []);\n if (files.length > 0) {\n onDropFiles(files);\n }\n },\n [disabled, onDropFiles]\n );\n\n return (\n <Zone\n type=\"button\"\n $isDragging={isDragging}\n aria-disabled={disabled}\n onClick={() => !disabled && onClick()}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n {/* Same treatment as the repeatable-component initializer, so the two\n empty states in a form read as one affordance. */}\n <Flex justifyContent=\"center\" color={disabled ? 'neutral500' : 'primary600'}>\n <PlusCircle width=\"3.2rem\" height=\"3.2rem\" />\n </Flex>\n <Typography textColor=\"neutral600\" fontWeight=\"bold\" variant=\"pi\">\n {/* The legacy field's own key: identical wording, already translated in\n every locale, where a new key would ship English to all of them. */}\n {formatMessage({\n id: getTranslationKey('mediaLibraryInput.placeholder'),\n defaultMessage: 'Click to add an asset or drag and drop one in this area',\n })}\n </Typography>\n </Zone>\n );\n};\n"],"names":["Zone","styled","button","theme","spaces","colors","neutral200","borderRadius","neutral100","primary600","$isDragging","AssetDropZone","disabled","onClick","onDropFiles","formatMessage","useIntl","isDragging","setIsDragging","useState","dragDepth","useRef","handleDragEnter","useCallback","event","preventDefault","dataTransfer","types","includes","current","handleDragLeave","handleDragOver","dropEffect","handleDrop","files","Array","from","length","_jsxs","type","aria-disabled","onDragEnter","onDragLeave","onDragOver","onDrop","_jsx","Flex","justifyContent","color","PlusCircle","width","height","Typography","textColor","fontWeight","variant","id","getTranslationKey","defaultMessage"],"mappings":"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"}
1
+ {"version":3,"file":"AssetDropZone.js","sources":["../../../../admin/src/components/MediaLibraryInput/AssetDropZone.tsx"],"sourcesContent":["import { useCallback, useRef, useState, type DragEvent } from 'react';\n\nimport { Flex, Typography } from '@strapi/design-system';\nimport { Images } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslationKey } from '../../utils/translations';\n\n/**\n * `bar` on an empty field, `tile` after a multiple field's cards, `stacked`\n * below them when the field is too narrow for both on one row.\n */\nexport type ZoneVariant = 'bar' | 'tile' | 'stacked';\n\ntype DragState = 'idle' | 'accept' | 'reject';\n\nconst DRAG_FRAME_COLORS = {\n accept: { border: 'primary600', background: 'primary100' },\n reject: { border: 'neutral300', background: 'neutral150' },\n} as const;\n\nconst Zone = styled.div<{ $dragState: DragState; $variant: ZoneVariant }>`\n position: relative;\n display: flex;\n align-items: center;\n gap: ${({ theme }) => theme.spaces[4]};\n width: 100%;\n border-radius: ${({ theme }) => theme.borderRadius};\n text-align: ${({ $variant }) => ($variant === 'bar' ? 'start' : 'center')};\n\n ${({ $variant, theme }) =>\n $variant !== 'bar'\n ? `\n flex-direction: column;\n justify-content: center;\n height: 100%;\n min-height: ${$variant === 'tile' ? '20.8rem' : 'auto'};\n padding: ${theme.spaces[4]};\n border: 1px dashed ${theme.colors.neutral300};\n background: ${theme.colors.neutral0};\n `\n : `\n min-height: 7.2rem;\n padding: ${theme.spaces[4]};\n border: 1px solid ${theme.colors.neutral200};\n background: ${theme.colors.neutral100};\n `}\n\n // Only while a file is dragged over the zone: a solid frame inset from the\n // zone's own border marks where the file will land, greyed out when it can't.\n ${({ $dragState, theme }) =>\n $dragState !== 'idle' &&\n `\n &::after {\n content: '';\n position: absolute;\n inset: ${theme.spaces[2]};\n border: 1px solid ${theme.colors[DRAG_FRAME_COLORS[$dragState].border]};\n border-radius: ${theme.borderRadius};\n background: ${theme.colors[DRAG_FRAME_COLORS[$dragState].background]};\n pointer-events: none;\n }\n\n & > * {\n z-index: 1;\n }\n `}\n\n &[data-disabled='true'] {\n cursor: not-allowed;\n }\n`;\n\nconst IconFrame = styled(Flex)`\n flex-shrink: 0;\n width: 4rem;\n height: 4rem;\n border-radius: ${({ theme }) => theme.borderRadius};\n background: ${({ theme }) => theme.colors.neutral200};\n color: ${({ theme }) => theme.colors.neutral500};\n`;\n\ninterface AssetDropZoneProps {\n variant?: ZoneVariant;\n disabled?: boolean;\n onDropFiles: (files: globalThis.File[]) => void;\n}\n\n/**\n * The field's own drop target. It only takes drops: browsing and picking files\n * go through the \"Add asset\" menu, so the field has one way in, not two.\n *\n * Deliberately not the Media Library page's\n * `UploadDropZoneProvider`: that one covers a whole route and paints a\n * full-surface overlay, where this has to stay inside one field on a form that\n * may hold several of them.\n */\nexport const AssetDropZone = ({\n variant = 'bar',\n disabled = false,\n onDropFiles,\n}: AssetDropZoneProps) => {\n const { formatMessage } = useIntl();\n const [isDragging, setIsDragging] = useState(false);\n // Drag events fire on descendants too, so a plain boolean flickers as the\n // pointer crosses the icon or the label. Counting enter/leave pairs doesn't.\n const dragDepth = useRef(0);\n\n const handleDragEnter = useCallback((event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n if (!event.dataTransfer.types.includes('Files')) {\n return;\n }\n dragDepth.current += 1;\n setIsDragging(true);\n }, []);\n\n const handleDragLeave = useCallback((event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n dragDepth.current -= 1;\n if (dragDepth.current <= 0) {\n dragDepth.current = 0;\n setIsDragging(false);\n }\n }, []);\n\n const handleDragOver = useCallback(\n (event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n // `none` shows the no-drop cursor, and the browser then fires no `drop`.\n event.dataTransfer.dropEffect = disabled ? 'none' : 'copy';\n },\n [disabled]\n );\n\n const handleDrop = useCallback(\n (event: DragEvent<HTMLElement>) => {\n event.preventDefault();\n dragDepth.current = 0;\n setIsDragging(false);\n\n if (disabled) {\n return;\n }\n\n const files = Array.from(event.dataTransfer.files ?? []);\n if (files.length > 0) {\n onDropFiles(files);\n }\n },\n [disabled, onDropFiles]\n );\n\n return (\n <Zone\n $dragState={isDragging ? (disabled ? 'reject' : 'accept') : 'idle'}\n $variant={variant}\n data-disabled={disabled}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n <IconFrame justifyContent=\"center\" alignItems=\"center\">\n <Images width=\"2.4rem\" height=\"2.4rem\" />\n </IconFrame>\n <Typography textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('content-manager.input.placeholder'),\n defaultMessage: 'Drag & drop an asset here',\n })}\n </Typography>\n </Zone>\n );\n};\n"],"names":["DRAG_FRAME_COLORS","accept","border","background","reject","Zone","styled","div","theme","spaces","borderRadius","$variant","colors","neutral300","neutral0","neutral200","neutral100","$dragState","IconFrame","Flex","neutral500","AssetDropZone","variant","disabled","onDropFiles","formatMessage","useIntl","isDragging","setIsDragging","useState","dragDepth","useRef","handleDragEnter","useCallback","event","preventDefault","dataTransfer","types","includes","current","handleDragLeave","handleDragOver","dropEffect","handleDrop","files","Array","from","length","_jsxs","data-disabled","onDragEnter","onDragLeave","onDragOver","onDrop","_jsx","justifyContent","alignItems","Images","width","height","Typography","textColor","id","getTranslationKey","defaultMessage"],"mappings":"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"}