Skip to content

Commit 06a66a1

Browse files
Matt's review
1 parent 52e8083 commit 06a66a1

File tree

4 files changed

+66
-13
lines changed

4 files changed

+66
-13
lines changed

docs/pages/api/rating.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
2727
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
2828
| <span class="prop-name">disabled</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the rating will be disabled. |
2929
| <span class="prop-name">emptyIcon</span> | <span class="prop-type">node</span> | | The icon to display when empty. |
30+
| <span class="prop-name">emptyLabelText</span> | <span class="prop-type">node</span> | <span class="prop-default">'Empty'</span> | The label read when the rating input is empty. |
3031
| <span class="prop-name">getLabelText</span> | <span class="prop-type">func</span> | <span class="prop-default">function defaultLabelText(value) { return `${value} Star${value !== 1 ? 's' : ''}`;}</span> | Accepts a function which returns a string value that provides a user-friendly name for the current value of the rating.<br>For localization purposes, you can use the provided [translations](/guides/localization/).<br><br>**Signature:**<br>`function(value: number) => string`<br>*value:* The rating label's value to format. |
3132
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | <span class="prop-default">&lt;Star fontSize="inherit" /></span> | The icon to display. |
3233
| <span class="prop-name">IconContainerComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">function IconContainer(props) { const { value, ...other } = props; return &lt;span {...other} />;}</span> | The component containing the icon. |

packages/material-ui-lab/src/Rating/Rating.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ function getDecimalPrecision(num) {
2222
}
2323

2424
function roundValueToPrecision(value, precision) {
25+
if (value == null) {
26+
return value;
27+
}
28+
2529
const nearest = Math.round(value / precision) * precision;
2630
return Number(nearest.toFixed(getDecimalPrecision(precision)));
2731
}
@@ -134,6 +138,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
134138
className,
135139
disabled = false,
136140
emptyIcon,
141+
emptyLabelText = 'Empty',
137142
getLabelText = defaultLabelText,
138143
icon = defaultIcon,
139144
IconContainerComponent = IconContainer,
@@ -146,7 +151,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
146151
precision = 1,
147152
readOnly = false,
148153
size = 'medium',
149-
value: valueProp2 = null,
154+
value: valueProp = null,
150155
...other
151156
} = props;
152157

@@ -159,14 +164,14 @@ const Rating = React.forwardRef(function Rating(props, ref) {
159164
setDefaultName(`mui-rating-${Math.round(Math.random() * 1e5)}`);
160165
}, []);
161166

162-
const valueProp = roundValueToPrecision(valueProp2, precision);
167+
const valueRounded = roundValueToPrecision(valueProp, precision);
163168
const theme = useTheme();
164169
const [{ hover, focus }, setState] = React.useState({
165170
hover: -1,
166171
focus: -1,
167172
});
168173

169-
let value = valueProp;
174+
let value = valueRounded;
170175
if (hover !== -1) {
171176
value = hover;
172177
}
@@ -188,7 +193,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
188193

189194
const rootNode = rootRef.current;
190195
const { right, left } = rootNode.getBoundingClientRect();
191-
const { width } = rootNode.firstChild.getBoundingClientRect();
196+
const { width } = rootNode.querySelector(`.${classes.label}`).getBoundingClientRect();
192197
let percent;
193198

194199
if (theme.direction === 'rtl') {
@@ -239,7 +244,18 @@ const Rating = React.forwardRef(function Rating(props, ref) {
239244
};
240245

241246
const handleClear = event => {
242-
if (onChange && parseFloat(event.target.value) === valueProp) {
247+
// Ignore keyboard events
248+
// https://github.com/facebook/react/issues/7407
249+
if (event.clientX === 0 && event.clientY === 0) {
250+
return;
251+
}
252+
253+
setState({
254+
hover: -1,
255+
focus: -1,
256+
});
257+
258+
if (onChange && parseFloat(event.target.value) === valueRounded) {
243259
onChange(event, null);
244260
}
245261
};
@@ -343,19 +359,19 @@ const Rating = React.forwardRef(function Rating(props, ref) {
343359
aria-label={readOnly ? getLabelText(value) : null}
344360
{...other}
345361
>
346-
{!readOnly && !disabled && value == null && (
362+
{!readOnly && !disabled && valueRounded == null && (
347363
<React.Fragment>
364+
<label className={classes.pristine} htmlFor={`${name}-empty`}>
365+
<span className={classes.visuallyhidden}>{emptyLabelText}</span>
366+
</label>
348367
<input
349-
value="0"
350-
id={`${name}-0`}
368+
value=""
369+
id={`${name}-empty`}
351370
type="radio"
352371
name={name}
353372
defaultChecked
354373
className={classes.visuallyhidden}
355374
/>
356-
<label htmlFor={`${name}-0`} className={classes.pristine}>
357-
<span className={classes.visuallyhidden}>{getLabelText(0)}</span>
358-
</label>
359375
</React.Fragment>
360376
)}
361377
{Array.from(new Array(max)).map((_, index) => {
@@ -397,7 +413,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
397413
filled: itemDecimalValue <= value,
398414
hover: itemDecimalValue <= hover,
399415
focus: itemDecimalValue <= focus,
400-
checked: itemDecimalValue === valueProp,
416+
checked: itemDecimalValue === valueRounded,
401417
},
402418
);
403419
})}
@@ -414,7 +430,7 @@ const Rating = React.forwardRef(function Rating(props, ref) {
414430
filled: itemValue <= value,
415431
hover: itemValue <= hover,
416432
focus: itemValue <= focus,
417-
checked: itemValue === valueProp,
433+
checked: itemValue === valueRounded,
418434
},
419435
);
420436
})}
@@ -440,6 +456,10 @@ Rating.propTypes = {
440456
* The icon to display when empty.
441457
*/
442458
emptyIcon: PropTypes.node,
459+
/**
460+
* The label read when the rating input is empty.
461+
*/
462+
emptyLabelText: PropTypes.node,
443463
/**
444464
* Accepts a function which returns a string value that provides a user-friendly name for the current value of the rating.
445465
*

packages/material-ui-lab/src/Rating/Rating.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,14 @@ describe('<Rating />', () => {
8888
expect(handleChange.callCount).to.equal(1);
8989
expect(handleChange.args[0][1]).to.deep.equal(3);
9090
});
91+
92+
it('should select the empty input if value is null', () => {
93+
const { container, getByLabelText } = render(
94+
<Rating {...defaultProps} value={null} />,
95+
);
96+
const input = getByLabelText('Empty');
97+
const checked = container.querySelector('input[name="rating-test"]:checked');
98+
expect(input).to.equal(checked);
99+
expect(input.value).to.equal('');
100+
});
91101
});

packages/material-ui/src/locale/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const azAZ = {
1717

1818
return `${value} ${pluralForm}`;
1919
},
20+
emptyLabelText: 'Empty',
2021
},
2122
MuiAutocomplete: {
2223
clearText: 'Silmək',
@@ -46,6 +47,7 @@ export const csCZ = {
4647
}
4748
return `${value} hvězdiček`;
4849
},
50+
emptyLabelText: 'Empty',
4951
},
5052
MuiAutocomplete: {
5153
clearText: 'Vymazat',
@@ -67,6 +69,7 @@ export const deDE = {
6769
},
6870
MuiRating: {
6971
getLabelText: value => `${value} ${value !== 1 ? 'Sterne' : 'Stern'}`,
72+
emptyLabelText: 'Empty',
7073
},
7174
MuiAutocomplete: {
7275
clearText: 'Leeren',
@@ -91,6 +94,7 @@ export const enUS = {};
9194
},
9295
MuiRating: {
9396
getLabelText: value => `${value} Star${value !== 1 ? 's' : ''}`,
97+
emptyLabelText: 'Empty',
9498
},
9599
MuiAutocomplete: {
96100
clearText: 'Clear',
@@ -112,6 +116,7 @@ export const esES = {
112116
},
113117
MuiRating: {
114118
getLabelText: value => `${value} Estrella${value !== 1 ? 's' : ''}`,
119+
emptyLabelText: 'Empty',
115120
},
116121
MuiAutocomplete: {
117122
clearText: 'Limpiar',
@@ -133,6 +138,7 @@ export const faIR = {
133138
},
134139
MuiRating: {
135140
getLabelText: value => `${value} ستاره`,
141+
emptyLabelText: 'Empty',
136142
},
137143
MuiAutocomplete: {
138144
clearText: 'پاک‌کردن',
@@ -154,6 +160,7 @@ export const frFR = {
154160
},
155161
MuiRating: {
156162
getLabelText: value => `${value} Etoile${value !== 1 ? 's' : ''}`,
163+
emptyLabelText: 'Vide',
157164
},
158165
MuiAutocomplete: {
159166
clearText: 'Vider',
@@ -176,6 +183,7 @@ export const idID = {
176183
},
177184
MuiRating: {
178185
getLabelText: value => `${value} Bintang`,
186+
emptyLabelText: 'Empty',
179187
},
180188
MuiAutocomplete: {
181189
clearText: 'Hapus',
@@ -197,6 +205,7 @@ export const itIT = {
197205
},
198206
MuiRating: {
199207
getLabelText: value => `${value} Stell${value !== 1 ? 'a' : 'e'}`,
208+
emptyLabelText: 'Empty',
200209
},
201210
MuiAutocomplete: {
202211
clearText: 'Svuota',
@@ -218,6 +227,7 @@ export const jaJP = {
218227
},
219228
MuiRating: {
220229
getLabelText: value => `${value} ${value !== 1 ? '出演者' : '星'}`,
230+
emptyLabelText: 'Empty',
221231
},
222232
MuiAutocomplete: {
223233
clearText: 'クリア',
@@ -239,6 +249,7 @@ export const koKR = {
239249
},
240250
MuiRating: {
241251
getLabelText: value => `${value} 점`,
252+
emptyLabelText: 'Empty',
242253
},
243254
MuiAutocomplete: {
244255
clearText: '지우기',
@@ -260,6 +271,7 @@ export const nlNL = {
260271
},
261272
MuiRating: {
262273
getLabelText: value => `${value} Ster${value !== 1 ? 'ren' : ''}`,
274+
emptyLabelText: 'Empty',
263275
},
264276
MuiAutocomplete: {
265277
clearText: 'Wissen',
@@ -292,6 +304,7 @@ export const plPL = {
292304

293305
return `${value} ${pluralForm}`;
294306
},
307+
emptyLabelText: 'Empty',
295308
},
296309
MuiAutocomplete: {
297310
clearText: 'Wyczyść',
@@ -313,6 +326,7 @@ export const ptBR = {
313326
},
314327
MuiRating: {
315328
getLabelText: value => `${value} Estrela${value !== 1 ? 's' : ''}`,
329+
emptyLabelText: 'Empty',
316330
},
317331
MuiAutocomplete: {
318332
clearText: 'Limpar',
@@ -334,6 +348,7 @@ export const ptPT = {
334348
},
335349
MuiRating: {
336350
getLabelText: value => `${value} Estrela${value !== 1 ? 's' : ''}`,
351+
emptyLabelText: 'Empty',
337352
},
338353
MuiAutocomplete: {
339354
clearText: 'Limpar',
@@ -355,6 +370,7 @@ export const roRO = {
355370
},
356371
MuiRating: {
357372
getLabelText: value => `${value} St${value !== 1 ? 'ele' : 'ea'}`,
373+
emptyLabelText: 'Empty',
358374
},
359375
MuiAutocomplete: {
360376
clearText: 'Șterge',
@@ -387,6 +403,7 @@ export const ruRU = {
387403

388404
return `${value} ${pluralForm}`;
389405
},
406+
emptyLabelText: 'Empty',
390407
},
391408
MuiAutocomplete: {
392409
clearText: 'Очистить',
@@ -416,6 +433,7 @@ export const skSK = {
416433
}
417434
return `${value} hviezdičiek`;
418435
},
436+
emptyLabelText: 'Empty',
419437
},
420438
MuiAutocomplete: {
421439
clearText: 'Vymazať',
@@ -437,6 +455,7 @@ export const svSE = {
437455
},
438456
MuiRating: {
439457
getLabelText: value => `${value} ${value !== 1 ? 'Stjärnor' : 'Stjärna'}`,
458+
emptyLabelText: 'Empty',
440459
},
441460
MuiAutocomplete: {
442461
clearText: 'Rensa',
@@ -459,6 +478,7 @@ export const trTR = {
459478
},
460479
MuiRating: {
461480
getLabelText: value => `${value} Yıldız`,
481+
emptyLabelText: 'Empty',
462482
},
463483
MuiAutocomplete: {
464484
clearText: 'Temizle',
@@ -491,6 +511,7 @@ export const ukUA = {
491511

492512
return `${value} ${pluralForm}`;
493513
},
514+
emptyLabelText: 'Empty',
494515
},
495516
MuiAutocomplete: {
496517
clearText: 'Очистити',
@@ -512,6 +533,7 @@ export const zhCN = {
512533
},
513534
MuiRating: {
514535
getLabelText: value => `${value}${value !== 1 ? '星' : ''}`,
536+
emptyLabelText: 'Empty',
515537
},
516538
MuiAutocomplete: {
517539
clearText: '明确',

0 commit comments

Comments
 (0)