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