Repository: couds/react-bulma-components (js)

Issue:
Update to Bulma v0.8.2
This is an issue to track features introduced in Bulma 0.8.0.  

- [x] Support light/dark variants of main colors
- [x] Support panel colors
- [x] New `.is-fullwidth` modifier for `image`

Pull request:
Update to Bulma v0.8.2
Closes #237  

Changes:
- `<Panel />` component now has a `color` prop that accepts the same value as other components that support color like `<Button />`
- New `colorVariant` modifier that accepts two values: `light` and `dark`. Equivalent to Bulma's `is-light` and `is-dark` modifiers.
- Added a changelog.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..795292c
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,15 @@
+# Changelog
+
+## 3.3.0
+
+- Add `CHANGELOG.md`
+
+- Bump Bulma version to `0.8.2`
+
+  - `<Panel />` component now supports `color` prop which is exactly the same as
+    other component that supports color, like `<Button />`
+
+  - New modifier: `colorVariant`. Accepts two values: `'light'` and `'dark'`.
+    It is equivalent to Bulma's `is-light` and `is-dark` modifier.
+  
+  - For changelog of Bulma `0.8.2`, see [here](https://github.com/jgthms/bulma/blob/master/CHANGELOG.md#082)
diff --git a/package-lock.json b/package-lock.json
index 9139a93..d55e2b1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3163,9 +3163,9 @@
       }
     },
     "acorn": {
-      "version": "5.7.3",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
-      "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+      "version": "5.7.4",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
+      "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
       "dev": true
     },
     "acorn-globals": {
@@ -3179,9 +3179,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         }
       }
@@ -4920,9 +4920,9 @@
       "dev": true
     },
     "bulma": {
-      "version": "0.7.5",
-      "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.5.tgz",
-      "integrity": "sha512-cX98TIn0I6sKba/DhW0FBjtaDpxTelU166pf7ICXpCCuplHWyu6C9LYZmL5PEsnePIeJaiorsTEzzNk3Tsm1hw=="
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.8.2.tgz",
+      "integrity": "sha512-vMM/ijYSxX+Sm+nD7Lmc1UgWDy2JcL2nTKqwgEqXuOMU+IGALbXd5MLt/BcjBAPLIx36TtzhzBcSnOP974gcqA=="
     },
     "byline": {
       "version": "5.0.0",
@@ -7540,9 +7540,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         }
       }
@@ -11361,9 +11361,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         },
         "tough-cookie": {
@@ -20074,9 +20074,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         }
       }
@@ -20103,9 +20103,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
-          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
           "dev": true
         },
         "ws": {
diff --git a/package.json b/package.json
index e5d6475..8c7e93a 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
   },
   "homepage": "https://github.com/couds/react-bulma-components#readme",
   "dependencies": {
-    "bulma": "0.7.5",
+    "bulma": "0.8.2",
     "classnames": "2.2.6"
   },
   "peerDependencies": {
diff --git a/src/components/button/button.story.js b/src/components/button/button.story.js
index 8a97ccb..a2e3523 100644
--- a/src/components/button/button.story.js
+++ b/src/components/button/button.story.js
@@ -7,20 +7,7 @@ import { action } from '@storybook/addon-actions';
 import Button from 'react-bulma-components/lib/components/button';
 import Section from 'react-bulma-components/lib/components/section';
 import Box from 'react-bulma-components/lib/components/box';
-
-const colors = {
-  Default: '',
-  primary: 'primary',
-  info: 'info',
-  danger: 'danger',
-  warning: 'warning',
-  success: 'success',
-  white: 'white',
-  black: 'black',
-  light: 'light',
-  dark: 'dark',
-  link: 'link',
-};
+import CONSTANTS from '../../constants';
 
 const positions = {
   default: '',
@@ -36,8 +23,9 @@ storiesOf('Button', module)
         Play with the button props using the knobs addon panel at the bottom
       </Box>
       <Button
+        colorVariant={select('Color variant', CONSTANTS.COLOR_VARIANT)}
         fullwidth={boolean('Full width', false)}
-        color={select('Color', colors)}
+        color={select('Color', { ...CONSTANTS.COLORS, default: '' })}
         loading={boolean('Loading', false)}
         outlined={boolean('Outlined', false)}
         inverted={boolean('Inverted', false)}
diff --git a/src/components/image/image.js b/src/components/image/image.js
index 2bcc93e..d0b515e 100644
--- a/src/components/image/image.js
+++ b/src/components/image/image.js
@@ -30,6 +30,7 @@ export default class Image extends PureComponent {
       fallback,
       rounded,
       src,
+      fullwidth,
       ...props
     } = this.props;
     let s = size;
@@ -44,6 +45,7 @@ export default class Image extends PureComponent {
         renderAs="figure"
         className={classnames('image', className, {
           [`is-${s}`]: s,
+          'is-fullwidth': fullwidth,
         })}
       >
         <img
@@ -68,6 +70,7 @@ Image.propTypes = {
   style: PropTypes.shape({}),
   size: PropTypes.oneOf(CONSTANTS.SIZES),
   fallback: PropTypes.string,
+  fullwidth: PropTypes.bool,
 };
 
 Image.defaultProps = {
@@ -79,4 +82,5 @@ Image.defaultProps = {
   style: undefined,
   size: undefined,
   fallback: 'https://bulma.io/images/placeholders/480x480.png',
+  fullwidth: false,
 };
diff --git a/src/components/image/image.story.js b/src/components/image/image.story.js
index a6307ef..56b4abe 100644
--- a/src/components/image/image.story.js
+++ b/src/components/image/image.story.js
@@ -11,6 +11,7 @@ storiesOf('Image', module)
   .add('Default', () => (
     <div style={{ width: 320 }}>
       <Image
+        fullwidth={boolean('fullwidth', false)}
         rounded={boolean('rounded', false)}
         src="http://bulma.io/images/placeholders/640x480.png"
         size="3by2"
diff --git a/src/components/navbar/navbar.js b/src/components/navbar/navbar.js
index 4a643f6..fbf824b 100644
--- a/src/components/navbar/navbar.js
+++ b/src/components/navbar/navbar.js
@@ -39,8 +39,10 @@ const Navbar = ({
       return () => {};
     }
     const html = window.document.querySelector('html');
-    html.classList.remove('has-navbar-fixed-top');
-    html.classList.remove('has-navbar-fixed-bottom');
+    if (!html.classList.contains(`has-navbar-fixed-${fixed}`)) {
+      html.classList.remove('has-navbar-fixed-top');
+      html.classList.remove('has-navbar-fixed-bottom');
+    }
     if (fixed) {
       html.classList.add(`has-navbar-fixed-${fixed}`);
     }
diff --git a/src/components/navbar/navbar.story.js b/src/components/navbar/navbar.story.js
index 75021a2..58ae095 100644
--- a/src/components/navbar/navbar.story.js
+++ b/src/components/navbar/navbar.story.js
@@ -1,24 +1,11 @@
 /* eslint-disable react/no-multi-comp, react/prop-types */
-import React, { Fragment } from 'react';
+import React from 'react';
 
 import { storiesOf } from '@storybook/react';
 import { select, boolean } from '@storybook/addon-knobs';
 import Navbar from 'react-bulma-components/lib/components/navbar';
 import Box from '../box';
-
-const colors = {
-  Default: '',
-  primary: 'primary',
-  info: 'info',
-  danger: 'danger',
-  warning: 'warning',
-  success: 'success',
-  white: 'white',
-  black: 'black',
-  light: 'light',
-  dark: 'dark',
-  link: 'link',
-};
+import CONSTANTS from '../../constants';
 
 storiesOf('Navbar', module)
   .addDecorator(story => (
@@ -32,7 +19,7 @@ storiesOf('Navbar', module)
   .add('Default', () => {
     return (
       <Navbar
-        color={select('Color', colors)}
+        color={select('Color', { ...CONSTANTS.COLORS, default: '' })}
         fixed={select('Fixed', {
           default: undefined,
           top: 'top',
diff --git a/src/components/panel/panel.js b/src/components/panel/panel.js
index f7290fa..1ad273e 100644
--- a/src/components/panel/panel.js
+++ b/src/components/panel/panel.js
@@ -9,9 +9,15 @@ import Tabs from './components/tabs';
 import modifiers from '../../modifiers';
 import Element from '../element';
 import renderAsShape from '../../modifiers/render-as';
-
-const Panel = ({ className, ...props }) => (
-  <Element {...props} className={classnames('panel', className)} />
+import CONSTANTS from '../../constants';
+
+const Panel = ({ color, className, ...props }) => (
+  <Element
+    {...props}
+    className={classnames('panel', className, {
+      [`is-${color}`]: color,
+    })}
+  />
 );
 
 Panel.Header = Header;
@@ -26,12 +32,14 @@ Panel.propTypes = {
   ...modifiers.propTypes,
   className: PropTypes.string,
   renderAs: renderAsShape,
+  colors: [null, '', ...Object.values(CONSTANTS.COLORS)],
 };
 
 Panel.defaultProps = {
   ...modifiers.defaultProps,
   className: undefined,
   renderAs: 'nav',
+  color: undefined,
 };
 
 export default Panel;
diff --git a/src/components/panel/panel.story.js b/src/components/panel/panel.story.js
index 33f954c..ab790e1 100644
--- a/src/components/panel/panel.story.js
+++ b/src/components/panel/panel.story.js
@@ -9,11 +9,14 @@ import {
 } from 'react-bulma-components/lib/components/form';
 import Icon from 'react-bulma-components/lib/components/icon';
 import Button from 'react-bulma-components/lib/components/button';
+import { select } from '@storybook/addon-knobs';
+
+import CONSTANTS from '../../constants';
 
 storiesOf('Panel', module)
   .addDecorator(story => <div style={{ margin: 10 }}>{story()}</div>)
   .add('Default', () => (
-    <Panel>
+    <Panel color={select('color', { ...CONSTANTS.COLORS, default: '' })}>
       <Panel.Header>repositories</Panel.Header>
       <Panel.Block>
         <Control>
diff --git a/src/constants.js b/src/constants.js
index 1f24265..510a456 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -19,4 +19,8 @@ export default {
     BLACK: 'black',
     LINK: 'link',
   },
+  COLOR_VARIANT: {
+    light: 'light',
+    dark: 'dark',
+  },
 };
diff --git a/src/modifiers/colors.js b/src/modifiers/colors.js
index bfbb6b6..9a6afe5 100644
--- a/src/modifiers/colors.js
+++ b/src/modifiers/colors.js
@@ -7,15 +7,18 @@ export default {
   propTypes: {
     textColor: PropTypes.string,
     backgroundColor: PropTypes.string,
+    colorVariant: PropTypes.oneOf(['light', 'dark']),
   },
   defaultProps: {
     textColor: undefined,
     backgroundColor: undefined,
+    colorVariant: undefined,
   },
   classnames: props =>
     classnames({
       [`has-text-${props.textColor}`]: props.textColor,
       [`has-background-${props.backgroundColor}`]: props.backgroundColor,
+      [`is-${props.colorVariant}`]: props.colorVariant,
     }),
-  clean: ({ textColor, backgroundColor, ...props }) => props,
+  clean: ({ textColor, backgroundColor, colorVariant, ...props }) => props,
 };


Test patch:
diff --git a/src/components/image/__test__/__snapshots__/image.test.js.snap b/src/components/image/__test__/__snapshots__/image.test.js.snap
index a71f290..328cf28 100644
--- a/src/components/image/__test__/__snapshots__/image.test.js.snap
+++ b/src/components/image/__test__/__snapshots__/image.test.js.snap
@@ -53,3 +53,16 @@ exports[`Image component Should have image classname 1`] = `
   />
 </figure>
 `;
+
+exports[`Image component should be fullwidth 1`] = `
+<figure
+  className="image is-fullwidth"
+>
+  <img
+    alt=""
+    className=""
+    onError={[Function]}
+    src="http://mydomain.com/image"
+  />
+</figure>
+`;
diff --git a/src/components/image/__test__/image.test.js b/src/components/image/__test__/image.test.js
index 633b4a3..28d8371 100644
--- a/src/components/image/__test__/image.test.js
+++ b/src/components/image/__test__/image.test.js
@@ -36,6 +36,13 @@ describe('Image component', () => {
     expect(component.toJSON()).toMatchSnapshot();
   });
 
+  it('should be fullwidth', () => {
+    const component = renderer.create(
+      <Image fullwidth src="http://mydomain.com/image" />,
+    );
+    expect(component.toJSON()).toMatchSnapshot();
+  });
+
   it('Should have use default image if error encounter', () => {
     const component = shallow(
       <Image
diff --git a/src/components/panel/__test__/__snapshots__/panel.test.js.snap b/src/components/panel/__test__/__snapshots__/panel.test.js.snap
index 1fc20da..76b62e9 100644
--- a/src/components/panel/__test__/__snapshots__/panel.test.js.snap
+++ b/src/components/panel/__test__/__snapshots__/panel.test.js.snap
@@ -2,6 +2,75 @@
 
 exports[`Panel component Should Exist 1`] = `[Function]`;
 
+exports[`Panel component Should be a primary panel 1`] = `
+<nav
+  className="panel is-primary"
+>
+  <div
+    className="panel-heading"
+  >
+    repositories
+  </div>
+  <div
+    className="panel-block"
+  >
+    <div>
+      Control
+    </div>
+  </div>
+  <div
+    className="panel-tabs panel-tabs"
+  >
+    <a
+      className="is-active"
+    >
+      all
+    </a>
+    <a>
+      public
+    </a>
+    <a>
+      private
+    </a>
+    <a>
+      sources
+    </a>
+    <a>
+      forks
+    </a>
+  </div>
+  <a
+    className="panel-block is-active"
+  >
+    <span
+      className="panel-icon"
+    >
+      <i
+        className="fa fa-bars"
+      />
+    </span>
+    bulma
+  </a>
+  <label
+    className="panel-block panel-block"
+  >
+    <input
+      type="checkbox"
+    />
+    remember me
+  </label>
+  <div
+    className="panel-block"
+  >
+    <button
+      type="button"
+    >
+      reset all filters
+    </button>
+  </div>
+</nav>
+`;
+
 exports[`Panel component Should have box classname 1`] = `
 <nav
   className="panel"
diff --git a/src/components/panel/__test__/panel.test.js b/src/components/panel/__test__/panel.test.js
index 30a87f8..f05a1c8 100644
--- a/src/components/panel/__test__/panel.test.js
+++ b/src/components/panel/__test__/panel.test.js
@@ -6,6 +6,37 @@ describe('Panel component', () => {
   it('Should Exist', () => {
     expect(Panel).toMatchSnapshot();
   });
+  it('Should be a primary panel', () => {
+    const component = renderer.create(
+      <Panel color="primary">
+        <Panel.Header>repositories</Panel.Header>
+        <Panel.Block>
+          <div>Control</div>
+        </Panel.Block>
+        <Panel.Tabs className="panel-tabs">
+          <Panel.Tabs.Tab active>all</Panel.Tabs.Tab>
+          <Panel.Tabs.Tab>public</Panel.Tabs.Tab>
+          <Panel.Tabs.Tab>private</Panel.Tabs.Tab>
+          <Panel.Tabs.Tab>sources</Panel.Tabs.Tab>
+          <Panel.Tabs.Tab>forks</Panel.Tabs.Tab>
+        </Panel.Tabs>
+        <Panel.Block renderAs="a" active>
+          <Panel.Icon>
+            <i className="fa fa-bars" />
+          </Panel.Icon>
+          bulma
+        </Panel.Block>
+        <Panel.Block renderAs="label" className="panel-block">
+          <input type="checkbox" />
+          remember me
+        </Panel.Block>
+        <Panel.Block>
+          <button type="button">reset all filters</button>
+        </Panel.Block>
+      </Panel>,
+    );
+    expect(component.toJSON()).toMatchSnapshot();
+  });
   it('Should have box classname', () => {
     const component = renderer.create(
       <Panel>