|
@@ -1,8 +1,10 @@
|
|
|
+import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react'
|
|
|
+
|
|
|
import { IconButton } from '@/shared/components'
|
|
|
+import { SvgGlyphPan, SvgGlyphZoomIn, SvgGlyphZoomOut } from '@/shared/icons'
|
|
|
import { ImageCropData, AssetDimensions } from '@/types/cropper'
|
|
|
-import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react'
|
|
|
-import { ActionDialogProps } from '../ActionDialog'
|
|
|
-import { CropperImageType, useCropper } from './cropper'
|
|
|
+import { validateImage } from '@/utils/image'
|
|
|
+
|
|
|
import {
|
|
|
AlignInfo,
|
|
|
AlignInfoContainer,
|
|
@@ -15,8 +17,9 @@ import {
|
|
|
StyledSlider,
|
|
|
ZoomControl,
|
|
|
} from './ImageCropDialog.style'
|
|
|
-import { SvgGlyphPan, SvgGlyphZoomIn, SvgGlyphZoomOut } from '@/shared/icons'
|
|
|
-import { validateImage } from '@/utils/image'
|
|
|
+import { CropperImageType, useCropper } from './cropper'
|
|
|
+
|
|
|
+import { ActionDialogProps } from '../ActionDialog'
|
|
|
|
|
|
export type ImageCropDialogProps = {
|
|
|
imageType: CropperImageType
|
|
@@ -30,7 +33,7 @@ export type ImageCropDialogProps = {
|
|
|
} & Pick<ActionDialogProps, 'onExitClick'>
|
|
|
|
|
|
export type ImageCropDialogImperativeHandle = {
|
|
|
- open: (file?: File | Blob) => void
|
|
|
+ open: (file?: File | Blob, cropData?: ImageCropData) => void
|
|
|
}
|
|
|
|
|
|
const ImageCropDialogComponent: React.ForwardRefRenderFunction<
|
|
@@ -41,19 +44,27 @@ const ImageCropDialogComponent: React.ForwardRefRenderFunction<
|
|
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
|
const [imageEl, setImageEl] = useState<HTMLImageElement | null>(null)
|
|
|
const [editedImageHref, setEditedImageHref] = useState<string | null>(null)
|
|
|
- const { currentZoom, zoomRange, zoomStep, handleZoomChange, cropImage } = useCropper({ imageEl, imageType })
|
|
|
+ const [cropData, setCropData] = useState<ImageCropData | null>(null)
|
|
|
+ const { currentZoom, zoomRange, zoomStep, handleZoomChange, cropImage } = useCropper({
|
|
|
+ imageEl,
|
|
|
+ imageType,
|
|
|
+ cropData,
|
|
|
+ })
|
|
|
+
|
|
|
+ const cropEditDisabled = !!cropData
|
|
|
|
|
|
// not great - ideally we'd have a data flow trigger this via prop change
|
|
|
// however, since there's no way to detect whether the file pick succeeds, the component wouldn't be able to report back whether it was actually opened
|
|
|
// because of that we're letting the consumer trigger the open manually
|
|
|
useImperativeHandle(ref, () => ({
|
|
|
- open: (file) => {
|
|
|
+ open: (file, cropData) => {
|
|
|
if (file) {
|
|
|
const fileUrl = URL.createObjectURL(file)
|
|
|
setEditedImageHref(fileUrl)
|
|
|
setShowDialog(true)
|
|
|
} else {
|
|
|
inputRef.current?.click()
|
|
|
+ if (cropData) setCropData(cropData)
|
|
|
}
|
|
|
},
|
|
|
}))
|
|
@@ -97,7 +108,11 @@ const ImageCropDialogComponent: React.ForwardRefRenderFunction<
|
|
|
|
|
|
const zoomControlNode = (
|
|
|
<ZoomControl>
|
|
|
- <IconButton variant="tertiary" onClick={() => handleZoomChange(currentZoom - zoomStep)}>
|
|
|
+ <IconButton
|
|
|
+ variant="tertiary"
|
|
|
+ onClick={() => handleZoomChange(currentZoom - zoomStep)}
|
|
|
+ disabled={cropEditDisabled}
|
|
|
+ >
|
|
|
<SvgGlyphZoomOut />
|
|
|
</IconButton>
|
|
|
<StyledSlider
|
|
@@ -106,8 +121,13 @@ const ImageCropDialogComponent: React.ForwardRefRenderFunction<
|
|
|
min={zoomRange[0]}
|
|
|
max={zoomRange[1]}
|
|
|
step={zoomStep}
|
|
|
+ disabled={cropEditDisabled}
|
|
|
/>
|
|
|
- <IconButton variant="tertiary" onClick={() => handleZoomChange(currentZoom + zoomStep)}>
|
|
|
+ <IconButton
|
|
|
+ variant="tertiary"
|
|
|
+ onClick={() => handleZoomChange(currentZoom + zoomStep)}
|
|
|
+ disabled={cropEditDisabled}
|
|
|
+ >
|
|
|
<SvgGlyphZoomIn />
|
|
|
</IconButton>
|
|
|
</ZoomControl>
|
|
@@ -131,7 +151,7 @@ const ImageCropDialogComponent: React.ForwardRefRenderFunction<
|
|
|
<AlignInfo variant="body2">Drag and adjust image position</AlignInfo>
|
|
|
</AlignInfoContainer>
|
|
|
{editedImageHref && (
|
|
|
- <CropContainer rounded={imageType === 'avatar'}>
|
|
|
+ <CropContainer rounded={imageType === 'avatar'} disabled={cropEditDisabled}>
|
|
|
<StyledImage src={editedImageHref} ref={imageElRefCallback} />
|
|
|
</CropContainer>
|
|
|
)}
|