Repository: react-materialize/react-materialize
Pull request #656 (2018-09-30 17:12:40)

Implements Checkbox component
Implements `<Checkbox />`


Patch:
diff --git a/src/Checkbox.js b/src/Checkbox.js
new file mode 100644
index 0000000..ed134ff
--- /dev/null
+++ b/src/Checkbox.js
@@ -0,0 +1,77 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import cx from 'classnames';
+import idgen from './idgen';
+
+const Checkbox = ({
+  checked,
+  onChange,
+  filledIn,
+  label,
+  disabled,
+  value,
+  id,
+  indeterminate
+}) => {
+  let computedId;
+  if (indeterminate) {
+    computedId = 'indeterminate-checkbox';
+  } else if (id) {
+    computedId = id;
+  } else {
+    computedId = idgen();
+  }
+
+  return (
+    <label htmlFor={computedId}>
+      <input
+        id={computedId}
+        className={cx({ 'filled-in': filledIn })}
+        disabled={disabled}
+        onChange={onChange}
+        type="checkbox"
+        defaultChecked={checked}
+        value={value}
+      />
+      <span>{label}</span>
+    </label>
+  );
+};
+
+Checkbox.propTypes = {
+  /*
+   * checkbox value
+   */
+  value: PropTypes.string.isRequired,
+  /*
+   * filled-in styled checkbox
+   */
+  filledIn: PropTypes.bool,
+  /*
+   * label next to checkbox
+   */
+  label: PropTypes.string.isRequired,
+  /*
+   * Indeterminate Style
+   */
+  indeterminate: PropTypes.bool,
+  /*
+   * onChange callback
+   */
+  onChange: PropTypes.func,
+  /*
+   * override id
+   * @default idgen()
+   */
+  id: PropTypes.string,
+  /*
+   * disabled input
+   */
+  disabled: PropTypes.bool,
+  /*
+   * initialise checkbox checked
+   */
+  checked: PropTypes.bool
+};
+
+export default Checkbox;
diff --git a/src/index.js b/src/index.js
index 962cdf3..39bc970 100644
--- a/src/index.js
+++ b/src/index.js
@@ -6,6 +6,7 @@ import Carousel from './Carousel';
 import Card from './Card';
 import CardPanel from './CardPanel';
 import CardTitle from './CardTitle';
+import Checkbox from './Checkbox';
 import Chip from './Chip';
 import Col from './Col';
 import Collapsible from './Collapsible';
@@ -46,10 +47,11 @@ export {
   Badge,
   Breadcrumb,
   Button,
-  Carousel,
   Card,
   CardPanel,
   CardTitle,
+  Carousel,
+  Checkbox,
   Chip,
   Col,
   Collapsible,
diff --git a/stories/Checkbox.stories.js b/stories/Checkbox.stories.js
new file mode 100644
index 0000000..f162bb7
--- /dev/null
+++ b/stories/Checkbox.stories.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+import Checkbox from '../src/Checkbox';
+
+const stories = storiesOf('javascript/Checkbox', module);
+
+stories.addParameters({
+  info: {
+    text: `Use checkboxes when looking for yes or no answers. 
+    The for attribute is necessary to bind our custom checkbox 
+    with the input. Add the input's id as the value of the for 
+    attribute of the label.`
+  }
+});
+
+stories.add('Default', () => (
+  <Checkbox value="Red" label="Red" />
+));
+
+stories.add('Checked', () => (
+  <Checkbox value="Red" label="Red" checked />
+));
+
+stories.add('Filled-In Checked', () => (
+  <Checkbox value="Red" label="Red" filledIn checked />
+));
+
+stories.add('Indeterminate', () => (
+  <Checkbox value="Red" label="Red" indeterminate />
+));
+
+stories.add('Disabled', () => (
+  <Checkbox value="Red" label="Red" disabled />
+));
+
+stories.add('Disabled Checked', () => (
+  <Checkbox value="Red" label="Red" disabled checked />
+));


Test patch:
diff --git a/test/Checkbox.spec.js b/test/Checkbox.spec.js
new file mode 100644
index 0000000..90d3a00
--- /dev/null
+++ b/test/Checkbox.spec.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import Checkbox from '../src/Checkbox';
+import idgen from '../src/idgen';
+
+jest.mock('../src/idgen');
+
+describe('<Checkbox />', () => {
+  let wrapper;
+
+  beforeEach(() => {
+    idgen.mockClear();
+  });
+
+  test('renders', () => {
+    wrapper = shallow(<Checkbox value="red" label="red" />);
+    expect(idgen).toHaveBeenCalledTimes(1);
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  test('renders disabled', () => {
+    wrapper = shallow(<Checkbox value="red" label="red" disabled />);
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  test('filled-in', () => {
+    wrapper = shallow(<Checkbox value="red" label="red" filledIn />);
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  test('with id', () => {
+    wrapper = shallow(<Checkbox value="red" label="red" id="test" />);
+    expect(idgen).not.toHaveBeenCalled();
+    expect(wrapper).toMatchSnapshot();
+  });
+
+  test('with indeterminate', () => {
+    wrapper = shallow(<Checkbox value="red" label="red" indeterminate />);
+    expect(idgen).not.toHaveBeenCalled();
+    expect(wrapper).toMatchSnapshot();
+  });
+});
diff --git a/test/__snapshots__/Checkbox.spec.js.snap b/test/__snapshots__/Checkbox.spec.js.snap
new file mode 100644
index 0000000..090dd63
--- /dev/null
+++ b/test/__snapshots__/Checkbox.spec.js.snap
@@ -0,0 +1,82 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Checkbox /> filled-in 1`] = `
+<label
+  htmlFor="mockId"
+>
+  <input
+    className="filled-in"
+    id="mockId"
+    type="checkbox"
+    value="red"
+  />
+  <span>
+    red
+  </span>
+</label>
+`;
+
+exports[`<Checkbox /> renders 1`] = `
+<label
+  htmlFor="mockId"
+>
+  <input
+    className=""
+    id="mockId"
+    type="checkbox"
+    value="red"
+  />
+  <span>
+    red
+  </span>
+</label>
+`;
+
+exports[`<Checkbox /> renders disabled 1`] = `
+<label
+  htmlFor="mockId"
+>
+  <input
+    className=""
+    disabled={true}
+    id="mockId"
+    type="checkbox"
+    value="red"
+  />
+  <span>
+    red
+  </span>
+</label>
+`;
+
+exports[`<Checkbox /> with id 1`] = `
+<label
+  htmlFor="test"
+>
+  <input
+    className=""
+    id="test"
+    type="checkbox"
+    value="red"
+  />
+  <span>
+    red
+  </span>
+</label>
+`;
+
+exports[`<Checkbox /> with indeterminate 1`] = `
+<label
+  htmlFor="indeterminate-checkbox"
+>
+  <input
+    className=""
+    id="indeterminate-checkbox"
+    type="checkbox"
+    value="red"
+  />
+  <span>
+    red
+  </span>
+</label>
+`;
diff --git a/test/setup.js b/test/setup.js
index d834002..0f32deb 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -2,7 +2,7 @@ import Enzyme from 'enzyme';
 import Adapter from 'enzyme-adapter-react-16';
 import idgen from '../src/idgen';
 
-jest.mock('../src/idgen', () => () => 'mockId');
+jest.mock('../src/idgen', () => jest.fn(() => 'mockId'));
 
 global.$ = require('jquery');
 global.M = require('materialize-css');