Repository: react-materialize/react-materialize
Pull request #700 (2018-11-23 20:14:33)

Carousel enhancement
# Description

Looking at the source code I noticed that when no options are given the `Carousel` component used just an empty object.

Hence I've added the default options as per the [`materialize` documentation](https://materializecss.com/carousel.html#options)

For accessibility purposes every image has now a default empty `alt` tag (also called the NULL alt text), implying they are just decorative images that serves no specific purpose.

I've also fixed a bug regarding `centerImages` prop introduced by #649, it was used only when using the `images` props.

It didn't work for `children` elements.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

# How Has This Been Tested?

Added a test to check if the `centerImages` props is correctly used.
Added a test to make sure to initializes the component with the default options if none are given. (Refer to the [`materialize`](https://materializecss.com/carousel.html#options) documentation for more information)

# 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/Carousel.js b/src/Carousel.js
index ba65f68..fc25085 100644
--- a/src/Carousel.js
+++ b/src/Carousel.js
@@ -10,7 +10,7 @@ class Carousel extends React.Component {
   }
 
   componentDidMount() {
-    const { options = {} } = this.props;
+    const { options } = this.props;
 
     this.instance = M.Carousel.init(this._carousel, options);
   }
@@ -29,20 +29,20 @@ class Carousel extends React.Component {
             'valign-wrapper': centerImages
           })}
         >
-          <img src={child} />
+          <img src={child} alt="" />
         </a>
       );
     }
+
     return React.cloneElement(child, {
-      className: cx(child.props.className, 'carousel-item')
+      className: cx('carousel-item', child.props.className, {
+        'valign-wrapper': centerImages
+      })
     });
   }
 
-  renderFixedItem() {
-    const { fixedItem } = this.props;
-    return (
-      fixedItem && <div className="carousel-fixed-item center">{fixedItem}</div>
-    );
+  renderFixedItem(fixedItem) {
+    return <div className="carousel-fixed-item center">{fixedItem}</div>;
   }
 
   render() {
@@ -50,9 +50,10 @@ class Carousel extends React.Component {
       children,
       className,
       carouselId,
+      fixedItem,
       images,
       centerImages,
-      options = {}
+      options
     } = this.props;
     const elemsToRender = children || images || [];
 
@@ -69,7 +70,7 @@ class Carousel extends React.Component {
             className
           )}
         >
-          {this.renderFixedItem()}
+          {fixedItem && this.renderFixedItem(fixedItem)}
           {React.Children.map(elemsToRender, child =>
             this.renderItems(child, centerImages)
           )}
@@ -81,7 +82,7 @@ class Carousel extends React.Component {
 
 Carousel.propTypes = {
   /*
-  * Children to render as slider elements
+  * Children to render as carousel elements
   */
   children: PropTypes.any,
   /*
@@ -148,4 +149,18 @@ Carousel.propTypes = {
   })
 };
 
+Carousel.defaultProps = {
+  options: {
+    duration: 200,
+    dist: -100,
+    shift: 0,
+    padding: 0,
+    numVisible: 5,
+    fullWidth: false,
+    indicators: false,
+    noWrap: false,
+    onCycleTo: null
+  }
+};
+
 export default Carousel;


Test patch:
diff --git a/test/Carousel.spec.js b/test/Carousel.spec.js
index 49d0b0f..ea85d48 100644
--- a/test/Carousel.spec.js
+++ b/test/Carousel.spec.js
@@ -24,6 +24,11 @@ describe('<Carousel />', () => {
     expect(wrapper).toMatchSnapshot();
   });
 
+  test('renders centered images', () => {
+    wrapper = shallow(<Carousel images={images} centerImages />);
+    expect(wrapper).toMatchSnapshot();
+  });
+
   test('handles content slides', () => {
     const child = (
       <div className="red">
@@ -69,6 +74,22 @@ describe('<Carousel />', () => {
       restore();
     });
 
+    test('uses default options if none are given', () => {
+      wrapper = shallow(<Carousel />);
+
+      expect(carouselInitMock).toHaveBeenCalledWith({
+        duration: 200,
+        dist: -100,
+        shift: 0,
+        padding: 0,
+        numVisible: 5,
+        fullWidth: false,
+        indicators: false,
+        noWrap: false,
+        onCycleTo: null
+      });
+    });
+
     test('handles full width sliders', () => {
       wrapper = shallow(
         <Carousel images={images} options={{ fullWidth: true }} />
diff --git a/test/__snapshots__/Carousel.spec.js.snap b/test/__snapshots__/Carousel.spec.js.snap
index 43273b6..c8ddfe5 100644
--- a/test/__snapshots__/Carousel.spec.js.snap
+++ b/test/__snapshots__/Carousel.spec.js.snap
@@ -9,6 +9,7 @@ exports[`<Carousel /> accepts className props 1`] = `
     key=".0"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/1"
     />
   </a>
@@ -17,6 +18,7 @@ exports[`<Carousel /> accepts className props 1`] = `
     key=".1"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/2"
     />
   </a>
@@ -25,6 +27,7 @@ exports[`<Carousel /> accepts className props 1`] = `
     key=".2"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/3"
     />
   </a>
@@ -33,6 +36,7 @@ exports[`<Carousel /> accepts className props 1`] = `
     key=".3"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/4"
     />
   </a>
@@ -49,6 +53,7 @@ exports[`<Carousel /> accepts external \`id\` value 1`] = `
     key=".0"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/1"
     />
   </a>
@@ -57,6 +62,7 @@ exports[`<Carousel /> accepts external \`id\` value 1`] = `
     key=".1"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/2"
     />
   </a>
@@ -65,6 +71,7 @@ exports[`<Carousel /> accepts external \`id\` value 1`] = `
     key=".2"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/3"
     />
   </a>
@@ -73,6 +80,7 @@ exports[`<Carousel /> accepts external \`id\` value 1`] = `
     key=".3"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/4"
     />
   </a>
@@ -84,7 +92,7 @@ exports[`<Carousel /> handles content slides 1`] = `
   className="carousel"
 >
   <div
-    className="red carousel-item"
+    className="carousel-item red"
     key=".0"
   >
     <h2>
@@ -106,6 +114,7 @@ exports[`<Carousel /> initialises handles full width sliders 1`] = `
     key=".0"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/1"
     />
   </a>
@@ -114,6 +123,7 @@ exports[`<Carousel /> initialises handles full width sliders 1`] = `
     key=".1"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/2"
     />
   </a>
@@ -122,6 +132,7 @@ exports[`<Carousel /> initialises handles full width sliders 1`] = `
     key=".2"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/3"
     />
   </a>
@@ -130,6 +141,7 @@ exports[`<Carousel /> initialises handles full width sliders 1`] = `
     key=".3"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/4"
     />
   </a>
@@ -145,6 +157,7 @@ exports[`<Carousel /> renders 1`] = `
     key=".0"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/1"
     />
   </a>
@@ -153,6 +166,7 @@ exports[`<Carousel /> renders 1`] = `
     key=".1"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/2"
     />
   </a>
@@ -161,6 +175,7 @@ exports[`<Carousel /> renders 1`] = `
     key=".2"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/3"
     />
   </a>
@@ -169,6 +184,50 @@ exports[`<Carousel /> renders 1`] = `
     key=".3"
   >
     <img
+      alt=""
+      src="https://lorempixel.com/250/250/nature/4"
+    />
+  </a>
+</div>
+`;
+
+exports[`<Carousel /> renders centered images 1`] = `
+<div
+  className="carousel"
+>
+  <a
+    className="carousel-item valign-wrapper"
+    key=".0"
+  >
+    <img
+      alt=""
+      src="https://lorempixel.com/250/250/nature/1"
+    />
+  </a>
+  <a
+    className="carousel-item valign-wrapper"
+    key=".1"
+  >
+    <img
+      alt=""
+      src="https://lorempixel.com/250/250/nature/2"
+    />
+  </a>
+  <a
+    className="carousel-item valign-wrapper"
+    key=".2"
+  >
+    <img
+      alt=""
+      src="https://lorempixel.com/250/250/nature/3"
+    />
+  </a>
+  <a
+    className="carousel-item valign-wrapper"
+    key=".3"
+  >
+    <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/4"
     />
   </a>
@@ -191,6 +250,7 @@ exports[`<Carousel /> renders fixed items 1`] = `
     key=".0"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/1"
     />
   </a>
@@ -199,6 +259,7 @@ exports[`<Carousel /> renders fixed items 1`] = `
     key=".1"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/2"
     />
   </a>
@@ -207,6 +268,7 @@ exports[`<Carousel /> renders fixed items 1`] = `
     key=".2"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/3"
     />
   </a>
@@ -215,6 +277,7 @@ exports[`<Carousel /> renders fixed items 1`] = `
     key=".3"
   >
     <img
+      alt=""
       src="https://lorempixel.com/250/250/nature/4"
     />
   </a>