UNPKG

@geneui/components

Version:

The Gene UI components library designed for BI tools

175 lines (170 loc) 9.72 kB
import { _ as __rest } from '../tslib.es6-f211516f.js'; import * as React from 'react'; import React__default, { useState, useLayoutEffect, isValidElement, cloneElement } from 'react'; import { c as classnames } from '../index-031ff73c.js'; import { s as styleInject } from '../style-inject.es-746bb8ed.js'; function SvgSquareMajor(props) { return React.createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', width: 24, height: 24, viewBox: '0 0 24 24', strokeLinecap: 'round', strokeLinejoin: 'round' }, props, React.createElement('rect', { width: 18, height: 18, x: 3, y: 3, rx: 2 })); } var css_248z = "[data-gene-ui-version=\"2.16.5\"] .rating{box-sizing:border-box;display:flex;-webkit-user-select:none;user-select:none;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}[data-gene-ui-version=\"2.16.5\"] .rating *>svg{color:unset!important}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper{display:flex;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;justify-content:center;position:relative;transition:transform .1s ease-in;width:100%}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper:hover{cursor:pointer;transform:scale(1.1)}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper-readonly{pointer-events:none}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper:focus-visible{outline:.02rem solid var(--hero)}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper-small:not(:first-child){margin-inline-start:.4rem}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper-medium:not(:first-child){margin-inline-start:.8rem}[data-gene-ui-version=\"2.16.5\"] .rating__wrapper-big:not(:first-child){margin-inline-start:1.2rem}[data-gene-ui-version=\"2.16.5\"] .rating__element{height:100%;inset-inline-start:0;overflow:hidden;position:absolute;top:0;width:100%;z-index:7}[data-gene-ui-version=\"2.16.5\"] .rating__icon-small{font-size:3.2rem}[data-gene-ui-version=\"2.16.5\"] .rating__icon-medium{font-size:3.6rem}[data-gene-ui-version=\"2.16.5\"] .rating__icon-big{font-size:4.2rem}"; styleInject(css_248z); const sizes = { small: 32, medium: 36, big: 42 }; const Element = ({ isIcon = false, Element, isCompareElement = false, color, bgColor, size }) => { const currentColor = isCompareElement ? color : bgColor; const className = `rating__icon rating__icon-${size}`; const currentSizes = { width: sizes[size], height: sizes[size] }; const elementProps = Object.assign(Object.assign({ fill: currentColor }, currentSizes), { style: Object.assign({ color: currentColor }, currentSizes) }); return isIcon ? (cloneElement(Element, Object.assign(Object.assign({}, elementProps), { className }))) : (React__default.createElement("div", Object.assign({}, elementProps, { className: className }), Element)); }; const calculatePosition = (position) => (position - Math.floor(position)) * 100; const Rating = (props) => { const { defaultValue = 0, count = 5, onChange, character = SvgSquareMajor, color = 'var(--hero)', bgColor = 'rgba(var(--hero-rgb), 0.3)', halfAllow = false, readonly = false, size = 'small', value } = props, restProps = __rest(props, ["defaultValue", "count", "onChange", "character", "color", "bgColor", "halfAllow", "readonly", "size", "value"]); const isControlled = 'value' in props; const isDefaultValueExist = 'defaultValue' in props; const isRTLMode = document.dir === 'rtl'; const currentValue = value || defaultValue || 0; const [rating, setRating] = useState(currentValue); const [hoveredValue, setHoveredValue] = useState(0); const [regardingPosition, setRegardingPosition] = useState(0); const [remainingRating, setRemainingRating] = useState(0); const [temporaryRating, setTemporaryRating] = useState(0); const [disableMouseMove, setDisableMouseMove] = useState(false); const calculateRegardingPosition = (e) => { const { left, width } = e.currentTarget.getBoundingClientRect(); const getClientPosition = e.clientX - (isRTLMode ? left + width : left); const getRelativeWidth = Math.abs((getClientPosition / width) * 100); return halfAllow && getRelativeWidth <= 50 ? 50 : 100; }; const handleMouseMoveForElement = (e, currentRating) => { if (readonly) return; const regradingPosition = calculateRegardingPosition(e); setRegardingPosition(regradingPosition); if (disableMouseMove) return; setHoveredValue(currentRating); setRating(currentRating); }; useLayoutEffect(() => { if (isControlled || isDefaultValueExist) { setRating(currentValue); setTemporaryRating(currentValue); } const ratingDecimalParts = Math.round((currentValue % Math.floor(currentValue)) * 100); if (ratingDecimalParts > 0) { setRemainingRating(ratingDecimalParts); } if (currentValue < 1) { setRemainingRating(Math.ceil(currentValue * 100)); } }, [defaultValue, isDefaultValueExist, value, isControlled, currentValue]); const mouseLeaveHandler = () => { setHoveredValue(0); setRegardingPosition(0); setDisableMouseMove(false); setRating(temporaryRating); }; const ratingController = (currentRating, state, blockMouseMovie = true) => { setHoveredValue(currentRating); setRating(0); setRemainingRating(calculatePosition(state)); setTemporaryRating((prev) => { if (state !== prev) return state; setHoveredValue(0); setRating(currentValue); setRemainingRating(calculatePosition(currentValue)); setDisableMouseMove(blockMouseMovie); return currentValue; }); }; const getRating = (e, currentRating) => { if (readonly) return; setRegardingPosition(calculateRegardingPosition(e)); const selected = regardingPosition === 50 ? +`${currentRating - 1}.${regardingPosition}` : currentRating; if (isControlled) { setDisableMouseMove(true); setHoveredValue(0); setRating(selected); onChange === null || onChange === void 0 ? void 0 : onChange(selected); return; } ratingController(currentRating, selected); }; const mouseEnterHandler = () => { setTemporaryRating(rating); }; const elementsList = Math.round(count) > 0 ? new Array(Math.round(count)).fill(undefined) : []; const PrimitiveValue = (typeof character === 'string' || typeof character === 'number') && character; const keyDownHandler = (e, currentRating) => { if (readonly) return; if (e.key === 'Enter') { if (isControlled) { setRegardingPosition(100); onChange === null || onChange === void 0 ? void 0 : onChange(currentRating); return; } setRegardingPosition(0); ratingController(currentRating + 1, currentRating, false); } }; const mouseLeaveHandlerForEveryElement = () => { setDisableMouseMove(false); }; return (React__default.createElement("div", Object.assign({}, restProps, { className: "rating", onMouseLeave: mouseLeaveHandler, onMouseEnter: mouseEnterHandler, onBlur: () => setDisableMouseMove(false) }), elementsList.map((_, i) => { const currentRating = i + 1; const Icon = typeof character === 'function' && isValidElement(character(i)) && character(i).type ? character(i) : null; let calculatedWidthFor = 0; if (currentRating < hoveredValue) { calculatedWidthFor = 100; } else if (hoveredValue === currentRating) { calculatedWidthFor = regardingPosition; } else if (currentRating <= rating) { calculatedWidthFor = 100; } else if (currentRating === Math.ceil(rating)) { calculatedWidthFor = remainingRating; } else { calculatedWidthFor = 0; } const clipPath = isRTLMode ? `polygon(${100 - calculatedWidthFor}% 0, 100% 0, 100% 100%, ${100 - calculatedWidthFor}% 100%)` : `polygon( 0 0, ${calculatedWidthFor}% 0, ${calculatedWidthFor}% 100%,0 100%)`; return (React__default.createElement("div", { className: classnames('rating__wrapper', `rating__wrapper-${size}`, { 'rating__wrapper-readonly': readonly }), onMouseMove: (e) => handleMouseMoveForElement(e, currentRating), onMouseLeave: mouseLeaveHandlerForEveryElement, onKeyDown: (e) => keyDownHandler(e, currentRating), onClick: (e) => getRating(e, currentRating), tabIndex: 0, key: i }, Icon && React__default.createElement(Element, { color: color, bgColor: bgColor, size: size, Element: Icon, isIcon: true }), PrimitiveValue && (React__default.createElement(Element, { color: color, bgColor: bgColor, size: size, Element: PrimitiveValue })), React__default.createElement("div", { className: "rating__element", style: { clipPath } }, Icon && (React__default.createElement(Element, { Element: Icon, isIcon: true, isCompareElement: true, color: color, bgColor: bgColor, size: size })), PrimitiveValue && (React__default.createElement(Element, { Element: PrimitiveValue, color: color, bgColor: bgColor, size: size, isCompareElement: true }))))); }))); }; export { Rating as default };