@wonderflow/react-components
Version:
UI components from Wonderflow's Wanda design system
62 lines (61 loc) • 5.29 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import tkns from '@wonderflow/tokens/platforms/web/tokens.json';
import { useDebounce } from 'ahooks';
import clsx from 'clsx';
import { forwardRef, useRef, } from 'react';
import { Elevator, Stack, Text, } from '../..';
import * as styles from './product-card.module.css';
import { ProductCardFooter } from './product-card-footer/product-card-footer';
import { ProductCardHeader } from './product-card-header/product-card-header';
import { ProductCardKpis } from './product-card-kpis/product-card-kpis';
import { ProductCardMedia } from './product-card-media/product-card-media';
const getColorFromString = (input) => {
const colorPalette = tkns.color;
// Generate a hash from the input string
let hash = 0;
for (let i = 0; i < input.length; i += 1) {
// eslint-disable-next-line no-bitwise
hash = input.charCodeAt(i) + ((hash << 5) - hash);
}
// Get all color keys
const colorKeys = Object.keys(colorPalette);
// Pick a color family based on the hash
const colorFamily = colorKeys[Math.abs(hash) % colorKeys.length];
// Return the first shade of the selected color family
const shades = colorPalette[colorFamily];
const firstShade = Object.values(shades)[5];
return `hsl(${firstShade})`;
};
export const ProductCard = forwardRef(({ direction = 'vertical', bordered = false, highlightOnHover = false, title, titleRows = 3, subtitle, menuActions, rating, feedbackCount, votesCount, votesRating, sentiment, nps, groups, tgw, priceMin, priceMax, currency, currencyDecimals, users, usersCap, skus, skusCap, kpiItems, kpisRowGap, ratio, source, footer, overlayActions, onClick, isLoading = false, hasColoredCover = false, className, style, children, ...otherProps }, forwardedRef) => {
const hasOverlay = !!(overlayActions && !menuActions && !onClick && !isLoading);
const hasMenu = !!(menuActions && !overlayActions && !onClick);
const hasHighlight = !!(onClick ?? highlightOnHover);
const isClickable = !!(!isLoading && onClick);
const containerRef = useRef(null);
const mediaSizeStyle = (direction) => {
if (containerRef?.current) {
// @ts-expect-error: getBoundingClientRect()
const { width, height } = containerRef.current.getBoundingClientRect();
if (direction === 'vertical') {
return ({
flexGrow: 0,
height: 'auto',
width: '100%',
});
}
return ({
flexGrow: 0,
width: `${Math.min(width, height)}px`,
height: 'auto',
});
}
return ({});
};
const deboucedStyle = useDebounce(mediaSizeStyle(direction), { wait: 500 });
return (_jsx(Elevator, { resting: 1, hover: hasHighlight ? 2 : undefined, children: _jsx(Stack, { ref: forwardedRef, className: clsx(styles.Card, className), style: { ...style }, "data-card-bordered": bordered, "data-card-clickable": isClickable, onClick: isLoading ? undefined : onClick, ...otherProps, children: _jsxs(Stack, { "data-inner-element": "ProductCard-Container", direction: "row", className: styles.Row, fill: false, ref: containerRef, children: [hasOverlay && (_jsx(Stack, { direction: "row", hPadding: 24, vAlign: "center", hAlign: "center", className: styles.OverlayActions, "data-inner-element": "ProductCard-OverlayActions", children: _jsx(Stack, { children: overlayActions }) })), _jsxs(Stack, { "data-inner-element": "ProductCard-Group", direction: (direction === 'vertical') ? 'column' : 'row', className: styles.Content, children: [hasColoredCover && !source?.length && (_jsx(Stack, { className: styles.ColoredCard, style: { backgroundColor: `${getColorFromString(title ?? '')}` }, hAlign: "center", vAlign: "center", fill: false, children: _jsx(Text, { variant: "heading-1", textAlign: "center", style: { color: '#fff' }, children: title?.slice(0, 2) }) })), _jsx(ProductCard.Media, { source: source, isLoading: isLoading, ratio: ratio, "data-inner-element": "ProductCard-Media", style: deboucedStyle }), _jsxs(Stack, { direction: "column", children: [_jsx(ProductCard.Header, { "data-inner-element": "ProductCard-Header", title: title, titleRows: titleRows, subtitle: subtitle, isLoading: isLoading, menuActions: hasMenu && menuActions }), _jsx(ProductCardKpis, { "data-inner-element": "ProductCard-Kpis", rating: rating, feedbackCount: feedbackCount, votesCount: votesCount, votesRating: votesRating, sentiment: sentiment, nps: nps, groups: groups, tgw: tgw, priceMin: priceMin, priceMax: priceMax, currency: currency, currencyDecimals: currencyDecimals, users: users, usersCap: usersCap, skus: skus, skusCap: skusCap, isLoading: isLoading, kpiItems: kpiItems, kpisRowGap: kpisRowGap }), children && !isLoading && (_jsx(Stack, { hPadding: 24, "data-inner-element": "ProductCard-Children", children: children })), _jsx(ProductCard.Footer, { isLoading: isLoading, "data-inner-element": "ProductCard-Footer", children: footer })] })] })] }) }) }));
});
ProductCard.displayName = 'ProductCard';
ProductCard.Media = ProductCardMedia;
ProductCard.Header = ProductCardHeader;
ProductCard.Kpis = ProductCardKpis;
ProductCard.Footer = ProductCardFooter;