diff --git a/packages/material-ui/src/Radio/Radio.js b/packages/material-ui/src/Radio/Radio.js index 800d33dbde5a55..9fee569953d487 100644 --- a/packages/material-ui/src/Radio/Radio.js +++ b/packages/material-ui/src/Radio/Radio.js @@ -8,7 +8,7 @@ import { fade } from '../styles/colorManipulator'; import capitalize from '../utils/capitalize'; import createChainedFunction from '../utils/createChainedFunction'; import withStyles from '../styles/withStyles'; -import RadioGroupContext from '../RadioGroup/RadioGroupContext'; +import useRadioGroup from '../RadioGroup/useRadioGroup'; export const styles = theme => ({ /* Styles applied to the root element. */ @@ -67,7 +67,7 @@ const Radio = React.forwardRef(function Radio(props, ref) { size = 'medium', ...other } = props; - const radioGroup = React.useContext(RadioGroupContext); + const radioGroup = useRadioGroup(); let checked = checkedProp; const onChange = createChainedFunction(onChangeProp, radioGroup && radioGroup.onChange); diff --git a/packages/material-ui/src/RadioGroup/RadioGroup.test.js b/packages/material-ui/src/RadioGroup/RadioGroup.test.js index e426f44575253a..76a73671ffd3d6 100644 --- a/packages/material-ui/src/RadioGroup/RadioGroup.test.js +++ b/packages/material-ui/src/RadioGroup/RadioGroup.test.js @@ -1,16 +1,19 @@ import React from 'react'; -import { assert } from 'chai'; +import { assert, expect } from 'chai'; import { spy } from 'sinon'; import * as PropTypes from 'prop-types'; import { createMount, findOutermostIntrinsic } from '@material-ui/core/test-utils'; import describeConformance from '../test-utils/describeConformance'; +import { createClientRender } from 'test/utils/createClientRender'; import FormGroup from '../FormGroup'; import Radio from '../Radio'; import RadioGroup from './RadioGroup'; import consoleErrorMock from 'test/utils/consoleErrorMock'; +import useRadioGroup from './useRadioGroup'; describe('', () => { let mount; + const render = createClientRender({ strict: true }); before(() => { // StrictModeViolation: test uses #simulate @@ -257,6 +260,61 @@ describe('', () => { }); }); + describe('useRadioGroup', () => { + const RadioGroupController = React.forwardRef((_, ref) => { + const radioGroup = useRadioGroup(); + React.useImperativeHandle(ref, () => radioGroup, [radioGroup]); + return null; + }); + + const RadioGroupControlled = React.forwardRef(function RadioGroupControlled(props, ref) { + return ( + + + + ); + }); + + describe('from props', () => { + it('should have the name prop from the instance', () => { + const radioGroupRef = React.createRef(); + const { setProps } = render(); + + expect(radioGroupRef.current).to.have.property('name', 'group'); + + setProps({ name: 'anotherGroup' }); + expect(radioGroupRef.current).to.have.property('name', 'anotherGroup'); + }); + + it('should have the value prop from the instance', () => { + const radioGroupRef = React.createRef(); + const { setProps } = render(); + + expect(radioGroupRef.current).to.have.property('value', ''); + + setProps({ value: 'one' }); + expect(radioGroupRef.current).to.have.property('value', 'one'); + }); + }); + + describe('callbacks', () => { + describe('onChange', () => { + it('should set the value state', () => { + const radioGroupRef = React.createRef(); + render(); + + expect(radioGroupRef.current).to.have.property('value', 'zero'); + + radioGroupRef.current.onChange({ target: { value: 'one' } }); + expect(radioGroupRef.current).to.have.property('value', 'one'); + + radioGroupRef.current.onChange({ target: { value: 'two' } }); + expect(radioGroupRef.current).to.have.property('value', 'two'); + }); + }); + }); + }); + describe('warnings', () => { beforeEach(() => { consoleErrorMock.spy(); diff --git a/packages/material-ui/src/RadioGroup/index.d.ts b/packages/material-ui/src/RadioGroup/index.d.ts index e7e280f415004c..b79185835ed329 100644 --- a/packages/material-ui/src/RadioGroup/index.d.ts +++ b/packages/material-ui/src/RadioGroup/index.d.ts @@ -1,2 +1,3 @@ export { default } from './RadioGroup'; export * from './RadioGroup'; +export { default as useRadioGroup, RadioGroupState } from './useRadioGroup'; diff --git a/packages/material-ui/src/RadioGroup/index.js b/packages/material-ui/src/RadioGroup/index.js index 43f73d549d23b4..20284cadcf592c 100644 --- a/packages/material-ui/src/RadioGroup/index.js +++ b/packages/material-ui/src/RadioGroup/index.js @@ -1 +1,2 @@ export { default } from './RadioGroup'; +export { default as useRadioGroup } from './useRadioGroup'; diff --git a/packages/material-ui/src/RadioGroup/useRadioGroup.d.ts b/packages/material-ui/src/RadioGroup/useRadioGroup.d.ts new file mode 100644 index 00000000000000..8277f3aca3b7b6 --- /dev/null +++ b/packages/material-ui/src/RadioGroup/useRadioGroup.d.ts @@ -0,0 +1,9 @@ +import { Context } from 'react'; +import { RadioGroupProps } from './RadioGroup'; + +// shut off automatic exporting +export {}; + +export interface RadioGroupState extends Pick {} + +export default function useRadioGroup(): RadioGroupState; diff --git a/packages/material-ui/src/RadioGroup/useRadioGroup.js b/packages/material-ui/src/RadioGroup/useRadioGroup.js new file mode 100644 index 00000000000000..47b2186f39fe42 --- /dev/null +++ b/packages/material-ui/src/RadioGroup/useRadioGroup.js @@ -0,0 +1,6 @@ +import React from 'react'; +import RadioGroupContext from './RadioGroupContext'; + +export default function useRadioGroup() { + return React.useContext(RadioGroupContext); +}