@amaui/ui-react
Version:
UI for React
373 lines (372 loc) • 19.6 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importDefault(require("react"));
const utils_1 = require("@amaui/utils");
const style_react_1 = require("@amaui/style-react");
const IconMaterialGradeW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialGradeW100"));
const IconMaterialGradeW100Filled_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialGradeW100Filled"));
const utils_2 = require("../utils");
const useStyle = (0, style_react_1.style)(theme => ({
root: {
display: 'inline-flex',
alignItems: 'flex-start',
cursor: 'pointer',
touchAction: 'none'
},
iconWrapper: {
display: 'inline-flex',
position: 'relative',
transition: theme.methods.transitions.make('transform', { duration: 'xs' }),
'&:hover': {
transform: 'scale(1.14)'
}
},
iconWrapper_readOnly: {
'&:hover': {
transform: 'none'
}
},
icon: {
display: 'inline-flex'
},
active: {
display: 'inline-flex',
position: 'absolute',
inset: '0',
overflow: 'hidden',
height: '100%',
width: '0px'
},
inactive: {
opacity: theme.palette.light ? '0.24' : '0.4'
},
focus_outline: {
outline: `1px solid ${theme.palette.text.default.secondary}`
},
readOnly: {
cursor: 'default'
},
disabled: {
opacity: theme.palette.visual_contrast.default.opacity.disabled,
cursor: 'default'
}
}), { name: 'amaui-Rating' });
const Rating = react_1.default.forwardRef((props_, ref) => {
var _a;
const theme = (0, style_react_1.useAmauiTheme)();
const props = react_1.default.useMemo(() => { var _a, _b, _c, _d, _e, _f, _g, _h; return (Object.assign(Object.assign(Object.assign({}, (_d = (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _a === void 0 ? void 0 : _a.elements) === null || _b === void 0 ? void 0 : _b.all) === null || _c === void 0 ? void 0 : _c.props) === null || _d === void 0 ? void 0 : _d.default), (_h = (_g = (_f = (_e = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _e === void 0 ? void 0 : _e.elements) === null || _f === void 0 ? void 0 : _f.amauiRating) === null || _g === void 0 ? void 0 : _g.props) === null || _h === void 0 ? void 0 : _h.default), props_)); }, [props_]);
const { tonal = true, color = 'primary', colorInactive = 'default', size = 'regular', value: value_, valueDefault, valueActive: valueActive_, valueActiveDefault, onChange, onChangeActive, values = 5, precision = 1, onlyValue, readOnly, disabled, icon, icons, iconInactive = (0, jsx_runtime_1.jsx)(IconMaterialGradeW100_1.default, {}), iconActive = (0, jsx_runtime_1.jsx)(IconMaterialGradeW100Filled_1.default, {}), IconProps, IconActiveProps, IconInactiveProps, Component = 'span', className, children } = props, other = __rest(props, ["tonal", "color", "colorInactive", "size", "value", "valueDefault", "valueActive", "valueActiveDefault", "onChange", "onChangeActive", "values", "precision", "onlyValue", "readOnly", "disabled", "icon", "icons", "iconInactive", "iconActive", "IconProps", "IconActiveProps", "IconInactiveProps", "Component", "className", "children"]);
const { classes } = useStyle();
const [init, setInit] = react_1.default.useState(false);
const [value, setValue] = react_1.default.useState(valueDefault !== undefined ? valueDefault : value_);
const [valueActive, setValueActive] = react_1.default.useState(valueActiveDefault !== undefined ? valueActiveDefault : valueActive_);
const [hover, setHover] = react_1.default.useState(false);
const [focus, setFocus] = react_1.default.useState(false);
const [mouseDown, setMouseDown] = react_1.default.useState(false);
const refs = {
root: react_1.default.useRef(undefined),
props: react_1.default.useRef(undefined),
value: react_1.default.useRef(undefined),
valueActive: react_1.default.useRef(undefined),
values: react_1.default.useRef([]),
mouseDown: react_1.default.useRef(undefined),
hover: react_1.default.useRef(undefined),
direction: react_1.default.useRef(undefined)
};
refs.props.current = props;
refs.value.current = value;
refs.valueActive.current = valueActive;
refs.mouseDown.current = mouseDown;
refs.hover.current = hover;
refs.direction.current = theme.direction;
const min = 0;
const max = values;
const valueDecimals = (String(precision).includes('e-') ? +String(precision).split('e-')[1] : (_a = String(precision).split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) || 0;
const valuePrecision = (valueMouse) => {
let value__ = (0, utils_1.valueFromPercentageWithinRange)(valueMouse * 100, min, max);
if (refs.direction.current === 'rtl')
value__ = (max + min) - value__;
if (value__ <= min)
return min;
if (value__ >= max)
return max;
// previous value
let previous = (0, utils_1.clamp)(+(value__ - (value__ % precision)).toFixed(valueDecimals), min, max);
if (value__ < 0)
previous -= precision;
// next value
const next = (0, utils_1.clamp)(+(previous + precision).toFixed(valueDecimals), min, max);
const valueNew = value__ > next ? previous : next;
return valueNew;
};
react_1.default.useEffect(() => {
var _a;
const onMouseUp = () => {
if (!disabled && !readOnly)
setMouseDown(false);
};
const onMouseMove = (event) => {
if (!refs.props.current.disabled && !refs.props.current.readOnly && (refs.mouseDown.current || refs.hover.current)) {
const valuePrevious = refs.hover.current ? refs.valueActive.current : refs.value.current;
const x = event.clientX;
const rect = refs.root.current.getBoundingClientRect();
const { width: width_ } = rect;
// Value to the precision point value
const value__ = valuePrecision((x - rect.x) / width_);
const valueNew = value__;
if (valueNew !== valuePrevious) {
if (!props.hasOwnProperty('value')) {
// Inner controlled value
if (refs.hover.current)
setValueActive(valueNew);
else
setValue(valueNew);
}
if (refs.hover.current) {
if ((0, utils_1.is)('function', onChangeActive))
onChangeActive(valueNew);
}
else {
if ((0, utils_1.is)('function', onChange))
onChange(valueNew);
}
}
}
};
const onTouchMove = (event) => {
if (!refs.props.current.disabled && !refs.props.current.readOnly && refs.mouseDown.current) {
const valuePrevious = refs.hover.current ? refs.valueActive.current : refs.value.current;
const x = event.touches[0].clientX;
const rect = refs.root.current.getBoundingClientRect();
const { width: width_ } = rect;
// Value to the precision point value
const value__ = valuePrecision((x - rect.x) / width_);
const valueNew = value__;
if (valueNew !== valuePrevious) {
// Inner controlled value
if (!props.hasOwnProperty('value'))
setValue(valueNew);
if ((0, utils_1.is)('function', onChange))
onChange(valueNew);
}
}
};
const rootDocument = (0, utils_1.isEnvironment)('browser') ? (((_a = refs.root.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) || window.document) : undefined;
rootDocument.addEventListener('mouseup', onMouseUp);
rootDocument.addEventListener('mousemove', onMouseMove);
rootDocument.addEventListener('touchend', onMouseUp, { passive: true });
rootDocument.addEventListener('touchmove', onTouchMove, { passive: true });
setInit(true);
return () => {
rootDocument.removeEventListener('mouseup', onMouseUp);
rootDocument.removeEventListener('touchend', onMouseUp);
rootDocument.removeEventListener('mousemove', onMouseMove);
rootDocument.removeEventListener('touchmove', onTouchMove);
};
}, []);
react_1.default.useEffect(() => {
if (init && value_ !== value)
setValue(value_);
}, [value_]);
react_1.default.useEffect(() => {
if (init && valueActive_ !== valueActive)
setValueActive(valueActive_);
}, [valueActive_]);
const onMouseDown = react_1.default.useCallback(() => {
if (!disabled && !readOnly)
setMouseDown(true);
}, [disabled, readOnly]);
const onClick = react_1.default.useCallback((event) => {
if (!disabled && !readOnly) {
// Make precision value
// if value is same as previous value clear
// otherwise update the value y
const x = event.clientX;
const rect = refs.root.current.getBoundingClientRect();
const { width: width_ } = rect;
const valueNew = valuePrecision((x - rect.x) / width_);
if (value === valueNew)
onClear();
else {
if (!props.hasOwnProperty('value'))
setValue(valueNew);
if ((0, utils_1.is)('function', onChange))
onChange(valueNew);
}
}
}, [disabled, readOnly, value, valueActive]);
const move = (forward_ = true) => {
const forward = theme.direction === 'ltr' ? forward_ : !forward_;
let value__ = refs.value.current || 0;
// previous value
const previous = (0, utils_1.clamp)(+(value__ - precision).toFixed(valueDecimals), min, max);
// next value
const next = (0, utils_1.clamp)(+(value__ + precision).toFixed(valueDecimals), min, max);
value__ = forward ? next : previous;
const valueNew = value__;
if (valueNew !== refs.value.current) {
if (!props.hasOwnProperty('value'))
setValue(valueNew);
if ((0, utils_1.is)('function', onChange))
onChange(valueNew);
}
};
const onClear = () => {
if (!props.hasOwnProperty('value'))
setValue('');
if ((0, utils_1.is)('function', onChange))
onChange('');
setHover(false);
};
const onKeyDown = react_1.default.useCallback((event) => {
if (!disabled && !readOnly) {
if (['Enter', 'Escape', 'ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft', 'Home', 'End'].includes(event.key)) {
// Prevent default
event.preventDefault();
switch (event.key) {
case 'End':
if (!props.hasOwnProperty('value'))
setValue(0);
if ((0, utils_1.is)('function', onChange))
return onChange(0);
return;
case 'Home':
if (!props.hasOwnProperty('value'))
setValue(values);
if ((0, utils_1.is)('function', onChange))
return onChange(values);
return;
case 'ArrowUp':
case 'ArrowRight':
return move();
case 'ArrowDown':
case 'ArrowLeft':
return move(false);
case 'Enter':
if (value === valueActive) {
if (!props.hasOwnProperty('value'))
setValue('');
if ((0, utils_1.is)('function', onChange))
onChange('');
}
return;
case 'Escape':
if (!props.hasOwnProperty('value'))
setValue('');
if ((0, utils_1.is)('function', onChange))
onChange('');
return;
default:
break;
}
}
}
}, [disabled, readOnly, value, valueActive, precision]);
const onFocus = react_1.default.useCallback((event) => {
if (!disabled && !readOnly && !mouseDown)
setFocus(true);
}, [disabled, readOnly, mouseDown]);
const onBlur = react_1.default.useCallback(() => {
if (!disabled && !readOnly)
setFocus(false);
}, [disabled, readOnly]);
const onMouseEnter = react_1.default.useCallback(() => {
if (!disabled && !readOnly)
setHover(true);
}, [disabled, readOnly]);
const onMouseLeave = react_1.default.useCallback(() => {
if (!disabled && !readOnly)
setHover(false);
}, [disabled, readOnly]);
const width = (index) => {
const value__ = !hover ? value : valueActive;
if (value__ > index - 1 && value__ <= index) {
if (value__ === index)
return '100%';
return `${(value__ % 1) * 100}%`;
}
if ((0, utils_1.is)('number', value__) && index < +(value__).toFixed(1) && !onlyValue)
return '100%';
};
const getIcon = (index, inactive = true) => {
var _a, _b, _c, _d;
if (inactive)
return ((_a = icons === null || icons === void 0 ? void 0 : icons[index]) === null || _a === void 0 ? void 0 : _a.iconInactive) || ((_b = icons === null || icons === void 0 ? void 0 : icons[index]) === null || _b === void 0 ? void 0 : _b.icon) || icon || iconInactive;
return ((_c = icons === null || icons === void 0 ? void 0 : icons[index]) === null || _c === void 0 ? void 0 : _c.iconActive) || ((_d = icons === null || icons === void 0 ? void 0 : icons[index]) === null || _d === void 0 ? void 0 : _d.icon) || icon || iconActive;
};
const selected = (index) => value > index - 1 && value <= index;
return ((0, jsx_runtime_1.jsx)(Component, Object.assign({ ref: item => {
if (ref) {
if ((0, utils_1.is)('function', ref))
ref(item);
else
ref.current = ref;
}
refs.root.current = item;
}, tabIndex: (!disabled && !readOnly) ? 0 : undefined, onBlur: onBlur, onFocus: onFocus, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onTouchStart: onMouseDown, onKeyDown: onKeyDown, className: (0, style_react_1.classNames)([
(0, utils_2.staticClassName)('Rating', theme) && [
'amaui-Rating-root',
`amaui-Rating-size-${size}`,
hover && `amaui-Button-hover`,
mouseDown && `amaui-Button-mouse-down`,
focus && [
`amaui-Button-focus`,
[undefined, 0].includes(value) && `amaui-Button-focus-noValue`
],
readOnly && `amaui-Rating-read-only`,
disabled && `amaui-Rating-disabled`
],
className,
classes.root,
focus && [
classes.focus,
[undefined, 0].includes(value) && classes.focus_outline
],
readOnly && classes.readOnly,
disabled && classes.disabled
]) }, other, { children: new Array(values).fill(undefined).map((item, index) => {
var _a, _b, _c, _d, _e, _f, _g, _h;
const IconInactive = getIcon(index + 1);
const IconActive = getIcon(index + 1, false);
return ((0, jsx_runtime_1.jsxs)("span", Object.assign({ ref: item_ => refs.values.current.push(item_), onClick: onClick, className: (0, style_react_1.classNames)([
(0, utils_2.staticClassName)('Rating', theme) && [
'amaui-Rating-icon-wrapper',
focus && selected(index + 1) && 'amaui-Rating-focus'
],
classes.iconWrapper,
focus && selected(index + 1) && classes.focus_outline,
(readOnly || disabled) && classes.iconWrapper_readOnly
]) }, { children: [(0, jsx_runtime_1.jsx)("span", Object.assign({ className: (0, style_react_1.classNames)([
(0, utils_2.staticClassName)('Rating', theme) && [
'amaui-Rating-icon',
'amaui-Rating-icon-inactive'
],
classes.icon,
classes.inactive
]) }, { children: react_1.default.cloneElement(IconInactive, Object.assign(Object.assign({ color: colorInactive, size: ((_a = IconInactive.props) === null || _a === void 0 ? void 0 : _a.size) !== undefined ? (_b = IconInactive.props) === null || _b === void 0 ? void 0 : _b.size : size }, IconProps), IconInactiveProps)) })), (0, jsx_runtime_1.jsx)("span", Object.assign({ className: (0, style_react_1.classNames)([
(0, utils_2.staticClassName)('Rating', theme) && [
'amaui-Rating-icon',
'amaui-Rating-icon-active'
],
classes.icon,
classes.active
]), style: { width: width(index + 1) } }, { children: react_1.default.cloneElement(IconActive, Object.assign(Object.assign({ tonal: ((_c = IconActive.props) === null || _c === void 0 ? void 0 : _c.tonal) !== undefined ? (_d = IconActive.props) === null || _d === void 0 ? void 0 : _d.tonal : tonal, color: ((_e = IconActive.props) === null || _e === void 0 ? void 0 : _e.color) !== undefined ? (_f = IconActive.props) === null || _f === void 0 ? void 0 : _f.color : color, size: ((_g = IconActive.props) === null || _g === void 0 ? void 0 : _g.size) !== undefined ? (_h = IconActive.props) === null || _h === void 0 ? void 0 : _h.size : size }, IconProps), IconActiveProps)) }))] }), index));
}) })));
});
Rating.displayName = 'amaui-Rating';
exports.default = Rating;
;