From 7e751e103813d8f9a24dd2b575e3cd9d40863943 Mon Sep 17 00:00:00 2001 From: "e.muhamethanov" Date: Fri, 29 Nov 2024 11:05:57 +0300 Subject: [PATCH] feat(ImageBase): add prop objectPosition --- .../components/ImageBase/ImageBase.module.css | 9 ++++ .../components/ImageBase/ImageBase.test.tsx | 9 ++++ .../src/components/ImageBase/ImageBase.tsx | 42 +++++++++++++++---- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/packages/vkui/src/components/ImageBase/ImageBase.module.css b/packages/vkui/src/components/ImageBase/ImageBase.module.css index 85b435c010..3ddf965ac7 100644 --- a/packages/vkui/src/components/ImageBase/ImageBase.module.css +++ b/packages/vkui/src/components/ImageBase/ImageBase.module.css @@ -71,6 +71,15 @@ object-fit: scale-down; } +.withObjectPosition { + --vkui_internal--ImageBase_object_position_default: 50% 50%; + + object-position: var( + --vkui_internal--ImageBase_object_position, + var(--vkui_internal--ImageBase_object_position_default) + ); +} + .loaded .img { visibility: visible; } diff --git a/packages/vkui/src/components/ImageBase/ImageBase.test.tsx b/packages/vkui/src/components/ImageBase/ImageBase.test.tsx index 80b16256a3..f36b0c1c45 100644 --- a/packages/vkui/src/components/ImageBase/ImageBase.test.tsx +++ b/packages/vkui/src/components/ImageBase/ImageBase.test.tsx @@ -220,6 +220,15 @@ describe(ImageBase, () => { render(} size={28} />); expect(logStub).toHaveBeenCalledTimes(1); }); + + it('should apply custom objectPosition style', () => { + render(); + + expect(getImageBaseImgEl()).toHaveClass(styles.withObjectPosition); + expect(getImageBaseImgEl()).toHaveStyle({ + '--vkui_internal--ImageBase_object_position': 'center bottom', + }); + }); }); describe(getOverlayIconSizeByImageBaseSize, () => { diff --git a/packages/vkui/src/components/ImageBase/ImageBase.tsx b/packages/vkui/src/components/ImageBase/ImageBase.tsx index 3e4df6101f..8a4d40c4e2 100644 --- a/packages/vkui/src/components/ImageBase/ImageBase.tsx +++ b/packages/vkui/src/components/ImageBase/ImageBase.tsx @@ -2,10 +2,17 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { mergeStyle } from '../../helpers/mergeStyle'; import { useExternRef } from '../../hooks/useExternRef'; import { minOr } from '../../lib/comparing'; import { getFetchPriorityProp } from '../../lib/utils'; -import type { AnchorHTMLAttributesOnly, HasRef, HasRootRef, LiteralUnion } from '../../types'; +import type { + AnchorHTMLAttributesOnly, + CSSCustomProperties, + HasRef, + HasRootRef, + LiteralUnion, +} from '../../types'; import { Clickable } from '../Clickable/Clickable'; import { ImageBaseBadge, type ImageBaseBadgeProps } from './ImageBaseBadge/ImageBaseBadge'; import { ImageBaseOverlay, type ImageBaseOverlayProps } from './ImageBaseOverlay/ImageBaseOverlay'; @@ -84,6 +91,11 @@ export interface ImageBaseProps * Подробнее можно почитать в [документации](https://developer.mozilla.org/ru/docs/Web/CSS/object-fit) */ objectFit?: React.CSSProperties['objectFit']; + /** + * Пользовательское значения стиля object-position + * Подробнее можно почитать в [документации](https://developer.mozilla.org/ru/docs/Web/CSS/object-position) + */ + objectPosition?: React.CSSProperties['objectPosition']; /** * Флаг для сохранения пропорций картинки. * Для корректной работы необходимо задать размеры хотя бы одной стороны картинки @@ -149,6 +161,7 @@ export const ImageBase: React.FC & { onError, withTransparentBackground, objectFit = 'cover', + objectPosition, keepAspectRatio = false, ...restProps }: ImageBaseProps) => { @@ -205,6 +218,23 @@ export const ImageBase: React.FC & { [imgRef, loaded], ); + const imgStyles: CSSCustomProperties | undefined = React.useMemo( + () => + objectPosition + ? { + '--vkui_internal--ImageBase_object_position': objectPosition, + } + : undefined, + [objectPosition], + ); + + const keepAspectRationStyles = keepAspectRatio + ? { + width: widthImg || width, + height: heightImg || height, + } + : undefined; + return ( & { className={classNames( styles.img, getObjectFitClassName(objectFit), + objectPosition && styles.withObjectPosition, keepAspectRatio && styles.imgKeepRatio, )} crossOrigin={crossOrigin} decoding={decoding} loading={loading} referrerPolicy={referrerPolicy} - style={ - keepAspectRatio - ? { - width: widthImg || width, - height: heightImg || height, - } - : undefined - } + style={mergeStyle(keepAspectRationStyles, imgStyles)} sizes={sizes} src={src} srcSet={srcSet}