UNPKG

@wonderflow/react-components

Version:

UI components from Wonderflow's Wanda design system

66 lines (65 loc) 3.87 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /* * Copyright 2022-2023 Wonderflow Design Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import clsx from 'clsx'; import { forwardRef, useCallback, useMemo, } from 'react'; import { useUIDSeed } from 'react-uid'; import { Stack, Symbol, Text, } from '../..'; import * as styles from './star-meter.module.css'; export const StarMeter = forwardRef(({ className, value = 0, starCount = 5, label, dimension = 'regular', hideLabel = false, ...otherProps }, forwardedRef) => { const seedID = useUIDSeed(); const properties = useMemo(() => ({ small: { labelSize: 'body-3', iconSize: 12, }, regular: { labelSize: 'body-2', iconSize: 16, }, big: { labelSize: 'body-1', iconSize: 24, }, }), []); const clamp = useMemo(() => (num, min, max) => Math.min(Math.max(num, min), max), []); const roundValue = useCallback((value) => { const integer = parseInt(String(value), 10); const fraction = value - integer; if (fraction >= 0.75) { return Math.ceil(value); } if (fraction < 0.25) { return Math.floor(value); } return integer + 0.5; }, []); const starType = useCallback((maxStars, value) => { const roundedValue = roundValue(value); return new Array(maxStars).fill(0).map((_, index) => { const starIndex = index + 1; let fillType = 'var(--star-dimmed-color)'; if (roundedValue >= starIndex) { fillType = 'var(--star-color)'; } if (roundedValue < starIndex && roundedValue > starIndex - 1) { fillType = 'url(#HalfStar)'; } return (_jsx(Symbol, { source: "star", weight: "solid", className: styles.Icon, dimension: properties[dimension].iconSize, fill: fillType }, starIndex)); }); }, [dimension, properties, roundValue]); return (_jsxs(Stack, { inline: true, direction: "row", vAlign: "center", columnGap: 8, className: clsx(styles.StarMeter, className), role: "meter", fill: false, "aria-valuenow": clamp(value, 0, starCount), "aria-valuemin": 0, "aria-valuemax": starCount, "aria-labelledby": seedID('star-meter'), "data-star-meter-dimension": dimension, ref: forwardedRef, ...otherProps, children: [_jsx("svg", { "aria-hidden": "true", className: styles.Gradient, width: "100", height: "50", version: "1.1", xmlns: "http://www.w3.org/2000/svg", children: _jsx("defs", { children: _jsxs("linearGradient", { id: "HalfStar", children: [_jsx("stop", { offset: "0", style: { stopColor: 'var(--star-color)' } }), _jsx("stop", { offset: "50%", style: { stopColor: 'var(--star-color)' } }), _jsx("stop", { offset: "50.1%", style: { stopColor: 'var(--star-dimmed-color)' } }), _jsx("stop", { offset: "100%", style: { stopColor: 'var(--star-dimmed-color)' } })] }) }) }), _jsx(Stack, { direction: "row", columnGap: dimension === 'small' ? 2 : 4, vAlign: "center", children: starType(starCount, value) }), _jsx(Text, { preventResponsive: true, preventBreakWord: true, id: seedID('star-meter'), variant: properties[dimension].labelSize, children: _jsx("b", { children: (!hideLabel && label) ?? value.toString() }) })] })); });