diff --git a/packages/material-ui-lab/src/Rating/Rating.js b/packages/material-ui-lab/src/Rating/Rating.js
index 26230b9756dbca..7cae8933fb7026 100644
--- a/packages/material-ui-lab/src/Rating/Rating.js
+++ b/packages/material-ui-lab/src/Rating/Rating.js
@@ -15,6 +15,16 @@ function clamp(value, min, max) {
return value;
}
+function getDecimalPrecision(num) {
+ const decimalPart = num.toString().split('.')[1];
+ return decimalPart ? decimalPart.length : 0;
+}
+
+function roundValueToPrecision(value, precision) {
+ const nearest = Math.round(value / precision) * precision;
+ return Number(nearest.toFixed(getDecimalPrecision(precision)));
+}
+
export const styles = theme => ({
/* Styles applied to the root element. */
root: {
@@ -133,10 +143,11 @@ const Rating = React.forwardRef(function Rating(props, ref) {
precision = 1,
readOnly = false,
size = 'medium',
- value: valueProp = null,
+ value: valueProp2 = null,
...other
} = props;
+ const valueProp = roundValueToPrecision(valueProp2, precision);
const theme = useTheme();
const [{ hover, focus }, setState] = React.useState({
hover: -1,
@@ -174,7 +185,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
percent = (event.pageX - left - ownerWindow(rootNode).pageXOffset) / (width * max);
}
- let newHover = Math.ceil((max * percent) / precision) * precision;
+ let newHover = roundValueToPrecision(max * percent, precision);
newHover = clamp(newHover, precision, max);
setState(prev =>
prev.hover === newHover && prev.focus === newHover
@@ -341,7 +352,10 @@ const Rating = React.forwardRef(function Rating(props, ref) {
})}
>
{items.map(($, indexDecimal) => {
- const itemDeciamlValue = itemValue - 1 + (indexDecimal + 1) * precision;
+ const itemDeciamlValue = roundValueToPrecision(
+ itemValue - 1 + (indexDecimal + 1) * precision,
+ precision,
+ );
return item(
{
@@ -380,7 +394,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
filled: itemValue <= value,
hover: itemValue <= hover,
focus: itemValue <= focus,
- checked: itemValue === Math.round(valueProp),
+ checked: itemValue === valueProp,
},
);
})}
diff --git a/packages/material-ui-lab/src/Rating/Rating.test.js b/packages/material-ui-lab/src/Rating/Rating.test.js
index 20cc3fb05fcae2..93941421c8061e 100644
--- a/packages/material-ui-lab/src/Rating/Rating.test.js
+++ b/packages/material-ui-lab/src/Rating/Rating.test.js
@@ -10,6 +10,7 @@ describe('', () => {
const render = createClientRender({ strict: true });
let classes;
const defaultProps = {
+ name: 'rating-test',
value: 2,
};
@@ -39,4 +40,14 @@ describe('', () => {
expect(container.firstChild).to.have.class(classes.root);
});
+
+ it('should round the value to the provided precision', () => {
+ const { container, getByLabelText } = render(
+ ,
+ );
+ const input = getByLabelText('4 Stars');
+ const checked = container.querySelector('input[name="rating-test"]:checked');
+ expect(input).to.equal(checked);
+ expect(input.value).to.equal('4');
+ });
});