diff --git a/packages/web-react/src/components/FileUploader/README.md b/packages/web-react/src/components/FileUploader/README.md index 2c2cadcfb1..4e1e69006b 100644 --- a/packages/web-react/src/components/FileUploader/README.md +++ b/packages/web-react/src/components/FileUploader/README.md @@ -329,13 +329,13 @@ const customUpdate = (_event: MouseEvent, file: File) => { #### Updating Image Preview with cropped image When you are using FileUploader with some kind of image cropper you want to also update the image preview on FileUploaderAttachment when image changes. -You can do this by passing a specific object in shape of coordinates (`{ x: number, y: number, width: number, height: number }`) to the `meta` argument. +You can do this by passing a specific object in shape of coordinates (`{ x: number, y: number, cropWidth: number, cropHeight: number, originalWidth: number, originalHeight: number }`) to the `meta` argument. Then the coordinates will be applied to the preview image in the attachment. ```javascript // … const customUpdate = (_event: MouseEvent, file: File) => { - const meta = { x: 30, y: 30, width: 150, height: 150 }; + const meta = { x: 30, y: 30, cropWidth: 150, cropHeight: 150, originalWidth: 560, originalHeight: 330 }; return updateQueue(file.name, file, meta); }; diff --git a/packages/web-react/src/components/FileUploader/__tests__/useFileUploaderStyleProps.test.ts b/packages/web-react/src/components/FileUploader/__tests__/useFileUploaderStyleProps.test.ts index b35eb436a1..1fd5525fd5 100644 --- a/packages/web-react/src/components/FileUploader/__tests__/useFileUploaderStyleProps.test.ts +++ b/packages/web-react/src/components/FileUploader/__tests__/useFileUploaderStyleProps.test.ts @@ -56,16 +56,16 @@ describe('useFileUploaderStyleProps', () => { it('should have CSS for crop image', () => { const { result } = renderHook(() => useFileUploaderStyleProps({ - meta: { x: 1, y: 2, width: 3, height: 4 }, + meta: { x: 0, y: 0, cropWidth: 100, cropHeight: 100, originalWidth: 350, originalHeight: 200 }, }), ); expect(result.current.classProps.imageCropStyles).toBeDefined(); expect(result.current.classProps.imageCropStyles).toStrictEqual({ - '--file-uploader-attachment-image-height': '4px', - '--file-uploader-attachment-image-left': '-1px', - '--file-uploader-attachment-image-top': '-2px', - '--file-uploader-attachment-image-width': '3px', + '--file-uploader-attachment-image-height': '108px', + '--file-uploader-attachment-image-left': '-0px', + '--file-uploader-attachment-image-top': '-0px', + '--file-uploader-attachment-image-width': '189px', }); }); }); diff --git a/packages/web-react/src/components/FileUploader/constants.ts b/packages/web-react/src/components/FileUploader/constants.ts index f2563b7c14..b18053e27a 100644 --- a/packages/web-react/src/components/FileUploader/constants.ts +++ b/packages/web-react/src/components/FileUploader/constants.ts @@ -1,6 +1,7 @@ export const DEFAULT_FILE_SIZE_LIMIT = 10000000; // = 10 MB export const DEFAULT_FILE_QUEUE_LIMIT = 10; -export const IMAGE_DIMENSION = 54; // px +export const IMAGE_DIMENSION = 54; // px; @see: CSS class `.FileUploaderAttachment__image` in _FileUploaderAttachment.scss +export const IMAGE_PREVIEW_BASE64_MAX_WIDTH = 500; // px export const DEFAULT_ERROR_MESSAGE_MAX_FILE_SIZE = 'The file size limit has been exceeded'; export const DEFAULT_ERROR_MESSAGE_QUEUE_DUPLICITY = 'This file already exists in the queue'; diff --git a/packages/web-react/src/components/FileUploader/demo/FileUploaderMetaData.tsx b/packages/web-react/src/components/FileUploader/demo/FileUploaderMetaData.tsx index 906b7ba01d..1cc4532271 100644 --- a/packages/web-react/src/components/FileUploader/demo/FileUploaderMetaData.tsx +++ b/packages/web-react/src/components/FileUploader/demo/FileUploaderMetaData.tsx @@ -1,8 +1,8 @@ -import React, { useState, MouseEvent } from 'react'; +import React, { MouseEvent, useState } from 'react'; +import { FileUploader, FileUploaderAttachment, FileUploaderInput, FileUploaderList, useFileQueue } from '..'; import { SpiritFileUploaderAttachmentProps } from '../../../types'; import { Button } from '../../Button'; -import { Modal, ModalDialog, ModalBody, ModalFooter } from '../../Modal'; -import { FileUploader, FileUploaderAttachment, FileUploaderInput, FileUploaderList, useFileQueue } from '..'; +import { Modal, ModalBody, ModalDialog, ModalFooter } from '../../Modal'; const FileUploaderMetaData = () => { const [isModalOpen, setIsModalOpen] = useState(false); @@ -34,7 +34,9 @@ const FileUploaderMetaData = () => { }; const customUpdate = (_event: MouseEvent, file: File) => { - const newMeta = toggleMeta ? { x: 30, y: 30, width: 150, height: 150 } : { x: 22, y: 0, width: 110, height: 100 }; + const newMeta = toggleMeta + ? { x: 30, y: 30, cropWidth: 150, cropHeight: 150, originalWidth: 560, originalHeight: 330 } + : { x: 22, y: 0, cropWidth: 110, cropHeight: 100, originalWidth: 560, originalHeight: 330 }; setIsModalOpen(false); setToggleMeta(!toggleMeta); diff --git a/packages/web-react/src/components/FileUploader/useFileUploaderStyleProps.ts b/packages/web-react/src/components/FileUploader/useFileUploaderStyleProps.ts index 50eaf50e99..ba711bbbca 100644 --- a/packages/web-react/src/components/FileUploader/useFileUploaderStyleProps.ts +++ b/packages/web-react/src/components/FileUploader/useFileUploaderStyleProps.ts @@ -1,8 +1,9 @@ -import { CSSProperties } from 'react'; import classNames from 'classnames'; +import { CSSProperties } from 'react'; import { FileUploaderCropCSS } from '../../constants/dictionaries'; import { useClassNamePrefix } from '../../hooks'; import { FileMetadata, FileUploaderQueueLimitBehaviorType, Validation } from '../../types'; +import { IMAGE_DIMENSION } from './constants'; export interface FileUploaderStyleProps extends Validation { imageObjectFit?: 'contain' | 'cover'; @@ -28,6 +29,15 @@ type ImageObjectFit = { '--file-uploader-attachment-image-object-fit': string; }; +type ImageCropMeta = { + x: number; + y: number; + cropWidth: number; + cropHeight: number; + originalWidth: number; + originalHeight: number; +}; + export interface FileUploaderStyleReturn { /** className props */ classProps: { @@ -88,16 +98,32 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU const { meta, imageObjectFit } = props || {}; let imageCropCSS: ImageCropCSS | undefined; let imageObjectFitCSS: ImageObjectFit | undefined; - const hasCoords = meta && meta.x != null && meta.y != null && meta.width != null && meta.height != null; + const hasCoordsInMeta = + meta != null && + ['x', 'y', 'cropWidth', 'cropHeight', 'originalWidth', 'originalHeight'].every((coord) => meta[coord] != null); + + if (hasCoordsInMeta) { + const { x, y, cropWidth, cropHeight, originalWidth, originalHeight } = meta as ImageCropMeta; + const previewHeight = IMAGE_DIMENSION; + let scale; + if (cropHeight > cropWidth) { + // scale for portrait images + scale = previewHeight / cropWidth; + } else { + // scale for landscape images + scale = previewHeight / cropHeight; + } - if (hasCoords) { - const { x, y, width, height } = meta; + const cropX = Math.round(x * scale); + const cropY = Math.round(y * scale); + const imageWidth = Math.round(originalWidth * scale); + const imageHeight = Math.round(originalHeight * scale); imageCropCSS = { - [FileUploaderCropCSS.TOP]: `-${y}px`, - [FileUploaderCropCSS.LEFT]: `-${x}px`, - [FileUploaderCropCSS.WIDTH]: `${width}px`, - [FileUploaderCropCSS.HEIGHT]: `${height}px`, + [FileUploaderCropCSS.TOP]: `-${cropY}px`, + [FileUploaderCropCSS.LEFT]: `-${cropX}px`, + [FileUploaderCropCSS.WIDTH]: `${imageWidth}px`, + [FileUploaderCropCSS.HEIGHT]: `${imageHeight}px`, }; } @@ -141,7 +167,7 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU image: fileUploaderAttachmentImageClass, slot: fileUploaderAttachmentSlotClass, }, - ...(hasCoords && { imageCropStyles: imageCropCSS }), + ...(hasCoordsInMeta && { imageCropStyles: imageCropCSS }), ...(imageObjectFit && { attachmentStyles: imageObjectFitCSS }), }, };