Skip to content

Commit e782d99

Browse files
authored
fix(payload, ui): sends cropped image pixel values to server instead of percent values (#6903)
## Description v2 PR [here](#6852) - [x] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## Checklist: - [x] Existing test suite passes locally with my changes
1 parent b0e9338 commit e782d99

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

packages/payload/src/uploads/cropImage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const percentToPixel = (value, dimension) => {
66

77
export async function cropImage({ cropData, dimensions, file, sharp }) {
88
try {
9-
const { height, width, x, y } = cropData
9+
const { heightPixels, widthPixels, x, y } = cropData
1010

1111
const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)
1212

@@ -15,10 +15,10 @@ export async function cropImage({ cropData, dimensions, file, sharp }) {
1515
if (fileIsAnimatedType) sharpOptions.animated = true
1616

1717
const formattedCropData = {
18-
height: percentToPixel(height, dimensions.height),
18+
height: Number(heightPixels),
1919
left: percentToPixel(x, dimensions.width),
2020
top: percentToPixel(y, dimensions.height),
21-
width: percentToPixel(width, dimensions.width),
21+
width: Number(widthPixels),
2222
}
2323

2424
const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData)

packages/ui/src/elements/EditUpload/index.tsx

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import type CropType from 'react-image-crop'
33

44
import { useModal } from '@faceless-ui/modal'
5-
import React, { useRef, useState } from 'react'
5+
import React, { forwardRef, useRef, useState } from 'react'
66
import ReactCrop from 'react-image-crop'
77
import 'react-image-crop/dist/ReactCrop.css'
88

@@ -14,16 +14,28 @@ import './index.scss'
1414

1515
const baseClass = 'edit-upload'
1616

17-
const Input: React.FC<{ name: string; onChange: (value: string) => void; value: string }> = ({
18-
name,
19-
onChange,
20-
value,
21-
}) => (
22-
<div className={`${baseClass}__input`}>
23-
{name}
24-
<input name={name} onChange={(e) => onChange(e.target.value)} type="number" value={value} />
25-
</div>
26-
)
17+
type Props = {
18+
name: string
19+
onChange: (value: string) => void
20+
value: string
21+
}
22+
23+
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => {
24+
const { name, onChange, value } = props
25+
26+
return (
27+
<div className={`${baseClass}__input`}>
28+
{name}
29+
<input
30+
name={name}
31+
onChange={(e) => onChange(e.target.value)}
32+
ref={ref}
33+
type="number"
34+
value={value}
35+
/>
36+
</div>
37+
)
38+
})
2739

2840
type FocalPosition = {
2941
x: number
@@ -43,8 +55,10 @@ export type EditUploadProps = {
4355

4456
const defaultCrop: CropType = {
4557
height: 100,
58+
heightPixels: 0,
4659
unit: '%',
4760
width: 100,
61+
widthPixels: 0,
4862
x: 0,
4963
y: 0,
5064
}
@@ -84,6 +98,17 @@ export const EditUpload: React.FC<EditUploadProps> = ({
8498
const imageRef = useRef<HTMLImageElement | undefined>(undefined)
8599
const cropRef = useRef<HTMLDivElement | undefined>(undefined)
86100

101+
const heightRef = useRef<HTMLInputElement | null>(null)
102+
const widthRef = useRef<HTMLInputElement | null>(null)
103+
104+
const [imageLoaded, setImageLoaded] = useState<boolean>(false)
105+
106+
const onImageLoad = (e) => {
107+
setOriginalHeight(e.currentTarget.naturalHeight)
108+
setOriginalWidth(e.currentTarget.naturalWidth)
109+
setImageLoaded(true)
110+
}
111+
87112
const fineTuneCrop = ({ dimension, value }: { dimension: 'height' | 'width'; value: string }) => {
88113
const intValue = parseInt(value)
89114
if (dimension === 'width' && intValue >= originalWidth) return null
@@ -115,7 +140,13 @@ export const EditUpload: React.FC<EditUploadProps> = ({
115140
const saveEdits = () => {
116141
if (typeof onSave === 'function')
117142
onSave({
118-
crop,
143+
crop: crop
144+
? {
145+
...crop,
146+
heightPixels: Number(heightRef.current?.value ?? crop.heightPixels),
147+
widthPixels: Number(widthRef.current?.value ?? crop.widthPixels),
148+
}
149+
: undefined,
119150
focalPosition,
120151
})
121152
closeModal(editDrawerSlug)
@@ -159,6 +190,7 @@ export const EditUpload: React.FC<EditUploadProps> = ({
159190
aria-label={t('general:applyChanges')}
160191
buttonStyle="primary"
161192
className={`${baseClass}__save`}
193+
disabled={!imageLoaded}
162194
onClick={saveEdits}
163195
>
164196
{t('general:applyChanges')}
@@ -186,21 +218,15 @@ export const EditUpload: React.FC<EditUploadProps> = ({
186218
>
187219
<img
188220
alt={t('upload:setCropArea')}
189-
onLoad={(e) => {
190-
setOriginalHeight(e.currentTarget.naturalHeight)
191-
setOriginalWidth(e.currentTarget.naturalWidth)
192-
}}
221+
onLoad={onImageLoad}
193222
ref={imageRef}
194223
src={fileSrcToUse}
195224
/>
196225
</ReactCrop>
197226
) : (
198227
<img
199228
alt={t('upload:setFocalPoint')}
200-
onLoad={(e) => {
201-
setOriginalHeight(e.currentTarget.naturalHeight)
202-
setOriginalWidth(e.currentTarget.naturalWidth)
203-
}}
229+
onLoad={onImageLoad}
204230
ref={imageRef}
205231
src={fileSrcToUse}
206232
/>
@@ -233,8 +259,10 @@ export const EditUpload: React.FC<EditUploadProps> = ({
233259
onClick={() =>
234260
setCrop({
235261
height: 100,
262+
heightPixels: originalHeight,
236263
unit: '%',
237264
width: 100,
265+
widthPixels: originalWidth,
238266
x: 0,
239267
y: 0,
240268
})
@@ -251,11 +279,13 @@ export const EditUpload: React.FC<EditUploadProps> = ({
251279
<Input
252280
name={`${t('upload:width')} (px)`}
253281
onChange={(value) => fineTuneCrop({ dimension: 'width', value })}
282+
ref={widthRef}
254283
value={((crop.width / 100) * originalWidth).toFixed(0)}
255284
/>
256285
<Input
257286
name={`${t('upload:height')} (px)`}
258287
onChange={(value) => fineTuneCrop({ dimension: 'height', value })}
288+
ref={heightRef}
259289
value={((crop.height / 100) * originalHeight).toFixed(0)}
260290
/>
261291
</div>

0 commit comments

Comments
 (0)