From 0b06244d30a3aa1c99cafd1fbcb01a8fa55dcdd8 Mon Sep 17 00:00:00 2001 From: Duong Tran Date: Fri, 8 Jun 2018 07:45:20 +1000 Subject: [PATCH] [core] Add React.createRef support (#11757) * feat: make input accept both ref callback and ref from React.createRef * feat: update [TextArea] to accept React.createRef object as inputRef * feat: update typescript and proptypes declaration for inputRef * test: add inputRef test for input * simpler logic --- .size-limit.js | 2 +- packages/material-ui/src/Checkbox/Checkbox.js | 2 +- .../src/FormControlLabel/FormControlLabel.js | 2 +- packages/material-ui/src/Input/Input.d.ts | 2 +- packages/material-ui/src/Input/Input.js | 16 ++++++++++++--- packages/material-ui/src/Input/Input.test.js | 14 +++++++++++++ packages/material-ui/src/Input/Textarea.d.ts | 2 +- packages/material-ui/src/Input/Textarea.js | 12 ++++++++--- .../material-ui/src/Input/Textarea.test.js | 10 ++++++++-- .../src/NativeSelect/NativeSelectInput.js | 2 +- packages/material-ui/src/Radio/Radio.js | 2 +- .../material-ui/src/Select/SelectInput.js | 20 +++++++++++++------ .../src/Select/SelectInput.test.js | 8 ++++++++ packages/material-ui/src/Switch/Switch.js | 2 +- .../material-ui/src/TextField/TextField.d.ts | 2 +- .../material-ui/src/TextField/TextField.js | 2 +- .../material-ui/src/internal/SwitchBase.js | 2 +- pages/api/checkbox.md | 2 +- pages/api/form-control-label.md | 2 +- pages/api/input.md | 2 +- pages/api/radio.md | 2 +- pages/api/switch-base.md | 2 +- pages/api/switch.md | 2 +- pages/api/text-field.md | 2 +- 24 files changed, 84 insertions(+), 32 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index ac662de364d6d8..abd3066a57eddc 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -27,7 +27,7 @@ module.exports = [ name: 'The size of all the modules of material-ui.', webpack: true, path: 'packages/material-ui/build/index.js', - limit: '94.6 KB', + limit: '94.7 KB', }, { name: 'The main bundle of the docs', diff --git a/packages/material-ui/src/Checkbox/Checkbox.js b/packages/material-ui/src/Checkbox/Checkbox.js index 3a892075f2d991..abb53cc99c0594 100644 --- a/packages/material-ui/src/Checkbox/Checkbox.js +++ b/packages/material-ui/src/Checkbox/Checkbox.js @@ -98,7 +98,7 @@ Checkbox.propTypes = { /** * Use that property to pass a ref callback to the native input component. */ - inputRef: PropTypes.func, + inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /** * Callback fired when the state is changed. * diff --git a/packages/material-ui/src/FormControlLabel/FormControlLabel.js b/packages/material-ui/src/FormControlLabel/FormControlLabel.js index 5d2f8ae0a7143f..da5db998b6e7fd 100644 --- a/packages/material-ui/src/FormControlLabel/FormControlLabel.js +++ b/packages/material-ui/src/FormControlLabel/FormControlLabel.js @@ -116,7 +116,7 @@ FormControlLabel.propTypes = { /** * Use that property to pass a ref callback to the native input component. */ - inputRef: PropTypes.func, + inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /** * The text to be used in an enclosing label element. */ diff --git a/packages/material-ui/src/Input/Input.d.ts b/packages/material-ui/src/Input/Input.d.ts index 2481d86255cc7c..0cb45b5e29dbc6 100644 --- a/packages/material-ui/src/Input/Input.d.ts +++ b/packages/material-ui/src/Input/Input.d.ts @@ -18,7 +18,7 @@ export interface InputProps id?: string; inputComponent?: React.ReactType; inputProps?: { [arbitrary: string]: any }; - inputRef?: React.Ref; + inputRef?: React.Ref | React.RefObject; margin?: 'dense'; multiline?: boolean; name?: string; diff --git a/packages/material-ui/src/Input/Input.js b/packages/material-ui/src/Input/Input.js index 28d15859d25855..074a8b42aa5bfe 100644 --- a/packages/material-ui/src/Input/Input.js +++ b/packages/material-ui/src/Input/Input.js @@ -323,10 +323,20 @@ class Input extends React.Component { handleRefInput = node => { this.input = node; + let ref; + if (this.props.inputRef) { - this.props.inputRef(node); + ref = this.props.inputRef; } else if (this.props.inputProps && this.props.inputProps.ref) { - this.props.inputProps.ref(node); + ref = this.props.inputProps.ref; + } + + if (ref) { + if (typeof ref === 'function') { + ref(node); + } else { + ref.current = node; + } } }; @@ -541,7 +551,7 @@ Input.propTypes = { /** * Use that property to pass a ref callback to the native input component. */ - inputRef: PropTypes.func, + inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /** * If `dense`, will adjust vertical spacing. This is normally obtained via context from * FormControl. diff --git a/packages/material-ui/src/Input/Input.test.js b/packages/material-ui/src/Input/Input.test.js index 38df091d39f4a3..ceacbec735343b 100644 --- a/packages/material-ui/src/Input/Input.test.js +++ b/packages/material-ui/src/Input/Input.test.js @@ -471,4 +471,18 @@ describe('', () => { assert.strictEqual(wrapper.childAt(1).type(), InputAdornment); }); }); + + describe('prop: inputRef', () => { + it('should be able to return the input node via a ref object', () => { + const ref = React.createRef(); + mount(); + assert.strictEqual(ref.current.tagName, 'INPUT'); + }); + + it('should be able to return the textarea node via a ref object', () => { + const ref = React.createRef(); + mount(); + assert.strictEqual(ref.current.tagName, 'TEXTAREA'); + }); + }); }); diff --git a/packages/material-ui/src/Input/Textarea.d.ts b/packages/material-ui/src/Input/Textarea.d.ts index 25411b272077f6..9029b97da16cb3 100644 --- a/packages/material-ui/src/Input/Textarea.d.ts +++ b/packages/material-ui/src/Input/Textarea.d.ts @@ -11,7 +11,7 @@ export interface TextareaProps disabled?: boolean; rows?: string | number; rowsMax?: string | number; - textareaRef?: React.Ref; + textareaRef?: React.Ref | React.RefObject; value?: string; } diff --git a/packages/material-ui/src/Input/Textarea.js b/packages/material-ui/src/Input/Textarea.js index 06f867287dc334..9ec321ed76ff06 100644 --- a/packages/material-ui/src/Input/Textarea.js +++ b/packages/material-ui/src/Input/Textarea.js @@ -115,8 +115,14 @@ class Textarea extends React.Component { handleRefInput = node => { this.input = node; - if (this.props.textareaRef) { - this.props.textareaRef(node); + + const { textareaRef } = this.props; + if (textareaRef) { + if (typeof textareaRef === 'function') { + textareaRef(node); + } else { + textareaRef.current = node; + } } }; @@ -224,7 +230,7 @@ Textarea.propTypes = { /** * Use that property to pass a ref callback to the native textarea element. */ - textareaRef: PropTypes.func, + textareaRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), /** * @ignore */ diff --git a/packages/material-ui/src/Input/Textarea.test.js b/packages/material-ui/src/Input/Textarea.test.js index 5ab8ad26ebdad8..6e6f6a4023b630 100644 --- a/packages/material-ui/src/Input/Textarea.test.js +++ b/packages/material-ui/src/Input/Textarea.test.js @@ -1,5 +1,3 @@ -// @flow - import React from 'react'; import { assert } from 'chai'; import { spy, useFakeTimers } from 'sinon'; @@ -156,4 +154,12 @@ describe('