Repository: react-materialize/react-materialize
Pull request #794 (2019-03-29 17:05:04)

Textarea now correctly handles layout classes
# Description

Hi there, it's been a while since my last PR. :smile: 
This is just a fix for the `Textarea` component which, at the moment, doesn't correctly handles layout classes.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

# How Has This Been Tested?

I've written two new test and updated the snapshots.

# Checklist:

- [x] I have commented my code, particularly in hard-to-understand areas
- [x] My changes generate no new warnings
- [x] I have not generated a new package version. (the maintainers will handle that)



Patch:
diff --git a/src/Textarea.js b/src/Textarea.js
index 2cf7cc0..ce7fd5d 100644
--- a/src/Textarea.js
+++ b/src/Textarea.js
@@ -1,8 +1,9 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import cx from 'classnames';
 import idgen from './idgen';
 import Icon from './Icon';
-import TextInput from './TextInput';
+import constants from './constants';
 
 class Textarea extends Component {
   componentDidUpdate() {
@@ -14,12 +15,36 @@ class Textarea extends Component {
   }
 
   render() {
-    const { iconClassName, icon, label, id, onChange, ...other } = this.props;
+    const {
+      s,
+      m,
+      l,
+      xl,
+      noLayout,
+      iconClassName,
+      icon,
+      label,
+      id,
+      onChange,
+      ...other
+    } = this.props;
 
     const computedId = id || idgen();
 
+    const sizes = { s, m, l, xl };
+
+    let responsiveClasses;
+    if (!noLayout) {
+      responsiveClasses = { col: true };
+      constants.SIZES.forEach(size => {
+        responsiveClasses[size + sizes[size]] = sizes[size];
+      });
+    }
+
+    const wrapperClasses = cx('input-field', responsiveClasses);
+
     return (
-      <div className="input-field">
+      <div className={wrapperClasses}>
         {icon && this.renderIcon(icon, iconClassName)}
         <textarea
           ref={input => {
@@ -37,6 +62,26 @@ class Textarea extends Component {
 }
 
 Textarea.propTypes = {
+  /*
+ * Strip away all layout classes such as col and sX
+ */
+  noLayout: PropTypes.bool,
+  /*
+   * Responsive size for Mobile Devices
+   */
+  s: PropTypes.number,
+  /*
+   * Responsive size for Tablet Devices
+   */
+  m: PropTypes.number,
+  /*
+   * Responsive size for Desktop Devices
+   */
+  l: PropTypes.number,
+  /**
+   *  Responsive size for Large Desktop Devices
+   */
+  xl: PropTypes.number,
   /*
    * render icon next to input
    */
diff --git a/stories/Textarea.stories.js b/stories/Textarea.stories.js
index 3568c5a..8481e33 100644
--- a/stories/Textarea.stories.js
+++ b/stories/Textarea.stories.js
@@ -1,8 +1,11 @@
 import React from 'react';
 import { storiesOf } from '@storybook/react';
+import { text, boolean, number, withKnobs } from '@storybook/addon-knobs';
+import Row from '../src/Row';
 import Textarea from '../src/Textarea';
 
 const stories = storiesOf('Components|Textarea', module);
+stories.addDecorator(withKnobs);
 
 stories.addParameters({
   info: {
@@ -13,12 +16,40 @@ stories.addParameters({
   }
 });
 
-stories.add('Textarea', () => <Textarea />);
+stories.add('Textarea', () => {
+  const defaultValue = 12;
+  const options = {
+    range: true,
+    min: 1,
+    max: 12,
+    step: 1
+  };
 
-stories.add('Disabled', () => <Textarea value="I was here" disabled />);
+  return (
+    <Row>
+      <Textarea
+        s={number('s', defaultValue, options)}
+        m={number('m', defaultValue, options)}
+        l={number('l', defaultValue, options)}
+        xl={number('xl', defaultValue, options)}
+      />
+    </Row>
+  );
+});
+
+stories.add('Disabled', () => (
+  <Textarea
+    value={text('value', 'I was here')}
+    disabled={boolean('disabled', true)}
+  />
+));
 
-stories.add('Placeholder', () => <Textarea placeholder="I was here" />);
+stories.add('Placeholder', () => (
+  <Textarea placeholder={text('placeholder', 'I was here')} />
+));
 
-stories.add('Label', () => <Textarea label="Write something here..." />);
+stories.add('Label', () => (
+  <Textarea label={text('label', 'Write something here...')} />
+));
 
-stories.add('Icon', () => <Textarea icon="mode_edit" />);
+stories.add('Icon', () => <Textarea icon={text('icon', 'mode_edit')} />);


Test patch:
diff --git a/test/Textarea.spec.js b/test/Textarea.spec.js
index a3785eb..7c9b3ab 100644
--- a/test/Textarea.spec.js
+++ b/test/Textarea.spec.js
@@ -10,6 +10,24 @@ describe('<Textarea />', () => {
     expect(wrapper).toMatchSnapshot();
   });
 
+  test('Handles layout classes', () => {
+    wrapper = shallow(<Textarea s={4} m={6} />);
+
+    expect(wrapper.hasClass('input-field')).toBeTruthy();
+    expect(wrapper.hasClass('col')).toBeTruthy();
+    expect(wrapper.hasClass('s4')).toBeTruthy();
+    expect(wrapper.hasClass('m6')).toBeTruthy();
+  });
+
+  test('Handles removing layout classes', () => {
+    wrapper = shallow(<Textarea s={4} m={6} noLayout />);
+
+    expect(wrapper.hasClass('input-field')).toBeTruthy();
+    expect(wrapper.hasClass('col')).toBeFalsy();
+    expect(wrapper.hasClass('s4')).toBeFalsy();
+    expect(wrapper.hasClass('m6')).toBeFalsy();
+  });
+
   test('Disabled', () => {
     wrapper = shallow(<Textarea value="I was here" disabled />);
     expect(wrapper).toMatchSnapshot();
diff --git a/test/__snapshots__/Textarea.spec.js.snap b/test/__snapshots__/Textarea.spec.js.snap
index fff9088..ca97ec1 100644
--- a/test/__snapshots__/Textarea.spec.js.snap
+++ b/test/__snapshots__/Textarea.spec.js.snap
@@ -2,7 +2,7 @@
 
 exports[`<Textarea /> Disabled 1`] = `
 <div
-  className="input-field"
+  className="input-field col"
 >
   <textarea
     className="materialize-textarea"
@@ -18,7 +18,7 @@ exports[`<Textarea /> Disabled 1`] = `
 
 exports[`<Textarea /> Icon 1`] = `
 <div
-  className="input-field"
+  className="input-field col"
 >
   <Icon
     className="material-icons prefix"
@@ -37,7 +37,7 @@ exports[`<Textarea /> Icon 1`] = `
 
 exports[`<Textarea /> Label 1`] = `
 <div
-  className="input-field"
+  className="input-field col"
 >
   <textarea
     className="materialize-textarea"
@@ -53,7 +53,7 @@ exports[`<Textarea /> Label 1`] = `
 
 exports[`<Textarea /> Placeholder 1`] = `
 <div
-  className="input-field"
+  className="input-field col"
 >
   <textarea
     className="materialize-textarea"
@@ -68,7 +68,7 @@ exports[`<Textarea /> Placeholder 1`] = `
 
 exports[`<Textarea /> Textarea 1`] = `
 <div
-  className="input-field"
+  className="input-field col"
 >
   <textarea
     className="materialize-textarea"