@lumx/react 2.1.9-alpha-thumbnail2 → 2.1.9-alpha-thumbnail3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,7 +68,6 @@ var ImageBlock = forwardRef(function (props, ref) {
68
68
  }), fillHeight && "".concat(CLASSNAME, "--fill-height"))
69
69
  }), React.createElement(Thumbnail, _extends({}, thumbnailProps, {
70
70
  className: classnames("".concat(CLASSNAME, "__image"), thumbnailProps === null || thumbnailProps === void 0 ? void 0 : thumbnailProps.className),
71
- fillHeight: fillHeight,
72
71
  align: align,
73
72
  image: image,
74
73
  size: size,
@@ -1 +1 @@
1
- {"version":3,"file":"ImageBlock.js","sources":["../../../src/components/image-block/ImageBlock.tsx"],"sourcesContent":["import React, { CSSProperties, forwardRef, ReactNode } from 'react';\n\nimport classNames from 'classnames';\n\nimport isObject from 'lodash/isObject';\n\nimport { Alignment, HorizontalAlignment, Size, Theme, Thumbnail } from '@lumx/react';\n\nimport { Comp, GenericProps, getRootClassName, handleBasicClasses, ValueOf } from '@lumx/react/utils';\nimport { ThumbnailProps } from '../thumbnail/Thumbnail';\n\n/**\n * Image block variants.\n */\nexport const ImageBlockCaptionPosition = {\n below: 'below',\n over: 'over',\n} as const;\nexport type ImageBlockCaptionPosition = ValueOf<typeof ImageBlockCaptionPosition>;\n\n/**\n * Image block sizes.\n */\nexport type ImageBlockSize = Extract<Size, 'xl' | 'xxl'>;\n\n/**\n * Defines the props of the component.\n */\nexport interface ImageBlockProps extends GenericProps {\n /** Action toolbar content. */\n actions?: ReactNode;\n /** Alignment. */\n align?: HorizontalAlignment;\n /** Image alternative text. */\n alt: string;\n /** Caption position. */\n captionPosition?: ImageBlockCaptionPosition;\n /** Caption custom CSS style. */\n captionStyle?: CSSProperties;\n /** Image description. Can be either a string, or sanitized html. */\n description?: string | { __html: string };\n /** Whether the image has to fill its container height or not. */\n fillHeight?: boolean;\n /** Image URL. */\n image: string;\n /** Size variant. */\n size?: ImageBlockSize;\n /** Tag content. */\n tags?: ReactNode;\n /** Theme adapting the component to light or dark background. */\n theme?: Theme;\n /** Props to pass to the thumbnail (minus those already set by the ImageBlock props). */\n thumbnailProps?: Omit<ThumbnailProps, 'image' | 'size' | 'theme' | 'align' | 'fillHeight'>;\n /** Image title to display in the caption. */\n title?: string;\n}\n\n/**\n * Component display name.\n */\nconst COMPONENT_NAME = 'ImageBlock';\n\n/**\n * Component default class name and class prefix.\n */\nconst CLASSNAME = getRootClassName(COMPONENT_NAME);\n\n/**\n * Component default props.\n */\nconst DEFAULT_PROPS: Partial<ImageBlockProps> = {\n captionPosition: ImageBlockCaptionPosition.below,\n theme: Theme.light,\n align: Alignment.left,\n};\n\n/**\n * ImageBlock component.\n *\n * @param props Component props.\n * @param ref Component ref.\n * @return React element.\n */\nexport const ImageBlock: Comp<ImageBlockProps, HTMLDivElement> = forwardRef((props, ref) => {\n const {\n actions,\n align,\n alt,\n captionPosition,\n captionStyle,\n className,\n description,\n fillHeight,\n image,\n size,\n tags,\n theme,\n thumbnailProps,\n title,\n ...forwardedProps\n } = props;\n return (\n <figure\n ref={ref}\n {...forwardedProps}\n className={classNames(\n className,\n handleBasicClasses({\n prefix: CLASSNAME,\n captionPosition,\n align,\n size,\n theme,\n }),\n fillHeight && `${CLASSNAME}--fill-height`,\n )}\n >\n <Thumbnail\n {...thumbnailProps}\n className={classNames(`${CLASSNAME}__image`, thumbnailProps?.className)}\n fillHeight={fillHeight}\n align={align}\n image={image}\n size={size}\n theme={theme}\n alt={(alt || title) as string}\n />\n {(title || description || tags) && (\n <figcaption className={`${CLASSNAME}__wrapper`} style={captionStyle}>\n {(title || description) && (\n <div className={`${CLASSNAME}__caption`}>\n {title && <span className={`${CLASSNAME}__title`}>{title}</span>}\n {/* Add an `&nbsp;` when there is description and title. */}\n {title && description && '\\u00A0'}\n {isObject(description) && description.__html ? (\n // eslint-disable-next-line react/no-danger\n <span dangerouslySetInnerHTML={description} className={`${CLASSNAME}__description`} />\n ) : (\n <span className={`${CLASSNAME}__description`}>{description}</span>\n )}\n </div>\n )}\n {tags && <div className={`${CLASSNAME}__tags`}>{tags}</div>}\n </figcaption>\n )}\n {actions && <div className={`${CLASSNAME}__actions`}>{actions}</div>}\n </figure>\n );\n});\nImageBlock.displayName = COMPONENT_NAME;\nImageBlock.className = CLASSNAME;\nImageBlock.defaultProps = DEFAULT_PROPS;\n"],"names":["ImageBlockCaptionPosition","below","over","COMPONENT_NAME","CLASSNAME","getRootClassName","DEFAULT_PROPS","captionPosition","theme","Theme","light","align","Alignment","left","ImageBlock","forwardRef","props","ref","actions","alt","captionStyle","className","description","fillHeight","image","size","tags","thumbnailProps","title","forwardedProps","classNames","handleBasicClasses","prefix","isObject","__html","displayName","defaultProps"],"mappings":"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"}
1
+ {"version":3,"file":"ImageBlock.js","sources":["../../../src/components/image-block/ImageBlock.tsx"],"sourcesContent":["import React, { CSSProperties, forwardRef, ReactNode } from 'react';\n\nimport classNames from 'classnames';\n\nimport isObject from 'lodash/isObject';\n\nimport { Alignment, HorizontalAlignment, Size, Theme, Thumbnail } from '@lumx/react';\n\nimport { Comp, GenericProps, getRootClassName, handleBasicClasses, ValueOf } from '@lumx/react/utils';\nimport { ThumbnailProps } from '../thumbnail/Thumbnail';\n\n/**\n * Image block variants.\n */\nexport const ImageBlockCaptionPosition = {\n below: 'below',\n over: 'over',\n} as const;\nexport type ImageBlockCaptionPosition = ValueOf<typeof ImageBlockCaptionPosition>;\n\n/**\n * Image block sizes.\n */\nexport type ImageBlockSize = Extract<Size, 'xl' | 'xxl'>;\n\n/**\n * Defines the props of the component.\n */\nexport interface ImageBlockProps extends GenericProps {\n /** Action toolbar content. */\n actions?: ReactNode;\n /** Alignment. */\n align?: HorizontalAlignment;\n /** Image alternative text. */\n alt: string;\n /** Caption position. */\n captionPosition?: ImageBlockCaptionPosition;\n /** Caption custom CSS style. */\n captionStyle?: CSSProperties;\n /** Image description. Can be either a string, or sanitized html. */\n description?: string | { __html: string };\n /** Whether the image has to fill its container height or not. */\n fillHeight?: boolean;\n /** Image URL. */\n image: string;\n /** Size variant. */\n size?: ImageBlockSize;\n /** Tag content. */\n tags?: ReactNode;\n /** Theme adapting the component to light or dark background. */\n theme?: Theme;\n /** Props to pass to the thumbnail (minus those already set by the ImageBlock props). */\n thumbnailProps?: Omit<ThumbnailProps, 'image' | 'size' | 'theme' | 'align' | 'fillHeight'>;\n /** Image title to display in the caption. */\n title?: string;\n}\n\n/**\n * Component display name.\n */\nconst COMPONENT_NAME = 'ImageBlock';\n\n/**\n * Component default class name and class prefix.\n */\nconst CLASSNAME = getRootClassName(COMPONENT_NAME);\n\n/**\n * Component default props.\n */\nconst DEFAULT_PROPS: Partial<ImageBlockProps> = {\n captionPosition: ImageBlockCaptionPosition.below,\n theme: Theme.light,\n align: Alignment.left,\n};\n\n/**\n * ImageBlock component.\n *\n * @param props Component props.\n * @param ref Component ref.\n * @return React element.\n */\nexport const ImageBlock: Comp<ImageBlockProps, HTMLDivElement> = forwardRef((props, ref) => {\n const {\n actions,\n align,\n alt,\n captionPosition,\n captionStyle,\n className,\n description,\n fillHeight,\n image,\n size,\n tags,\n theme,\n thumbnailProps,\n title,\n ...forwardedProps\n } = props;\n return (\n <figure\n ref={ref}\n {...forwardedProps}\n className={classNames(\n className,\n handleBasicClasses({\n prefix: CLASSNAME,\n captionPosition,\n align,\n size,\n theme,\n }),\n fillHeight && `${CLASSNAME}--fill-height`,\n )}\n >\n <Thumbnail\n {...thumbnailProps}\n className={classNames(`${CLASSNAME}__image`, thumbnailProps?.className)}\n align={align}\n image={image}\n size={size}\n theme={theme}\n alt={(alt || title) as string}\n />\n {(title || description || tags) && (\n <figcaption className={`${CLASSNAME}__wrapper`} style={captionStyle}>\n {(title || description) && (\n <div className={`${CLASSNAME}__caption`}>\n {title && <span className={`${CLASSNAME}__title`}>{title}</span>}\n {/* Add an `&nbsp;` when there is description and title. */}\n {title && description && '\\u00A0'}\n {isObject(description) && description.__html ? (\n // eslint-disable-next-line react/no-danger\n <span dangerouslySetInnerHTML={description} className={`${CLASSNAME}__description`} />\n ) : (\n <span className={`${CLASSNAME}__description`}>{description}</span>\n )}\n </div>\n )}\n {tags && <div className={`${CLASSNAME}__tags`}>{tags}</div>}\n </figcaption>\n )}\n {actions && <div className={`${CLASSNAME}__actions`}>{actions}</div>}\n </figure>\n );\n});\nImageBlock.displayName = COMPONENT_NAME;\nImageBlock.className = CLASSNAME;\nImageBlock.defaultProps = DEFAULT_PROPS;\n"],"names":["ImageBlockCaptionPosition","below","over","COMPONENT_NAME","CLASSNAME","getRootClassName","DEFAULT_PROPS","captionPosition","theme","Theme","light","align","Alignment","left","ImageBlock","forwardRef","props","ref","actions","alt","captionStyle","className","description","fillHeight","image","size","tags","thumbnailProps","title","forwardedProps","classNames","handleBasicClasses","prefix","isObject","__html","displayName","defaultProps"],"mappings":"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"}
@@ -73,9 +73,9 @@ var DEFAULT_PROPS = {
73
73
 
74
74
  function getObjectPosition(aspectRatio, focusPoint) {
75
75
  if (aspectRatio === AspectRatio.original || !(focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.y) && !(focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.x)) return undefined;
76
- var x = (((focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.x) || 0) + 1) / 2 * 100;
77
- var y = (((focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.y) || 0) - 1) / 2 * 100;
78
- return "".concat(Math.round(x), "% ").concat(Math.round(y), "%");
76
+ var x = Math.round(Math.abs((((focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.x) || 0) + 1) / 2) * 100);
77
+ var y = Math.round(Math.abs((((focusPoint === null || focusPoint === void 0 ? void 0 : focusPoint.y) || 0) - 1) / 2) * 100);
78
+ return "".concat(x, "% ").concat(y, "%");
79
79
  }
80
80
  /**
81
81
  * Thumbnail component.
@@ -1 +1 @@
1
- {"version":3,"file":"Thumbnail2.js","sources":["../../../src/components/thumbnail/useImageLoad.ts","../../../src/components/thumbnail/Thumbnail.tsx"],"sourcesContent":["import { RefObject, useEffect, useState } from 'react';\n\nexport type LoadingState = 'isLoading' | 'isLoaded' | 'hasError';\n\nfunction getState(img: HTMLImageElement | null | undefined, event?: Event) {\n // Error event occurred or image loaded empty.\n if (event?.type === 'error' || (img?.complete && (img?.naturalWidth === 0 || img?.naturalHeight === 0))) {\n return 'hasError';\n }\n // Image is undefined or incomplete.\n if (!img || !img.complete) {\n return 'isLoading';\n }\n // Else loaded.\n return 'isLoaded';\n}\n\nexport function useImageLoad(imageURL: string, imgRef?: RefObject<HTMLImageElement>): LoadingState {\n const [state, setState] = useState<LoadingState>(getState(imgRef?.current));\n\n // Update state when changing image URL or DOM reference.\n useEffect(() => {\n setState(getState(imgRef?.current));\n }, [imageURL, imgRef]);\n\n // Listen to `load` and `error` event on image\n useEffect(() => {\n const img = imgRef?.current;\n if (!img) return undefined;\n const update = (event?: Event) => setState(getState(img, event));\n img.addEventListener('load', update);\n img.addEventListener('error', update);\n return () => {\n img.removeEventListener('load', update);\n img.removeEventListener('error', update);\n };\n }, [imgRef, imgRef?.current?.src]);\n\n return state;\n}\n","import React, {\n forwardRef,\n ImgHTMLAttributes,\n KeyboardEventHandler,\n MouseEventHandler,\n ReactElement,\n ReactNode,\n Ref,\n useRef,\n} from 'react';\nimport classNames from 'classnames';\n\nimport { AspectRatio, HorizontalAlignment, Icon, Size, Theme } from '@lumx/react';\n\nimport { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';\n\nimport { mdiImageBroken } from '@lumx/icons';\nimport { mergeRefs } from '@lumx/react/utils/mergeRefs';\nimport { useImageLoad } from '@lumx/react/components/thumbnail/useImageLoad';\nimport { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';\n\ntype ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;\n\n/**\n * Defines the props of the component.\n */\nexport interface ThumbnailProps extends GenericProps {\n /** Alignment of the thumbnail in it's parent (requires flex parent). */\n align?: HorizontalAlignment;\n /** Image alternative text. */\n alt: string;\n /** Image aspect ratio. */\n aspectRatio?: AspectRatio;\n /** Badge. */\n badge?: ReactElement;\n /** Image cross origin resource policy. */\n crossOrigin?: ImgHTMLProps['crossOrigin'];\n /** Fallback icon (SVG path) or react node when image fails to load. */\n fallback?: string | ReactNode;\n /** Whether the thumbnail should fill it's parent size (requires flex parent) or not. */\n fillHeight?: boolean;\n /** Apply relative vertical and horizontal shift (from -1 to 1) on the image position inside the thumbnail. */\n focusPoint?: FocusPoint;\n /** Image URL. */\n image: string;\n /** Props to inject into the native <img> element. */\n imgProps?: ImgHTMLProps;\n /** Reference to the native <img> element. */\n imgRef?: Ref<HTMLImageElement>;\n /** Set to true to force the display of the loading skeleton. */\n isLoading?: boolean;\n /** Size variant of the component. */\n size?: ThumbnailSize;\n /** Image loading mode. */\n loading?: ImgHTMLProps['loading'];\n /** On click callback. */\n onClick?: MouseEventHandler<HTMLDivElement>;\n /** On key press callback. */\n onKeyPress?: KeyboardEventHandler<HTMLDivElement>;\n /** Theme adapting the component to light or dark background. */\n theme?: Theme;\n /** Variant of the component. */\n variant?: ThumbnailVariant;\n /** Props to pass to the link wrapping the thumbnail. */\n linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;\n /** Custom react component for the link (can be used to inject react router Link). */\n linkAs?: 'a' | any;\n}\n\n/**\n * Component display name.\n */\nconst COMPONENT_NAME = 'Thumbnail';\n\n/**\n * Component default class name and class prefix.\n */\nconst CLASSNAME = getRootClassName(COMPONENT_NAME);\n\n/**\n * Component default props.\n */\nconst DEFAULT_PROPS: Partial<ThumbnailProps> = {\n fallback: mdiImageBroken,\n loading: 'lazy',\n theme: Theme.light,\n};\n\nfunction getObjectPosition(aspectRatio: AspectRatio, focusPoint?: FocusPoint) {\n if (aspectRatio === AspectRatio.original || (!focusPoint?.y && !focusPoint?.x)) return undefined;\n const x = (((focusPoint?.x || 0) + 1) / 2) * 100;\n const y = (((focusPoint?.y || 0) - 1) / 2) * 100;\n return `${Math.round(x)}% ${Math.round(y)}%`;\n}\n\n/**\n * Thumbnail component.\n *\n * @param props Component props.\n * @param ref Component ref.\n * @return React element.\n */\nexport const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {\n const {\n align,\n alt,\n aspectRatio = AspectRatio.original,\n badge,\n className,\n crossOrigin,\n fallback,\n fillHeight,\n focusPoint,\n image,\n imgProps,\n imgRef: propImgRef,\n isLoading: isLoadingProp,\n loading,\n size,\n theme,\n variant,\n linkProps,\n linkAs,\n showSkeletonLoading = true,\n ...forwardedProps\n } = props;\n const imgRef = useRef<HTMLImageElement>(null);\n\n // Image loading state.\n const loadingState = useImageLoad(image, imgRef);\n const isLoading = isLoadingProp || loadingState === 'isLoading';\n const hasError = loadingState === 'hasError';\n\n const isLink = Boolean(linkProps?.href || linkAs);\n const isButton = !!forwardedProps.onClick;\n const isClickable = isButton || isLink;\n\n let Wrapper: any = 'div';\n const wrapperProps = { ...forwardedProps };\n if (isLink) {\n Wrapper = linkAs || 'a';\n Object.assign(wrapperProps, linkProps);\n } else if (isButton) {\n Wrapper = 'button';\n }\n\n return (\n <Wrapper\n {...wrapperProps}\n ref={ref}\n className={classNames(\n linkProps?.className,\n className,\n handleBasicClasses({\n align,\n aspectRatio,\n prefix: CLASSNAME,\n size,\n theme,\n variant,\n isClickable,\n hasError,\n isLoading: showSkeletonLoading && isLoading,\n hasBadge: !!badge,\n }),\n fillHeight && `${CLASSNAME}--fill-height`,\n )}\n >\n <div className={`${CLASSNAME}__background`}>\n <img\n {...imgProps}\n style={{\n ...imgProps?.style,\n // Hide on error.\n visibility: hasError ? 'hidden' : undefined,\n // Focus point.\n objectPosition: getObjectPosition(aspectRatio, focusPoint),\n }}\n ref={mergeRefs(imgRef, propImgRef)}\n className={classNames(`${CLASSNAME}__image`, isLoading && `${CLASSNAME}__image--is-loading`)}\n crossOrigin={crossOrigin}\n src={image}\n alt={alt}\n loading={loading}\n />\n {!isLoading && hasError && (\n <div className={`${CLASSNAME}__fallback`}>\n {typeof fallback === 'string' ? (\n <Icon icon={fallback} size={Size.xxs} theme={theme} />\n ) : (\n fallback\n )}\n </div>\n )}\n </div>\n {badge &&\n React.cloneElement(badge, { className: classNames(`${CLASSNAME}__badge`, badge.props.className) })}\n </Wrapper>\n );\n});\nThumbnail.displayName = COMPONENT_NAME;\nThumbnail.className = CLASSNAME;\nThumbnail.defaultProps = DEFAULT_PROPS;\n"],"names":["getState","img","event","type","complete","naturalWidth","naturalHeight","useImageLoad","imageURL","imgRef","useState","current","state","setState","useEffect","undefined","update","addEventListener","removeEventListener","src","COMPONENT_NAME","CLASSNAME","getRootClassName","DEFAULT_PROPS","fallback","mdiImageBroken","loading","theme","Theme","light","getObjectPosition","aspectRatio","focusPoint","AspectRatio","original","y","x","Math","round","Thumbnail","forwardRef","props","ref","align","alt","badge","className","crossOrigin","fillHeight","image","imgProps","propImgRef","isLoadingProp","isLoading","size","variant","linkProps","linkAs","showSkeletonLoading","forwardedProps","useRef","loadingState","hasError","isLink","Boolean","href","isButton","onClick","isClickable","Wrapper","wrapperProps","Object","assign","classNames","handleBasicClasses","prefix","hasBadge","style","visibility","objectPosition","mergeRefs","Size","xxs","React","cloneElement","displayName","defaultProps"],"mappings":"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"}
1
+ {"version":3,"file":"Thumbnail2.js","sources":["../../../src/components/thumbnail/useImageLoad.ts","../../../src/components/thumbnail/Thumbnail.tsx"],"sourcesContent":["import { RefObject, useEffect, useState } from 'react';\n\nexport type LoadingState = 'isLoading' | 'isLoaded' | 'hasError';\n\nfunction getState(img: HTMLImageElement | null | undefined, event?: Event) {\n // Error event occurred or image loaded empty.\n if (event?.type === 'error' || (img?.complete && (img?.naturalWidth === 0 || img?.naturalHeight === 0))) {\n return 'hasError';\n }\n // Image is undefined or incomplete.\n if (!img || !img.complete) {\n return 'isLoading';\n }\n // Else loaded.\n return 'isLoaded';\n}\n\nexport function useImageLoad(imageURL: string, imgRef?: RefObject<HTMLImageElement>): LoadingState {\n const [state, setState] = useState<LoadingState>(getState(imgRef?.current));\n\n // Update state when changing image URL or DOM reference.\n useEffect(() => {\n setState(getState(imgRef?.current));\n }, [imageURL, imgRef]);\n\n // Listen to `load` and `error` event on image\n useEffect(() => {\n const img = imgRef?.current;\n if (!img) return undefined;\n const update = (event?: Event) => setState(getState(img, event));\n img.addEventListener('load', update);\n img.addEventListener('error', update);\n return () => {\n img.removeEventListener('load', update);\n img.removeEventListener('error', update);\n };\n }, [imgRef, imgRef?.current?.src]);\n\n return state;\n}\n","import React, {\n forwardRef,\n ImgHTMLAttributes,\n KeyboardEventHandler,\n MouseEventHandler,\n ReactElement,\n ReactNode,\n Ref,\n useRef,\n} from 'react';\nimport classNames from 'classnames';\n\nimport { AspectRatio, HorizontalAlignment, Icon, Size, Theme } from '@lumx/react';\n\nimport { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';\n\nimport { mdiImageBroken } from '@lumx/icons';\nimport { mergeRefs } from '@lumx/react/utils/mergeRefs';\nimport { useImageLoad } from '@lumx/react/components/thumbnail/useImageLoad';\nimport { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';\n\ntype ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;\n\n/**\n * Defines the props of the component.\n */\nexport interface ThumbnailProps extends GenericProps {\n /** Alignment of the thumbnail in it's parent (requires flex parent). */\n align?: HorizontalAlignment;\n /** Image alternative text. */\n alt: string;\n /** Image aspect ratio. */\n aspectRatio?: AspectRatio;\n /** Badge. */\n badge?: ReactElement;\n /** Image cross origin resource policy. */\n crossOrigin?: ImgHTMLProps['crossOrigin'];\n /** Fallback icon (SVG path) or react node when image fails to load. */\n fallback?: string | ReactNode;\n /** Whether the thumbnail should fill it's parent size (requires flex parent) or not. */\n fillHeight?: boolean;\n /** Apply relative vertical and horizontal shift (from -1 to 1) on the image position inside the thumbnail. */\n focusPoint?: FocusPoint;\n /** Image URL. */\n image: string;\n /** Props to inject into the native <img> element. */\n imgProps?: ImgHTMLProps;\n /** Reference to the native <img> element. */\n imgRef?: Ref<HTMLImageElement>;\n /** Set to true to force the display of the loading skeleton. */\n isLoading?: boolean;\n /** Size variant of the component. */\n size?: ThumbnailSize;\n /** Image loading mode. */\n loading?: ImgHTMLProps['loading'];\n /** On click callback. */\n onClick?: MouseEventHandler<HTMLDivElement>;\n /** On key press callback. */\n onKeyPress?: KeyboardEventHandler<HTMLDivElement>;\n /** Theme adapting the component to light or dark background. */\n theme?: Theme;\n /** Variant of the component. */\n variant?: ThumbnailVariant;\n /** Props to pass to the link wrapping the thumbnail. */\n linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;\n /** Custom react component for the link (can be used to inject react router Link). */\n linkAs?: 'a' | any;\n}\n\n/**\n * Component display name.\n */\nconst COMPONENT_NAME = 'Thumbnail';\n\n/**\n * Component default class name and class prefix.\n */\nconst CLASSNAME = getRootClassName(COMPONENT_NAME);\n\n/**\n * Component default props.\n */\nconst DEFAULT_PROPS: Partial<ThumbnailProps> = {\n fallback: mdiImageBroken,\n loading: 'lazy',\n theme: Theme.light,\n};\n\nfunction getObjectPosition(aspectRatio: AspectRatio, focusPoint?: FocusPoint) {\n if (aspectRatio === AspectRatio.original || (!focusPoint?.y && !focusPoint?.x)) return undefined;\n const x = Math.round(Math.abs(((focusPoint?.x || 0) + 1) / 2) * 100);\n const y = Math.round(Math.abs(((focusPoint?.y || 0) - 1) / 2) * 100);\n return `${x}% ${y}%`;\n}\n\n/**\n * Thumbnail component.\n *\n * @param props Component props.\n * @param ref Component ref.\n * @return React element.\n */\nexport const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {\n const {\n align,\n alt,\n aspectRatio = AspectRatio.original,\n badge,\n className,\n crossOrigin,\n fallback,\n fillHeight,\n focusPoint,\n image,\n imgProps,\n imgRef: propImgRef,\n isLoading: isLoadingProp,\n loading,\n size,\n theme,\n variant,\n linkProps,\n linkAs,\n showSkeletonLoading = true,\n ...forwardedProps\n } = props;\n const imgRef = useRef<HTMLImageElement>(null);\n\n // Image loading state.\n const loadingState = useImageLoad(image, imgRef);\n const isLoading = isLoadingProp || loadingState === 'isLoading';\n const hasError = loadingState === 'hasError';\n\n const isLink = Boolean(linkProps?.href || linkAs);\n const isButton = !!forwardedProps.onClick;\n const isClickable = isButton || isLink;\n\n let Wrapper: any = 'div';\n const wrapperProps = { ...forwardedProps };\n if (isLink) {\n Wrapper = linkAs || 'a';\n Object.assign(wrapperProps, linkProps);\n } else if (isButton) {\n Wrapper = 'button';\n }\n\n return (\n <Wrapper\n {...wrapperProps}\n ref={ref}\n className={classNames(\n linkProps?.className,\n className,\n handleBasicClasses({\n align,\n aspectRatio,\n prefix: CLASSNAME,\n size,\n theme,\n variant,\n isClickable,\n hasError,\n isLoading: showSkeletonLoading && isLoading,\n hasBadge: !!badge,\n }),\n fillHeight && `${CLASSNAME}--fill-height`,\n )}\n >\n <div className={`${CLASSNAME}__background`}>\n <img\n {...imgProps}\n style={{\n ...imgProps?.style,\n // Hide on error.\n visibility: hasError ? 'hidden' : undefined,\n // Focus point.\n objectPosition: getObjectPosition(aspectRatio, focusPoint),\n }}\n ref={mergeRefs(imgRef, propImgRef)}\n className={classNames(`${CLASSNAME}__image`, isLoading && `${CLASSNAME}__image--is-loading`)}\n crossOrigin={crossOrigin}\n src={image}\n alt={alt}\n loading={loading}\n />\n {!isLoading && hasError && (\n <div className={`${CLASSNAME}__fallback`}>\n {typeof fallback === 'string' ? (\n <Icon icon={fallback} size={Size.xxs} theme={theme} />\n ) : (\n fallback\n )}\n </div>\n )}\n </div>\n {badge &&\n React.cloneElement(badge, { className: classNames(`${CLASSNAME}__badge`, badge.props.className) })}\n </Wrapper>\n );\n});\nThumbnail.displayName = COMPONENT_NAME;\nThumbnail.className = CLASSNAME;\nThumbnail.defaultProps = DEFAULT_PROPS;\n"],"names":["getState","img","event","type","complete","naturalWidth","naturalHeight","useImageLoad","imageURL","imgRef","useState","current","state","setState","useEffect","undefined","update","addEventListener","removeEventListener","src","COMPONENT_NAME","CLASSNAME","getRootClassName","DEFAULT_PROPS","fallback","mdiImageBroken","loading","theme","Theme","light","getObjectPosition","aspectRatio","focusPoint","AspectRatio","original","y","x","Math","round","abs","Thumbnail","forwardRef","props","ref","align","alt","badge","className","crossOrigin","fillHeight","image","imgProps","propImgRef","isLoadingProp","isLoading","size","variant","linkProps","linkAs","showSkeletonLoading","forwardedProps","useRef","loadingState","hasError","isLink","Boolean","href","isButton","onClick","isClickable","Wrapper","wrapperProps","Object","assign","classNames","handleBasicClasses","prefix","hasBadge","style","visibility","objectPosition","mergeRefs","Size","xxs","React","cloneElement","displayName","defaultProps"],"mappings":"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"}
package/package.json CHANGED
@@ -7,8 +7,8 @@
7
7
  },
8
8
  "dependencies": {
9
9
  "@juggle/resize-observer": "^3.2.0",
10
- "@lumx/core": "^2.1.9-alpha-thumbnail2",
11
- "@lumx/icons": "^2.1.9-alpha-thumbnail2",
10
+ "@lumx/core": "^2.1.9-alpha-thumbnail3",
11
+ "@lumx/icons": "^2.1.9-alpha-thumbnail3",
12
12
  "@popperjs/core": "^2.5.4",
13
13
  "body-scroll-lock": "^3.1.5",
14
14
  "classnames": "^2.2.6",
@@ -120,6 +120,6 @@
120
120
  "build:storybook": "cd storybook && ./build"
121
121
  },
122
122
  "sideEffects": false,
123
- "version": "2.1.9-alpha-thumbnail2",
124
- "gitHead": "105e60082267526f6ac979d2c2d725417a1d6190"
123
+ "version": "2.1.9-alpha-thumbnail3",
124
+ "gitHead": "e57c222583d0f3fff98a3934a16a754302c88e3d"
125
125
  }
@@ -118,7 +118,6 @@ export const ImageBlock: Comp<ImageBlockProps, HTMLDivElement> = forwardRef((pro
118
118
  <Thumbnail
119
119
  {...thumbnailProps}
120
120
  className={classNames(`${CLASSNAME}__image`, thumbnailProps?.className)}
121
- fillHeight={fillHeight}
122
121
  align={align}
123
122
  image={image}
124
123
  size={size}
@@ -20,19 +20,6 @@ import { sizeKnob } from '@lumx/react/stories/knobs/sizeKnob';
20
20
  import { action } from '@storybook/addon-actions';
21
21
  import classNames from 'classnames';
22
22
 
23
- const knobAspectRatio = () => {
24
- const ratiosProps = {
25
- Original: {},
26
- 'Original (with natural size)': { imgNaturalSize: { width: 800, height: 600 } },
27
- 'Free (with fill height)': { aspectRatio: AspectRatio.free },
28
- Horizontal: { aspectRatio: AspectRatio.horizontal },
29
- Wide: { aspectRatio: AspectRatio.wide },
30
- Vertical: { aspectRatio: AspectRatio.vertical },
31
- Square: { aspectRatio: AspectRatio.square },
32
- } as const;
33
- return select('Aspect ratio', ratiosProps as any, ratiosProps.Original as any);
34
- };
35
-
36
23
  export default { title: 'LumX components/thumbnail/Thumbnail' };
37
24
 
38
25
  /** Default thumbnail props (editable via knobs) */
@@ -121,7 +108,13 @@ export const ClickableCustomLink = () => (
121
108
  );
122
109
 
123
110
  export const FillHeight = () => {
124
- const parentStyle = { width: 600, height: 240, border: '1px solid red' };
111
+ const parentStyle = {
112
+ width: 600,
113
+ height: 240,
114
+ border: '1px solid red',
115
+ overflow: 'hidden',
116
+ resize: 'both',
117
+ } as const;
125
118
  return (
126
119
  <>
127
120
  <h2>Default</h2>
@@ -213,6 +206,11 @@ export const Original = () => (
213
206
  export const Vertical = () => (
214
207
  <>
215
208
  <h1>Ratio: vertical</h1>
209
+ <h2>Default</h2>
210
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
211
+ <Thumbnail alt="" aspectRatio="vertical" image={IMAGES.landscape1} />
212
+ <Thumbnail alt="" aspectRatio="vertical" image={IMAGES.portrait1} />
213
+ </FlexBox>
216
214
  <h2>Constraint parent size</h2>
217
215
  <FlexBox orientation="horizontal" vAlign="center" gap="huge">
218
216
  <div className="parent" style={{ width: 220 }}>
@@ -261,6 +259,11 @@ export const Vertical = () => (
261
259
  export const Wide = () => (
262
260
  <>
263
261
  <h1>Ratio: wide</h1>
262
+ <h2>Default</h2>
263
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
264
+ <Thumbnail alt="" aspectRatio="wide" image={IMAGES.landscape1} />
265
+ <Thumbnail alt="" aspectRatio="wide" image={IMAGES.portrait1} />
266
+ </FlexBox>
264
267
  <h2>Constrained parent size</h2>
265
268
  <FlexBox orientation="horizontal" vAlign="center" gap="huge">
266
269
  <div className="parent" style={{ width: 220 }}>
@@ -306,6 +309,59 @@ export const Wide = () => (
306
309
  </>
307
310
  );
308
311
 
312
+ export const Square = () => (
313
+ <>
314
+ <h1>Ratio: square</h1>
315
+ <h2>Default</h2>
316
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
317
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1} />
318
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1} />
319
+ </FlexBox>
320
+ <h2>Constrained parent size</h2>
321
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
322
+ <div className="parent" style={{ width: 220 }}>
323
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1} />
324
+ </div>
325
+ <div className="parent" style={{ width: 220 }}>
326
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1} />
327
+ </div>
328
+ </FlexBox>
329
+ <h2>Constrained parent size & smaller image</h2>
330
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
331
+ <div className="parent" style={{ width: 220 }}>
332
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1s200} />
333
+ </div>
334
+ <div className="parent" style={{ width: 220 }}>
335
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1s200} />
336
+ </div>
337
+ </FlexBox>
338
+ <h2>With size</h2>
339
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
340
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1} size="xxl" />
341
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1} size="xxl" />
342
+ </FlexBox>
343
+ <h2>With size & smaller image</h2>
344
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
345
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1s200} size="xxl" />
346
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1s200} size="xxl" />
347
+ </FlexBox>
348
+ <h2>With size & smaller image & fill height</h2>
349
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
350
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1s200} size="xxl" fillHeight />
351
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1s200} size="xxl" fillHeight />
352
+ </FlexBox>
353
+ <h2>Constrained parent size & smaller image & fill height</h2>
354
+ <FlexBox orientation="horizontal" vAlign="center" gap="huge">
355
+ <div className="parent" style={{ width: 220 }}>
356
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1s200} fillHeight />
357
+ </div>
358
+ <div className="parent" style={{ width: 220 }}>
359
+ <Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1s200} fillHeight />
360
+ </div>
361
+ </FlexBox>
362
+ </>
363
+ );
364
+
309
365
  export const ParentSizeConstraint = () => {
310
366
  const fillHeight = boolean('Fill Height', true);
311
367
  return Object.values(AspectRatio).map((aspectRatio) => (
@@ -88,9 +88,9 @@ const DEFAULT_PROPS: Partial<ThumbnailProps> = {
88
88
 
89
89
  function getObjectPosition(aspectRatio: AspectRatio, focusPoint?: FocusPoint) {
90
90
  if (aspectRatio === AspectRatio.original || (!focusPoint?.y && !focusPoint?.x)) return undefined;
91
- const x = (((focusPoint?.x || 0) + 1) / 2) * 100;
92
- const y = (((focusPoint?.y || 0) - 1) / 2) * 100;
93
- return `${Math.round(x)}% ${Math.round(y)}%`;
91
+ const x = Math.round(Math.abs(((focusPoint?.x || 0) + 1) / 2) * 100);
92
+ const y = Math.round(Math.abs(((focusPoint?.y || 0) - 1) / 2) * 100);
93
+ return `${x}% ${y}%`;
94
94
  }
95
95
 
96
96
  /**