Skip to content

Commit

Permalink
fixup! Feat(web-react): FileUploader - Support for crop image #DS-954
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelklibani committed Oct 16, 2023
1 parent bdf1612 commit 5b28fb8
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import { FileQueueValueMetaType } from '../../types/fileUploader';
import { FileMetadata } from '../../types/fileUploader';
import { useFileUploaderStyleProps } from './useFileUploaderStyleProps';
import { IMAGE_DIMENSION } from './constants';

type AttachmentImagePreviewProps = {
label: string;
imagePreview: string;
meta?: FileQueueValueMetaType;
meta?: FileMetadata;
};

const AttachmentImagePreview = ({ label, imagePreview, meta }: AttachmentImagePreviewProps) => {
Expand Down
32 changes: 16 additions & 16 deletions packages/web-react/src/components/FileUploader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,22 +300,22 @@ const resetStateHandler = () => {

## FileUploader Props

| Name | Type | Default | Required | Description |
| ------------------------------------- | ------------------------------------------------------------------------------ | ------- | -------- | ------------------------------------------------------------------- |
| `addToQueue` | `(key: string, file: File, meta?: FileQueueValueMetaType) => FileQueueMapType` ||| Callback to add an item to the queue |
| `clearQueue` | `() => void` ||| Callback to clear the queue |
| `errorMessages.errorFileDuplicity` | `string` ||| Translation for the error message: Duplicate file in queue |
| `errorMessages.errorMaxFileSize` | `string` ||| Translation for the error message: Maximum file size |
| `errorMessages.errorMaxUploadedFiles` | `string` ||| Translation for the error message: Maximum number of uploaded files |
| `fileQueue` | `FileQueueMapType` ||| Queue of items to upload |
| `findInQueue` | `(key: string) => FileQueueMapType` ||| A callback to find a particular item in the queue |
| `id` | `string` ||| FileUploader id |
| `isDisabled` | `bool` ||| When the field is supposed to be disabled |
| `isFluid` | `bool` ||| When the field is supposed to be fluid |
| `onDismiss` | `(key: string) => FileQueueMapType` ||| A callback to delete a particular item from the queue |
| `UNSAFE_className` | `string` ||| FileUploader custom class name |
| `UNSAFE_style` | `CSSProperties` ||| FileUploader custom style |
| `updateQueue` | `(key: string, file: File, meta?: FileQueueValueMetaType) => FileQueueMapType` ||| A callback to update a particular item in the queue |
| Name | Type | Default | Required | Description |
| ------------------------------------- | -------------------------------------------------------------------- | ------- | -------- | ------------------------------------------------------------------- |
| `addToQueue` | `(key: string, file: File, meta?: FileMetadata) => FileQueueMapType` ||| Callback to add an item to the queue |
| `clearQueue` | `() => void` ||| Callback to clear the queue |
| `errorMessages.errorFileDuplicity` | `string` ||| Translation for the error message: Duplicate file in queue |
| `errorMessages.errorMaxFileSize` | `string` ||| Translation for the error message: Maximum file size |
| `errorMessages.errorMaxUploadedFiles` | `string` ||| Translation for the error message: Maximum number of uploaded files |
| `fileQueue` | `FileQueueMapType` ||| Queue of items to upload |
| `findInQueue` | `(key: string) => FileQueueMapType` ||| A callback to find a particular item in the queue |
| `id` | `string` ||| FileUploader id |
| `isDisabled` | `bool` ||| When the field is supposed to be disabled |
| `isFluid` | `bool` ||| When the field is supposed to be fluid |
| `onDismiss` | `(key: string) => FileQueueMapType` ||| A callback to delete a particular item from the queue |
| `UNSAFE_className` | `string` ||| FileUploader custom class name |
| `UNSAFE_style` | `CSSProperties` ||| FileUploader custom style |
| `updateQueue` | `(key: string, file: File, meta?: FileMetadata) => FileQueueMapType` ||| A callback to update a particular item in the queue |

The rest of the properties are created from the default `<div>` element. [More about the element][DivElementDocs]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,27 @@ describe('useFileQueue', () => {

it('should update queue', () => {
const { result } = renderHook(() => useFileQueue());
const testMeta = { test: 'test' };
const testUpdateMeta = { test: 'test updated' };

act(() => {
result.current.addToQueue('test1_txt', file1);
result.current.addToQueue('test2_txt', file2);
result.current.addToQueue('test3_txt', file2, testMeta);
});

expect(result.current.fileQueue.size).toBe(2);
expect(result.current.fileQueue.size).toBe(3);
expect(result.current.fileQueue.get('test3_txt')).toEqual({ file: file2, meta: testMeta });

act(() => {
result.current.updateQueue('test1_txt', file2);
result.current.updateQueue('test2_txt', file1);
result.current.updateQueue('test3_txt', file2, testUpdateMeta);
});

expect(result.current.fileQueue.size).toBe(2);
expect(result.current.fileQueue.size).toBe(3);
expect(result.current.fileQueue.get('test1_txt')).toEqual({ file: file2 });
expect(result.current.fileQueue.get('test2_txt')).toEqual({ file: file1 });
expect(result.current.fileQueue.get('test3_txt')).toEqual({ file: file2, meta: testUpdateMeta });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,14 @@ describe('useFileUploaderStyleProps', () => {

expect(result.current.classProps.input.root).toBe('FileUploaderInput FileUploaderInput--disabled');
});

it('should have CSS for crop image', () => {
const { result } = renderHook(() =>
useFileUploaderStyleProps({
meta: { x: 1, y: 2, width: 3, height: 4 },
}),
);

expect(result.current.classProps.imageCropStyles).toBeDefined();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { FileQueueValueMetaType, FileQueueValueType, FileUploaderHandlingProps } from '../../types';
import { FileMetadata, FileQueueValueType, FileUploaderHandlingProps } from '../../types';

export interface FileQueueReturn extends FileUploaderHandlingProps {}

Expand All @@ -17,7 +17,7 @@ export const useFileQueue = (): FileQueueReturn => {
return queue;
};

const addToQueueHandler = (key: string, file: File, meta?: FileQueueValueMetaType) => {
const addToQueueHandler = (key: string, file: File, meta?: FileMetadata) => {
setQueue((prev) => {
const newValue: FileQueueValueType = { file };
if (meta != null) {
Expand All @@ -32,7 +32,7 @@ export const useFileQueue = (): FileQueueReturn => {

const findInQueueHandler = (key: string) => queue.get(key) || null;

const updateQueueHandler = (key: string, file: File, meta?: FileQueueValueMetaType) => {
const updateQueueHandler = (key: string, file: File, meta?: FileMetadata) => {
setQueue((prev) => {
const newState = new Map(prev);
const newValue: FileQueueValueType = { file };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { RefObject, useLayoutEffect } from 'react';
import { FileQueueValueMetaType } from '../../types/fileUploader';
import { FileMetadata } from '../../types/fileUploader';
import { getAttachmentInput, getAttachmentMetaInput } from './utils';

export interface UseFileUploaderAttachmentProps {
attachmentRef: RefObject<HTMLLIElement>;
file: File;
meta?: FileQueueValueMetaType;
meta?: FileMetadata;
name: string;
onError?: (error: string) => void;
}
Expand All @@ -18,13 +18,13 @@ export const useFileUploaderAttachment = ({
onError,
}: UseFileUploaderAttachmentProps) => {
useLayoutEffect(() => {
const createAttachmentInput = (metadata: FileQueueValueMetaType) => {
const createAttachmentInput = (metadata: FileMetadata) => {
attachmentRef.current?.querySelectorAll('input').forEach((element) => element.remove());
const attachmentInputElement = getAttachmentInput(file, name, onError) as Node;
attachmentRef.current?.appendChild(attachmentInputElement);
const attachmentInputElement = getAttachmentInput(file, name, onError);
attachmentInputElement && attachmentRef.current?.appendChild(attachmentInputElement);

if (metadata) {
const attachmentInputMetaElement = getAttachmentMetaInput(file, name, metadata) as Node;
const attachmentInputMetaElement = getAttachmentMetaInput(file, name, metadata);
attachmentRef.current?.appendChild(attachmentInputMetaElement);
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { CSSProperties } from 'react';
import classNames from 'classnames';
import { FileUploaderCropCSS } from '../../constants/dictionaries';
import { useClassNamePrefix } from '../../hooks';
import { FileQueueValueMetaType, FileUploaderQueueLimitBehaviorType, Validation } from '../../types';
import { FileMetadata, FileUploaderQueueLimitBehaviorType, Validation } from '../../types';

export interface FileUploaderStyleProps extends Validation {
isDragAndDropSupported?: boolean;
Expand All @@ -12,15 +13,15 @@ export interface FileUploaderStyleProps extends Validation {
isDropZoneHidden?: boolean;
isFluid?: boolean;
queueLimitBehavior?: FileUploaderQueueLimitBehaviorType;
meta?: FileQueueValueMetaType;
meta?: FileMetadata;
}

interface ImageCropCSS extends CSSProperties {
'--file-uploader-attachment-image-top'?: string;
'--file-uploader-attachment-image-left'?: string;
'--file-uploader-attachment-image-width'?: string;
'--file-uploader-attachment-image-height'?: string;
}
type ImageCropCSS = {
[FileUploaderCropCSS.TOP]?: string;
[FileUploaderCropCSS.LEFT]?: string;
[FileUploaderCropCSS.WIDTH]?: string;
[FileUploaderCropCSS.HEIGHT]?: string;
} & CSSProperties;

export interface FileUploaderStyleReturn {
/** className props */
Expand Down Expand Up @@ -81,10 +82,10 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU
const { x, y, width, height } = props?.meta || {};
const hasCoords = x != null && y != null && width != null && height != null;
const imageCropCSS: ImageCropCSS = {
'--file-uploader-attachment-image-top': `-${props?.meta?.y}px`,
'--file-uploader-attachment-image-left': `-${props?.meta?.x}px`,
'--file-uploader-attachment-image-width': `${props?.meta?.width}px`,
'--file-uploader-attachment-image-height': `${props?.meta?.height}px`,
[FileUploaderCropCSS.TOP]: `-${props?.meta?.y}px`,
[FileUploaderCropCSS.LEFT]: `-${props?.meta?.x}px`,
[FileUploaderCropCSS.WIDTH]: `${props?.meta?.width}px`,
[FileUploaderCropCSS.HEIGHT]: `${props?.meta?.height}px`,
};

return {
Expand Down
10 changes: 7 additions & 3 deletions packages/web-react/src/components/FileUploader/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { FileQueueValueMetaType } from '../../types/fileUploader';
import { FileMetadata } from '../../types/fileUploader';

const getAttachmentInput = (file: File, name: string, onError?: (error: string) => void) => {
const getAttachmentInput = (
file: File,
name: string,
onError?: (error: string) => void,
): HTMLInputElement | undefined => {
const attachmentInputElement = document.createElement('input');
const dataContainer = new DataTransfer();

Expand All @@ -27,7 +31,7 @@ const getAttachmentInput = (file: File, name: string, onError?: (error: string)
return attachmentInputElement;
};

const getAttachmentMetaInput = (file: File, name: string, meta: FileQueueValueMetaType) => {
const getAttachmentMetaInput = (file: File, name: string, meta: FileMetadata): HTMLInputElement => {
const attachmentInputElement = document.createElement('input');

attachmentInputElement.setAttribute('type', 'text');
Expand Down
8 changes: 8 additions & 0 deletions packages/web-react/src/constants/dictionaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,11 @@ export const ValidationStates = {
WARNING: 'warning',
DANGER: 'danger',
} as const;

/* FileUploader CSS crop */
export const FileUploaderCropCSS = {
TOP: '--file-uploader-attachment-image-top',
LEFT: '--file-uploader-attachment-image-left',
WIDTH: '--file-uploader-attachment-image-width',
HEIGHT: '--file-uploader-attachment-image-height',
} as const;
14 changes: 6 additions & 8 deletions packages/web-react/src/types/fileUploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,26 @@ export interface FileUploaderTextProps {
linkText?: string;
}

export interface FileQueueValueMetaType {
export interface FileMetadata {
[key: string | number]: unknown;
}

export interface FileQueueValueType {
file: File;
meta?: FileQueueValueMetaType;
meta?: FileMetadata;
}

export interface UpdateQueueBaseType {
export interface UpdateQueueBaseType extends FileQueueValueType {
key: string;
file: File;
meta?: FileQueueValueMetaType;
}

export interface FileUploaderHandlingProps {
addToQueue: (key: string, file: File, meta?: FileQueueValueMetaType) => FileQueueMapType;
addToQueue: (key: string, file: File, meta?: FileMetadata) => FileQueueMapType;
clearQueue: () => void;
fileQueue: FileQueueMapType;
findInQueue: (key: string) => FileQueueValueType | null;
onDismiss: (key: string) => FileQueueMapType;
updateQueue: (key: string, file: File, meta?: FileQueueValueMetaType) => FileQueueMapType;
updateQueue: (key: string, file: File, meta?: FileMetadata) => FileQueueMapType;
}

export interface FileUploaderErrorMessagesProps {
Expand Down Expand Up @@ -100,7 +98,7 @@ export interface FileUploaderAttachmentBaseProps extends Omit<SpiritLItemElement
iconName?: string;
id: string;
label: string;
meta?: FileQueueValueMetaType;
meta?: FileMetadata;
name: string;
onDismiss: (key: string, callback?: (key: string) => void) => FileQueueMapType;
onEdit?: (event: MouseEvent, file: File) => void;
Expand Down

0 comments on commit 5b28fb8

Please sign in to comment.