UNPKG

@wonderflow/react-components

Version:

UI components from Wonderflow's Wanda design system

62 lines (61 loc) 5.29 kB
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;