From 98c9132f62ab149601486066ca350fb7df44a89d Mon Sep 17 00:00:00 2001 From: Jose Manuel Serrano Amaut <a20122128@pucp.pe> Date: Sat, 11 Mar 2023 00:09:00 -0500 Subject: [PATCH] [FEAT]: Add prop smartImgFit in ImagePreview FileMosaic File Card and Avatar components --- .../ExtraComponentsMainPageAvatar.tsx | 12 +++- src/files-ui/components/avatar/Avatar.tsx | 4 +- src/files-ui/components/avatar/AvatarProps.ts | 29 ++++++-- .../components/file-card/FileCard.tsx | 7 +- .../FileMosaicImageLayer.tsx | 21 +++++- .../components/file-mosaic/FileMosaic.tsx | 3 + .../components/file-mosaic/FileMosaicProps.ts | 16 +++++ .../previews/ImagePreview/ImagePreview.tsx | 70 ++++++++++++++----- .../ImagePreview/ImagePreviewProps.ts | 31 +++++++- 9 files changed, 157 insertions(+), 36 deletions(-) diff --git a/src/components/MainPage/SecondaryRight/ExtraComponentsMainPageAvatar.tsx b/src/components/MainPage/SecondaryRight/ExtraComponentsMainPageAvatar.tsx index d1537b8..2bd6bff 100644 --- a/src/components/MainPage/SecondaryRight/ExtraComponentsMainPageAvatar.tsx +++ b/src/components/MainPage/SecondaryRight/ExtraComponentsMainPageAvatar.tsx @@ -63,10 +63,18 @@ const ExtraComponentsMainPageAvatar: React.FC<ExtraComponentsMainPageProps> = ( src={avatarSrc} onChange={handleChange} isUloading={isUloading} - smart={false} + smartImgFit={"center"} + style={{ width: "170px", height: "170px" }} + //variant={"circle"} + /> + <Avatar + src={avatarSrc} + onChange={handleChange} + isUloading={isUloading} + smartImgFit={"center"} variant={"circle"} + style={{ width: "170px", height: "170px" }} /> - <MaterialButton onClick={() => setAvatarSrc(undefined)} disabled={avatarSrc === undefined} diff --git a/src/files-ui/components/avatar/Avatar.tsx b/src/files-ui/components/avatar/Avatar.tsx index ec1a995..796af6a 100644 --- a/src/files-ui/components/avatar/Avatar.tsx +++ b/src/files-ui/components/avatar/Avatar.tsx @@ -21,7 +21,7 @@ const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { uploadingLabel, isUloading, onError, - smart, + smartImgFit, } = mergeProps(props, defaultAvatarProps); const inputRef: React.RefObject<HTMLInputElement> = @@ -80,7 +80,7 @@ const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { src={src} alt={alt} onError={handleError} - smart={smart} + smartImgFit={smartImgFit} /> ) : ( <div className={"fui-avatar-label"}>{emptyLabel}</div> diff --git a/src/files-ui/components/avatar/AvatarProps.ts b/src/files-ui/components/avatar/AvatarProps.ts index 53384ba..513826b 100644 --- a/src/files-ui/components/avatar/AvatarProps.ts +++ b/src/files-ui/components/avatar/AvatarProps.ts @@ -29,16 +29,32 @@ export interface AvatarFullProps extends OverridableComponentProps { * In that case height will be set to 100%. Otherwise width will be set to 100% */ smart?: boolean; + /** + * If not present, image width will be set to 100%. + * + * If present, image will be analized and displayed according to its heigh and width. + * Image width height greater than its width has a "portrait" orientation. + * Otherwise it has a "landscape" orientation. + * - If value is "orientation", image will be displayed complete by giving 100% + * to width prop if the orientation is "landscape". + * When orientation is "portrait", height prop will be set to 100%. Some images + * will show an empty space. + * - If value is "center", image will be centered and will not be displayed complete. + * This the empty space is avoided. This is achived by giving 100% to width prop if + * the orientation is "portrait". When orientation is "landscape", height prop will be set to 100%. + * @default orientation + */ + smartImgFit?: false | "orientation" | "center"; } export declare type AvatarProps = - /* { - [D in keyof React.HTMLProps<HTMLDivElement>]: React.HTMLProps<HTMLDivElement>[D] - } & */ -{ - [P in keyof AvatarFullProps]: AvatarFullProps[P]; + /* { + [D in keyof React.HTMLProps<HTMLDivElement>]: React.HTMLProps<HTMLDivElement>[D] + } & */ + { + [P in keyof AvatarFullProps]: AvatarFullProps[P]; -} + } //React.HTMLProps<HTMLDivElement> export const defaultAvatarProps: AvatarProps = { @@ -49,4 +65,5 @@ export const defaultAvatarProps: AvatarProps = uploadingLabel: "Uploading...", readOnly: false, smart: false, + smartImgFit: "orientation", } \ No newline at end of file diff --git a/src/files-ui/components/file-card/FileCard.tsx b/src/files-ui/components/file-card/FileCard.tsx index 10f8b97..1af0ffb 100644 --- a/src/files-ui/components/file-card/FileCard.tsx +++ b/src/files-ui/components/file-card/FileCard.tsx @@ -104,7 +104,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { onRightClick, elevation = 4, - + smartImgFit = "orientation", //} = mergeProps(props, FileCardPropsDefault); } = props; @@ -268,6 +268,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { fileName={localName} url={url} isBlur={true} + smartImgFit={false} /> </Layer> {/** IMAGE LAYER NO BLUR */} @@ -277,6 +278,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { url={url} fileName={localName} isBlur={false} + smartImgFit={smartImgFit} /> </Layer> <Layer className="file-card-status-layer" visible={true}> @@ -300,7 +302,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { </div> </div> </Layer> - + {/** INFO LAYER */} <Layer className="file-card-info-layer-container" @@ -333,7 +335,6 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { /> </div> </Layer> - </LayerContainer> <FileCardRightActions deleteIcon={onDelete !== undefined} diff --git a/src/files-ui/components/file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer.tsx b/src/files-ui/components/file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer.tsx index 1f0f59b..4ce3ba9 100644 --- a/src/files-ui/components/file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer.tsx +++ b/src/files-ui/components/file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer.tsx @@ -22,12 +22,28 @@ interface FileMosaicImageLayerProps { * */ isBlur?: boolean; + /** + * If not present, image width will be set to 100%. + * + * If present, image will be analized and displayed according to its heigh and width. + * Image width height greater than its width has a "portrait" orientation. + * Otherwise it has a "landscape" orientation. + * - If value is "orientation", image will be displayed complete by giving 100% + * to width prop if the orientation is "landscape". + * When orientation is "portrait", height prop will be set to 100%. Some images + * will show an empty space. + * - If value is "center", image will be centered and will not be displayed complete. + * This the empty space is avoided. This is achived by giving 100% to width prop if + * the orientation is "portrait". When orientation is "landscape", height prop will be set to 100%. + * @default orientation + */ + smartImgFit?: false | "orientation" | "center"; } const FileMosaicImageLayer: React.FC<FileMosaicImageLayerProps> = ( props: FileMosaicImageLayerProps ) => { //console.log("FileMosaicImageLayer", props); - const { imageSource, url, fileName, card, isBlur } = props; + const { imageSource, url, fileName, card, isBlur,smartImgFit } = props; const [localSource, setLocalSource] = React.useState<string | undefined>( undefined @@ -58,7 +74,7 @@ const FileMosaicImageLayer: React.FC<FileMosaicImageLayerProps> = ( <ImagePreview src={localSource} alt={`blur ${fileName}`} - smart={false} + smartImgFit={false} /> )} </React.Fragment> @@ -71,6 +87,7 @@ const FileMosaicImageLayer: React.FC<FileMosaicImageLayerProps> = ( src={localSource} style={{ borderRadius: "0px" }} alt={`preview ${fileName}`} + smartImgFit={smartImgFit} /> </React.Fragment> ); diff --git a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx index a1b9c4d..c6b9d63 100644 --- a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx +++ b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx @@ -65,6 +65,7 @@ const FileMosaic: React.FC<FileMosaicProps> = (props: FileMosaicProps) => { onDoubleClick, onClick, onRightClick, + smartImgFit, } = props; //ref for anchor download element @@ -232,6 +233,7 @@ const FileMosaic: React.FC<FileMosaicProps> = (props: FileMosaicProps) => { url={url} fileName={localName} isBlur={true} + smartImgFit={false} /> </Layer> @@ -242,6 +244,7 @@ const FileMosaic: React.FC<FileMosaicProps> = (props: FileMosaicProps) => { url={url} fileName={localName} isBlur={false} + smartImgFit={smartImgFit} /> </Layer> diff --git a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaicProps.ts b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaicProps.ts index 29d1948..b4e2932 100644 --- a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaicProps.ts +++ b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaicProps.ts @@ -145,6 +145,22 @@ export interface FileMosaicPropsMap extends OverridableComponentProps { * In case onDownload prop is given */ downloadUrl?: string; + /** + * If not present, image width will be set to 100%. + * + * If present, image will be analized and displayed according to its heigh and width. + * Image width height greater than its width has a "portrait" orientation. + * Otherwise it has a "landscape" orientation. + * - If value is "orientation", image will be displayed complete by giving 100% + * to width prop if the orientation is "landscape". + * When orientation is "portrait", height prop will be set to 100%. Some images + * will show an empty space. + * - If value is "center", image will be centered and will not be displayed complete. + * This the empty space is avoided. This is achived by giving 100% to width prop if + * the orientation is "portrait". When orientation is "landscape", height prop will be set to 100%. + * @default orientation + */ + smartImgFit?: false | "orientation" | "center"; } //React.HTMLProps<HTMLDivElement> export type FileMosaicProps = diff --git a/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx b/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx index 3f0c0e4..d692c65 100644 --- a/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx +++ b/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx @@ -11,8 +11,21 @@ import "./ImagePreview.scss"; const ImagePreview: React.FC<ImagePreviewProps> = ( props: ImagePreviewProps ) => { - const { src, alt, className, style, width, height, onError, smart } = - mergeProps(props, ImagePreviewDefaultProps); + const { + src, + alt, + className, + style, + width, + height, + onError, + smart, + smartImgFit, + } = mergeProps(props, ImagePreviewDefaultProps); + + const [[finalHeight, finalWidth], setfinalDimensions] = React.useState< + [number | undefined, number | undefined] + >([undefined, undefined]); //console.table({ src, alt, className, style, width, height }); const [source, setSource] = React.useState<string | undefined>(undefined); @@ -30,21 +43,42 @@ const ImagePreview: React.FC<ImagePreviewProps> = ( setSource(imageSource); - if (!smart) return; + let finalHeight = undefined; + let finalWidth = undefined; - const orientation: "landscape" | "portrait" = await getImageOrientation( - imageSource - ); - setOrientation(orientation); + if (!smartImgFit) { + //if not given + finalWidth = 100; + } else { + const orientation: "landscape" | "portrait" = await getImageOrientation( + imageSource + ); + if (orientation === "landscape") { + if (smartImgFit === "orientation") { + finalHeight = undefined; + finalWidth = 100; + } else { + finalHeight = 100; + finalWidth = undefined; + } + } else { + if (smartImgFit === "center") { + finalHeight = undefined; + finalWidth = 100; + } else { + finalHeight = 100; + finalWidth = undefined; + } + } + } + setfinalDimensions([finalHeight, finalWidth]); setSource(imageSource); }; React.useEffect(() => { //if not undefined - if (!src) { - return; - } + if (!src) return; //console.log("ImagePreview There is source :D"); if (typeof src === "string") { @@ -53,20 +87,18 @@ const ImagePreview: React.FC<ImagePreviewProps> = ( } else { //if a File object is given, check if is a supported format and read it const headerMime = src.type ? src.type.split("/")[0] : "octet"; - - if (headerMime === "image") { - //set the video source and create the uri string if is a supported video format + if (headerMime === "image") + //set the image source and create the uri string if it's a supported image format getSource(src); - } } // eslint-disable-next-line }, [src]); //console.log("ImagePreview", src, source); - const finalWidth: string | number | undefined = + /* const finalWidth: string | number | undefined = width || (orientation === "landscape" && smart ? "100%" : undefined); const finalHeight: string | number | undefined = - height || (orientation === "portrait" && smart ? "100%" : undefined); + height || (orientation === "portrait" && smart ? "100%" : undefined); */ console.log("Image result", finalHeight, finalWidth, orientation, smart); const handleError = (evt: React.SyntheticEvent<HTMLImageElement, Event>) => { @@ -76,14 +108,14 @@ const ImagePreview: React.FC<ImagePreviewProps> = ( return ( <React.Fragment> - {src && source && ( + {src && source && (finalHeight || finalWidth) && ( <img style={style || {}} onClick={(evt) => { evt.preventDefault(); }} - width={!smart && !finalWidth?"100%":finalWidth} - height={finalHeight} + width={finalWidth?`${finalWidth}%`:finalWidth} + height={finalHeight?`${finalHeight}%`:finalHeight} src={source} alt={alt} className={className} diff --git a/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts b/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts index f008f69..a6b6b86 100644 --- a/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts +++ b/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts @@ -2,7 +2,7 @@ import { OverridableComponentProps } from "../../overridable"; -export interface ImagePreviewProps extends OverridableComponentProps { +export interface ImagePreviewFullProps extends OverridableComponentProps { /** * Image source in string format (URL) or File Object (Will be read as URL) */ @@ -31,12 +31,39 @@ export interface ImagePreviewProps extends OverridableComponentProps { * In that case height will be set to 100%. Otherwise width will be set to 100% */ smart?: boolean; + /** + * If not present, image width will be set to 100%. + * + * If present, image will be analized and displayed according to its heigh and width. + * Image width height greater than its width has a "portrait" orientation. + * Otherwise it has a "landscape" orientation. + * - If value is "orientation", image will be displayed complete by giving 100% + * to width prop if the orientation is "landscape". + * When orientation is "portrait", height prop will be set to 100%. Some images + * will show an empty space. + * - If value is "center", image will be centered and will not be displayed complete. + * This the empty space is avoided. This is achived by giving 100% to width prop if + * the orientation is "portrait". When orientation is "landscape", height prop will be set to 100%. + * @default orientation + */ + smartImgFit?: false | "orientation" | "center"; } +/* +type DefImageProps = React.HTMLProps<HTMLImageElement>; +type ImgPropsOmitImagePreviewFullProps = Omit<DefImageProps, keyof ImagePreviewFullProps>; + */ + +export declare type ImagePreviewProps = + //ImgPropsOmitImagePreviewFullProps & + { + [I in keyof ImagePreviewFullProps]: ImagePreviewFullProps[I] + } + export const ImagePreviewDefaultProps: ImagePreviewProps = { //width: "100%", //height: "100%", alt: "image-preview", //className: "fui-image-preview" - smart:true + smartImgFit: "orientation" } \ No newline at end of file -- GitLab