@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
122 lines • 5.51 kB
JavaScript
import React, { useCallback } from 'react';
import { StyledCornerElement, StyledCornerImage, StyledGroupedImage, StyledGroupImageElement } from './GroupedImage.styles';
import CareOfClipPath from './clip-paths/CareOfClipPath';
import { useUuid } from '../../hooks/uuid';
import SecondImageClipPath from './clip-paths/SecondImageClipPath';
import { useKeyboardFocusHighlighting } from '../../hooks/useKeyboardFocusHighlighting';
import { useColorScheme } from '../color-scheme-provider/ColorSchemeProvider';
const GROUPED_IMAGE_SERVICE_ORIGIN = 'https://tsimg.cloud';
const IMAGE_SERVICE_PARAM_PATTERN = /^(?:[whsbd]\d+|f(?:webp|avif|json|none)|c(?:c|f)|m(?:cr|sd|ct|pd|cv))$/i;
const getGroupedImageDisplayUrl = (url, size) => {
try {
const urlObject = new URL(url);
if (urlObject.origin !== GROUPED_IMAGE_SERVICE_ORIGIN) {
return url;
}
const pathSegments = urlObject.pathname.split('/');
const fileName = pathSegments.pop();
if (!fileName) {
return url;
}
const extensionIndex = fileName.lastIndexOf('.');
const extension = extensionIndex > -1 ? fileName.slice(extensionIndex) : '';
const fileBaseName = extensionIndex > -1 ? fileName.slice(0, extensionIndex) : fileName;
const parameterSegment = fileBaseName.split('_').pop() ?? '';
const hasImageServiceParameters = Boolean(parameterSegment && parameterSegment !== fileBaseName && parameterSegment.split('-').every(parameter => IMAGE_SERVICE_PARAM_PATTERN.test(parameter)));
const normalizedSize = Math.max(1, Math.round(size));
if (hasImageServiceParameters) {
const fileBaseNameWithoutParams = fileBaseName.slice(0, fileBaseName.lastIndexOf('_'));
const preservedParams = parameterSegment.split('-').filter(p => !/^[whs]\d+$/i.test(p));
const newParams = [...preservedParams, `w${normalizedSize}`, `h${normalizedSize}`];
pathSegments.push(`${fileBaseNameWithoutParams}_${newParams.join('-')}${extension}`);
} else {
pathSegments.push(`${fileBaseName}_w${normalizedSize}-h${normalizedSize}${extension}`);
}
urlObject.pathname = pathSegments.join('/');
return urlObject.toString();
} catch {
return url;
}
};
const GroupedImage = ({
cornerImage,
height = 40,
imageBackground,
images,
onClick,
shouldPreventBackground = false,
shouldShowRoundImage = false,
cornerElement,
onImageError,
shouldEnableKeyboardHighlighting
}) => {
const colorScheme = useColorScheme();
const shouldEnableKeyboardHighlightingEffective = shouldEnableKeyboardHighlighting ?? colorScheme?.shouldEnableKeyboardHighlighting ?? false;
const hasCornerImage = Boolean(cornerImage);
const hasCornerElement = Boolean(cornerElement);
const hasMultipleImages = images.length > 1;
const uuid = useUuid();
const cornerImageDisplayUrl = cornerImage ? getGroupedImageDisplayUrl(cornerImage, height) : undefined;
const isClickable = typeof onClick === 'function';
const isKeyboardFocusable = isClickable && shouldEnableKeyboardHighlightingEffective;
const shouldShowKeyboardHighlighting = useKeyboardFocusHighlighting(isKeyboardFocusable);
const handleKeyDown = useCallback(event => {
if (!isClickable) {
return;
}
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
onClick?.(event);
}
}, [isClickable, onClick]);
const imageElements = images.slice(0, 2).map((src, index) => /*#__PURE__*/React.createElement(StyledGroupImageElement, {
$background: imageBackground,
$isSecondImage: index === 1,
$hasCornerImage: hasCornerImage,
$hasMultipleImages: hasMultipleImages,
$shouldPreventBackground: shouldPreventBackground,
$shouldShowRoundImage: shouldShowRoundImage,
$uuid: uuid
// eslint-disable-next-line react/no-array-index-key
,
key: index
}, /*#__PURE__*/React.createElement("svg", {
width: "100%",
height: "100%",
viewBox: "0 0 40 40",
xmlns: "http://www.w3.org/2000/svg",
preserveAspectRatio: "xMidYMid slice"
}, /*#__PURE__*/React.createElement("foreignObject", {
width: "40",
height: "40"
}, /*#__PURE__*/React.createElement("img", {
alt: `image--${index}`,
src: getGroupedImageDisplayUrl(src, height),
onError: event => typeof onImageError === 'function' && onImageError(event, index)
})))));
return /*#__PURE__*/React.createElement(StyledGroupedImage, {
onClick: isClickable ? onClick : undefined,
onKeyDown: isKeyboardFocusable ? handleKeyDown : undefined,
tabIndex: isKeyboardFocusable ? 0 : -1,
role: isClickable ? 'button' : undefined,
$height: height,
$shouldShowKeyboardHighlighting: shouldShowKeyboardHighlighting
}, hasCornerImage && /*#__PURE__*/React.createElement(CareOfClipPath, {
height: height,
uuid: uuid,
imageFactors: hasMultipleImages ? [0.76, 0.8] : [1]
}), hasMultipleImages && /*#__PURE__*/React.createElement(SecondImageClipPath, {
height: height,
uuid: uuid,
shouldShowRoundImage: shouldShowRoundImage
}), imageElements, hasCornerImage && /*#__PURE__*/React.createElement(StyledCornerImage, {
$background: imageBackground,
$shouldPreventBackground: shouldPreventBackground,
$hasMultipleImages: hasMultipleImages,
src: cornerImageDisplayUrl,
key: "corner-image"
}), hasCornerElement && /*#__PURE__*/React.createElement(StyledCornerElement, null, cornerElement));
};
GroupedImage.displayName = 'GroupedImage';
export default GroupedImage;
//# sourceMappingURL=GroupedImage.js.map