@wonderflow/react-components
Version:
UI components from Wonderflow's Wanda design system
66 lines (65 loc) • 3.87 kB
JavaScript
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() }) })] }));
});