diff --git a/packages/mui-material/src/CircularProgress/CircularProgress.js b/packages/mui-material/src/CircularProgress/CircularProgress.js index 8101edb0f7c2d9..d7337118478e37 100644 --- a/packages/mui-material/src/CircularProgress/CircularProgress.js +++ b/packages/mui-material/src/CircularProgress/CircularProgress.js @@ -13,6 +13,14 @@ import { getCircularProgressUtilityClass } from './circularProgressClasses'; const SIZE = 44; +let warnedMinMaxWithoutVariant = false; +let warnedInvalidMinMaxValue = false; + +export function resetWarningFlags() { + warnedMinMaxWithoutVariant = false; + warnedInvalidMinMaxValue = false; +} + const circularRotateKeyframe = keyframes` 0% { transform: rotate(0deg); @@ -198,10 +206,15 @@ const CircularProgress = React.forwardRef(function CircularProgress(inProps, ref } = props; if (process.env.NODE_ENV !== 'production') { - if (variant === 'indeterminate' && (minProp !== undefined || maxProp !== undefined)) { + if ( + !warnedMinMaxWithoutVariant && + variant === 'indeterminate' && + (minProp !== undefined || maxProp !== undefined) + ) { console.warn( `MUI: You have provided the \`min\` or \`max\` props with an 'indeterminate' variant. These props will have no effect.`, ); + warnedMinMaxWithoutVariant = true; } } @@ -229,10 +242,11 @@ const CircularProgress = React.forwardRef(function CircularProgress(inProps, ref const circumference = 2 * Math.PI * ((SIZE - thickness) / 2); if (process.env.NODE_ENV !== 'production') { - if (value < min || value > max || min >= max) { + if (!warnedInvalidMinMaxValue && (value < min || value > max || min >= max)) { console.error( `MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=${min}, max=${max}, value=${value}.`, ); + warnedInvalidMinMaxValue = true; } } diff --git a/packages/mui-material/src/CircularProgress/CircularProgress.test.js b/packages/mui-material/src/CircularProgress/CircularProgress.test.js index 094aa6a454a0b0..ce420cce68de83 100644 --- a/packages/mui-material/src/CircularProgress/CircularProgress.test.js +++ b/packages/mui-material/src/CircularProgress/CircularProgress.test.js @@ -1,12 +1,9 @@ import { expect } from 'chai'; -import { - createRenderer, - strictModeDoubleLoggingSuppressed, - screen, -} from '@mui/internal-test-utils'; +import { createRenderer, screen } from '@mui/internal-test-utils'; import CircularProgress, { circularProgressClasses as classes, } from '@mui/material/CircularProgress'; +import { resetWarningFlags } from './CircularProgress'; import describeConformance from '../../test/describeConformance'; describe('', () => { @@ -224,45 +221,31 @@ describe('', () => { errorSpy.mockRestore(); }); - it('should error if min, max, and value props are invalid', () => { - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=0, value=5.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=0, value=5.', - ]); - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=10, value=15.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=10, value=15.', - ]); - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=20, value=5.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=20, value=5.', - ]); - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=20, value=25.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=10, max=20, value=25.', - ]); - }); - - it('should warn if min and max props are provided with an indeterminate variant', () => { - expect(() => { - render(); - }).toWarnDev([ - "MUI: You have provided the `min` or `max` props with an 'indeterminate' variant. These props will have no effect.", - !strictModeDoubleLoggingSuppressed && + describe('warnings and errors', () => { + beforeEach(() => { + resetWarningFlags(); + }); + + it.each([ + { value: 5, min: 10, max: 0 }, + { value: 15, min: 10, max: 10 }, + { value: 5, min: 10, max: 20 }, + { value: 25, min: 10, max: 20 }, + ])('should error if min=$min, max=$max, value=$value are invalid', ({ value, min, max }) => { + expect(() => { + render(); + }).toErrorDev([ + `MUI: The min, max, and value props in CircularProgress should be numbers where min < max and min <= value <= max. Received min=${min}, max=${max}, value=${value}.`, + ]); + }); + + it('should warn if min and max props are provided with an indeterminate variant', () => { + expect(() => { + render(); + }).toWarnDev([ "MUI: You have provided the `min` or `max` props with an 'indeterminate' variant. These props will have no effect.", - ]); + ]); + }); }); }); }); diff --git a/packages/mui-material/src/LinearProgress/LinearProgress.js b/packages/mui-material/src/LinearProgress/LinearProgress.js index 666dc0599cea19..d36b523dab185f 100644 --- a/packages/mui-material/src/LinearProgress/LinearProgress.js +++ b/packages/mui-material/src/LinearProgress/LinearProgress.js @@ -12,6 +12,20 @@ import capitalize from '../utils/capitalize'; import { getLinearProgressUtilityClass } from './linearProgressClasses'; const TRANSITION_DURATION = 4; // seconds + +let warnedMinMaxWithoutVariant = false; +let warnedInvalidMinMaxValue = false; +let warnedValueRequired = false; +let warnedInvalidMinMaxValueBuffer = false; +let warnedValueBufferRequired = false; + +export function resetWarningFlags() { + warnedMinMaxWithoutVariant = false; + warnedInvalidMinMaxValue = false; + warnedValueRequired = false; + warnedInvalidMinMaxValueBuffer = false; + warnedValueBufferRequired = false; +} const indeterminate1Keyframe = keyframes` 0% { left: -35%; @@ -372,12 +386,14 @@ const LinearProgress = React.forwardRef(function LinearProgress(inProps, ref) { if (process.env.NODE_ENV !== 'production') { if ( + !warnedMinMaxWithoutVariant && ['indeterminate', 'query'].includes(variant) && (minProp !== undefined || maxProp !== undefined) ) { console.warn( `MUI: You have provided the \`min\` or \`max\` props with an 'indeterminate' or 'query' variant. These props will have no effect.`, ); + warnedMinMaxWithoutVariant = true; } } @@ -393,10 +409,11 @@ const LinearProgress = React.forwardRef(function LinearProgress(inProps, ref) { if (variant === 'determinate' || variant === 'buffer') { if (value !== undefined) { if (process.env.NODE_ENV !== 'production') { - if (value < min || value > max || min >= max) { + if (!warnedInvalidMinMaxValue && (value < min || value > max || min >= max)) { console.error( `MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=${min}, max=${max}, value=${value}.`, ); + warnedInvalidMinMaxValue = true; } } @@ -411,19 +428,25 @@ const LinearProgress = React.forwardRef(function LinearProgress(inProps, ref) { rootProps['aria-valuemin'] = min; rootProps['aria-valuemax'] = max; } else if (process.env.NODE_ENV !== 'production') { - console.error( - 'MUI: You need to provide a value prop ' + - 'when using the determinate or buffer variant of LinearProgress.', - ); + if (!warnedValueRequired) { + console.error( + 'MUI: You need to provide a value prop when using the determinate or buffer variant of LinearProgress.', + ); + warnedValueRequired = true; + } } } if (variant === 'buffer') { if (valueBuffer !== undefined) { if (process.env.NODE_ENV !== 'production') { - if (valueBuffer < min || valueBuffer > max || valueBuffer < value || min >= max) { + if ( + !warnedInvalidMinMaxValueBuffer && + (valueBuffer < min || valueBuffer > max || valueBuffer < value || min >= max) + ) { console.error( `MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=${min}, max=${max}, value=${value}, valueBuffer=${valueBuffer}.`, ); + warnedInvalidMinMaxValueBuffer = true; } } @@ -434,10 +457,12 @@ const LinearProgress = React.forwardRef(function LinearProgress(inProps, ref) { } inlineStyles.bar2.transform = range > 0 ? `translateX(${transform}%)` : 'translateX(-100%)'; // empty-state fallback when range is invalid } else if (process.env.NODE_ENV !== 'production') { - console.error( - 'MUI: You need to provide a valueBuffer prop ' + - 'when using the buffer variant of LinearProgress.', - ); + if (!warnedValueBufferRequired) { + console.error( + 'MUI: You need to provide a valueBuffer prop when using the buffer variant of LinearProgress.', + ); + warnedValueBufferRequired = true; + } } } diff --git a/packages/mui-material/src/LinearProgress/LinearProgress.test.js b/packages/mui-material/src/LinearProgress/LinearProgress.test.js index bc9936b2149e92..4a06df880d1496 100644 --- a/packages/mui-material/src/LinearProgress/LinearProgress.test.js +++ b/packages/mui-material/src/LinearProgress/LinearProgress.test.js @@ -1,11 +1,8 @@ import { expect } from 'chai'; -import { - createRenderer, - screen, - strictModeDoubleLoggingSuppressed, -} from '@mui/internal-test-utils'; +import { createRenderer, screen } from '@mui/internal-test-utils'; import RtlProvider from '@mui/system/RtlProvider'; import LinearProgress, { linearProgressClasses as classes } from '@mui/material/LinearProgress'; +import { resetWarningFlags } from './LinearProgress'; import describeConformance from '../../test/describeConformance'; describe('', () => { @@ -161,28 +158,6 @@ describe('', () => { expect(progressbar).to.have.attribute('aria-valuemax', '100'); }); - describe('prop: value', () => { - it('should warn when not used as expected', () => { - let rerender; - - expect(() => { - ({ rerender } = render()); - }).toErrorDev([ - 'MUI: You need to provide a value prop', - !strictModeDoubleLoggingSuppressed && 'MUI: You need to provide a value prop', - ]); - - expect(() => { - rerender(); - }).toErrorDev([ - 'MUI: You need to provide a value prop', - 'MUI: You need to provide a valueBuffer prop', - !strictModeDoubleLoggingSuppressed && 'MUI: You need to provide a value prop', - !strictModeDoubleLoggingSuppressed && 'MUI: You need to provide a valueBuffer prop', - ]); - }); - }); - describe('prop: min & max', () => { it('should be able to use custom min and max values', () => { render(); @@ -249,83 +224,87 @@ describe('', () => { errorSpy.mockRestore(); }); - it('should warn if the value is out of range', () => { - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=0, max=10, value=-1.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=0, max=10, value=-1.', - ]); - - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=0, max=10, value=11.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=0, max=10, value=11.', - ]); - }); + describe('warnings and errors', () => { + beforeEach(() => { + resetWarningFlags(); + }); + + it.each([ + { variant: 'determinate', value: -1, min: 0, max: 10 }, + { variant: 'determinate', value: 11, min: 0, max: 10 }, + ])( + 'should warn if value=$value is out of range (min=$min, max=$max)', + ({ variant, value, min, max }) => { + expect(() => { + render(); + }).toErrorDev([ + `MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=${min}, max=${max}, value=${value}.`, + ]); + }, + ); - it('should error if the valueBuffer is out of range or less than the value prop', () => { - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=4.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=4.', - ]); - - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=11.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=11.', - ]); - - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=-1.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=0, max=10, value=5, valueBuffer=-1.', - ]); - }); + it.each([ + { value: 5, valueBuffer: 4, min: 0, max: 10 }, + { value: 5, valueBuffer: 11, min: 0, max: 10 }, + { value: 5, valueBuffer: -1, min: 0, max: 10 }, + ])( + 'should error if valueBuffer=$valueBuffer is out of range or less than value=$value', + ({ value, valueBuffer, min, max }) => { + expect(() => { + render( + , + ); + }).toErrorDev([ + `MUI: The min, max, value, and valueBuffer props in LinearProgress should be numbers where min < max and min <= value <= valueBuffer <= max. Received min=${min}, max=${max}, value=${value}, valueBuffer=${valueBuffer}.`, + ]); + }, + ); - it('should error if min is equal or greater than max', () => { - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=10, max=0, value=5.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=10, max=0, value=5.', - ]); - expect(() => { - render(); - }).toErrorDev([ - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=10, max=10, value=5.', - !strictModeDoubleLoggingSuppressed && - 'MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=10, max=10, value=5.', - ]); - }); + it.each([ + { value: 5, min: 10, max: 0 }, + { value: 5, min: 10, max: 10 }, + ])('should error if min=$min is equal or greater than max=$max', ({ value, min, max }) => { + expect(() => { + render(); + }).toErrorDev([ + `MUI: The min, max, and value props in LinearProgress should be numbers where min < max and min <= value <= max. Received min=${min}, max=${max}, value=${value}.`, + ]); + }); + + it.each([ + { variant: 'indeterminate', min: 0, max: undefined }, + { variant: 'query', min: undefined, max: 100 }, + ])( + 'should warn if variant=$variant and min/max props are provided', + ({ variant, min, max }) => { + expect(() => { + render(); + }).toWarnDev([ + "MUI: You have provided the `min` or `max` props with an 'indeterminate' or 'query' variant. These props will have no effect.", + ]); + }, + ); - it('should warn if variant is indeterminate or query and min or max props are provided', () => { - expect(() => { - render(); - }).toWarnDev([ - "MUI: You have provided the `min` or `max` props with an 'indeterminate' or 'query' variant. These props will have no effect.", - !strictModeDoubleLoggingSuppressed && - "MUI: You have provided the `min` or `max` props with an 'indeterminate' or 'query' variant. These props will have no effect.", - ]); - - expect(() => { - render(); - }).toWarnDev([ - "MUI: You have provided the `min` or `max` props with an 'indeterminate' or 'query' variant. These props will have no effect.", - !strictModeDoubleLoggingSuppressed && - "MUI: You have provided the `min` or `max` props with an 'indeterminate' or 'query' variant. These props will have no effect.", - ]); + it('should error if value prop is not provided for the determinate variant', () => { + expect(() => { + render(); + }).toErrorDev(['MUI: You need to provide a value prop']); + }); + + it('should error if value and valueBuffer props are not provided for the buffer variant', () => { + expect(() => { + render(); + }).toErrorDev([ + 'MUI: You need to provide a value prop', + 'MUI: You need to provide a valueBuffer prop', + ]); + }); }); }); }); diff --git a/packages/mui-utils/src/index.ts b/packages/mui-utils/src/index.ts index ffc2b8b1db1ca5..af9371279a8bcc 100644 --- a/packages/mui-utils/src/index.ts +++ b/packages/mui-utils/src/index.ts @@ -57,4 +57,5 @@ export { default as unstable_extractEventHandlers } from './extractEventHandlers export { default as unstable_getReactNodeRef } from './getReactNodeRef'; export { default as unstable_getReactElementRef } from './getReactElementRef'; export { default as isEventHandler } from './isEventHandler'; + export * from './types';