Skip to content

Commit

Permalink
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 10, 2023
1 parent 9249910 commit 13c1241
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const FileUploaderWithModalImagePreview = (args) => {
const [base64File, setBase64File] = useState<string>('');
const [fileToPreview, setFileToPreview] = useState<File | null>(null);
const { fileQueue, addToQueue, clearQueue, onDismiss, updateQueue } = useFileQueue();
console.log('fileQueue:', fileQueue);

const imagePreview = (key: string, file: File) => {
if (file.type.includes('image')) {
Expand Down Expand Up @@ -46,16 +47,18 @@ export const FileUploaderWithModalImagePreview = (args) => {
};

const confirmPreview = () => {
const meta = { x: 10, y: 10, width: 50, height: 50 };

setIsModalOpen(false);
addToQueue(fileToPreview?.name || '', fileToPreview as File);
addToQueue(fileToPreview?.name || '', fileToPreview as File, meta);
};

const onEdit = (event: MouseEvent, file: File) => {
imagePreview(file.name, file);
};

const attachmentComponent = ({ id, ...props }: SpiritFileUploaderAttachmentProps) => (
<FileUploaderAttachment key={id} id={id} onEdit={onEdit} {...props} />
const attachmentComponent = ({ id, meta, ...props }: SpiritFileUploaderAttachmentProps) => (
<FileUploaderAttachment key={id} id={id} meta={meta} onEdit={onEdit} {...props} />
);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import React from 'react';
import { FileQueueValueMetaType } from '../../types/fileUploader';
import { useFileUploaderStyleProps } from './useFileUploaderStyleProps';
import { IMAGE_DIMENSION } from './constants';

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

const AttachmentImagePreview = ({ label, imagePreview }: AttachmentImagePreviewProps) => {
const AttachmentImagePreview = ({ label, imagePreview, meta }: AttachmentImagePreviewProps) => {
const { classProps } = useFileUploaderStyleProps();

// TODO: Add CSS styles for crop
const { x, y, width, height } = meta || {};
console.log('x:', x, 'y:', y, 'width:', width, 'height:', height);

return (
<span className={classProps.attachment.image}>
<img src={imagePreview} width={IMAGE_DIMENSION} height={IMAGE_DIMENSION} alt={label} />
<img
src={imagePreview}
width={IMAGE_DIMENSION}
height={IMAGE_DIMENSION}
alt={label}
style={{
'--file-uploader-attachment-image-top': `-${y}px`,
'--file-uploader-attachment-image-left': `-${x}px`,
'--file-uploader-attachment-image-width': `${width}px`,
'--file-uploader-attachment-image-height': `${height}px`,
}}
/>
</span>
);
};

AttachmentImagePreview.defaultProps = {
meta: undefined,
};

export default AttachmentImagePreview;
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const FileUploaderAttachment = (props: SpiritFileUploaderAttachmentProps) => {
onEdit,
onError,
removeText,
meta,
...restProps
} = props;
const [imagePreview, setImagePreview] = useState<string>('');
Expand All @@ -51,7 +52,7 @@ const FileUploaderAttachment = (props: SpiritFileUploaderAttachmentProps) => {
image2Base64Preview(file, 100, (compressedDataURL) => setImagePreview(compressedDataURL));
}

useFileUploaderAttachment({ attachmentRef, file, name, onError });
useFileUploaderAttachment({ attachmentRef, file, name, meta, onError });

useDeprecationMessage({
method: 'property',
Expand Down Expand Up @@ -82,7 +83,7 @@ const FileUploaderAttachment = (props: SpiritFileUploaderAttachmentProps) => {
className={classNames(classProps.attachment.root, styleProps.className)}
>
{hasImagePreview && imagePreview ? (
<AttachmentImagePreview label={label} imagePreview={imagePreview} />
<AttachmentImagePreview label={label} imagePreview={imagePreview} meta={meta} />
) : (
<Icon name={iconName} aria-hidden="true" />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ const FileUploaderList = (props: SpiritFileUploaderListProps) => {

const renderAttachments = useMemo(() => {
const fileArray = Array.from(fileQueue, (entry) => {
return { key: entry[0], file: entry[1] };
return { key: entry[0], file: entry[1].file, meta: entry[1].meta };
});

return fileArray.map(
({ key, file }) =>
({ key, file, meta }) =>
attachmentComponent &&
attachmentComponent({
id: key,
label: file.name,
name: inputName,
file,
meta,
onDismiss,
hasImagePreview,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FileUploader, FileUploaderAttachment, FileUploaderInput, FileUploaderLi

const FileUploaderDefault = () => {
const { fileQueue, addToQueue, clearQueue, onDismiss, findInQueue, updateQueue } = useFileQueue();
console.log('fileQueue:', fileQueue);

const attachmentComponent = ({ id, ...props }: SpiritFileUploaderAttachmentProps) => (
<FileUploaderAttachment key={id} id={id} {...props} />
Expand Down
17 changes: 11 additions & 6 deletions packages/web-react/src/components/FileUploader/useFileQueue.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useState } from 'react';
import { FileUploaderHandlingProps } from '../../types';
import { FileQueueValueMetaType, FileQueueValueType, FileUploaderHandlingProps } from '../../types';

export interface FileQueueReturn extends FileUploaderHandlingProps {}

export const useFileQueue = (): FileQueueReturn => {
const [queue, setQueue] = useState<Map<string, File>>(new Map());
const [queue, setQueue] = useState<Map<string, FileQueueValueType>>(new Map());

const onDismissHandler = (name: string) => {
setQueue((prev) => {
Expand All @@ -17,18 +17,23 @@ export const useFileQueue = (): FileQueueReturn => {
return queue;
};

const addToQueueHandler = (key: string, file: File) => {
setQueue((prev) => new Map(prev.set(key, file)));
const addToQueueHandler = (key: string, file: File, meta?: FileQueueValueMetaType) => {
setQueue((prev) => {
const newValue: FileQueueValueType = { file };
if (typeof meta !== 'undefined') newValue.meta = meta;

return new Map(prev.set(key, newValue));
});

return queue;
};

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

const updateQueueHandler = (key: string, file: File) => {
const updateQueueHandler = (key: string, file: File, meta?: FileQueueValueMetaType) => {
setQueue((prev) => {
const newState = new Map(prev);
newState.set(key, file);
newState.set(key, { file, meta: meta || newState.get(key)?.meta });

return newState;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
import { RefObject, useEffect } from 'react';
import { getAttachmentInput } from './utils';
import { getAttachmentInput, getAttachmentMetaInput } from './utils';
import { FileQueueValueMetaType } from '../../types/fileUploader';

export interface UseFileUploaderAttachmentProps {
attachmentRef: RefObject<HTMLLIElement>;
file: File;
meta?: FileQueueValueMetaType;
name: string;
onError?: (error: string) => void;
}

export const useFileUploaderAttachment = ({ attachmentRef, file, name, onError }: UseFileUploaderAttachmentProps) => {
export const useFileUploaderAttachment = ({
attachmentRef,
file,
meta,
name,
onError,
}: UseFileUploaderAttachmentProps) => {
const createAttachmentInput = () => {
const attachmentInputElement = getAttachmentInput(file, name, onError) as Node;

attachmentRef.current?.appendChild(attachmentInputElement);

if (meta) {
const attachmentMetaInputElement = getAttachmentMetaInput(file, name, meta) as Node;

attachmentRef.current?.appendChild(attachmentMetaInputElement);
}
};

// const updateOrCreateAttachmentMetaInput = () => {
// const metaInput = attachmentRef.current?.querySelector(`input[name="${name}_meta"]`) as HTMLInputElement;

// if (metaInput) {
// metaInput.value = JSON.stringify(meta);
// } else {
// createAttachmentInput();
// }
// };

useEffect(() => {
createAttachmentInput();

Expand Down
14 changes: 13 additions & 1 deletion packages/web-react/src/components/FileUploader/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FileQueueValueMetaType } from '../../types/fileUploader';

const getAttachmentInput = (file: File, name: string, onError?: (error: string) => void) => {
const attachmentInputElement = document.createElement('input');
const dataContainer = new DataTransfer();
Expand Down Expand Up @@ -25,6 +27,16 @@ const getAttachmentInput = (file: File, name: string, onError?: (error: string)
return attachmentInputElement;
};

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

attachmentMetaInputElement.setAttribute('type', 'hidden');
attachmentMetaInputElement.setAttribute('name', `${name}_${file.name}_meta`);
attachmentMetaInputElement.setAttribute('value', JSON.stringify(meta));

return attachmentMetaInputElement;
};

const image2Base64Preview = (file: File, maxWidth: number, callback: (base64Preview: string) => void) => {
const reader = new FileReader();

Expand Down Expand Up @@ -59,4 +71,4 @@ const base64ToByteArray = (base64Image: string) => {
return byteArray;
};

export { getAttachmentInput, image2Base64Preview, base64ToByteArray };
export { getAttachmentInput, getAttachmentMetaInput, image2Base64Preview, base64ToByteArray };
18 changes: 14 additions & 4 deletions packages/web-react/src/types/fileUploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from './shared';

export type FileUploaderAttachmentComponentType = (props: FileUploaderAttachmentBaseProps) => ReactNode;
export type FileQueueMapType = Map<string, File>;
export type FileQueueMapType = Map<string, FileQueueValueType>;
export type FileUploaderErrorCallbackType = (error: string | Error) => void;
export type FileUploaderQueueLimitBehaviorType = 'hide' | 'disable' | 'none';

Expand All @@ -20,13 +20,22 @@ export interface FileUploaderTextProps {
linkText?: string;
}

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

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

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

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

0 comments on commit 13c1241

Please sign in to comment.