diff --git a/docs/components/Layout/index.jsx b/docs/components/Layout/index.jsx
index 8b22486e9..e9c456517 100644
--- a/docs/components/Layout/index.jsx
+++ b/docs/components/Layout/index.jsx
@@ -10,7 +10,6 @@ import SearchResultCard from '../SearchResultCard';
import ButtonExample from '../../examples/ButtonExample';
import AlertInputExample from '../../examples/AlertInputExample';
import FilePickerExample from '../../examples/FilePickerExample';
-import SpinnerButtonExample from '../../examples/SpinnerButtonExample';
import TextareaExample from '../../examples/TextareaExample';
import TextEllipsisExample from '../../examples/TextEllipsisExample';
import AlertExample from '../../examples/AlertExample';
@@ -69,7 +68,6 @@ ContentArea.propTypes = SidebarArea.propTypes;
const componentsBySection = {
'form-elements': [
'button',
- 'spinner-button',
'alert-input',
'file-picker',
'textarea',
@@ -170,7 +168,6 @@ class PageLayout extends React.Component {
-
diff --git a/docs/examples/ButtonExample.jsx b/docs/examples/ButtonExample.jsx
index f811f86f7..6d79e0cb4 100644
--- a/docs/examples/ButtonExample.jsx
+++ b/docs/examples/ButtonExample.jsx
@@ -92,6 +92,7 @@ export const exampleProps = {
propType: 'inverse',
type: 'bool',
note: 'Renders an inverse button. Can be used with bsStyle to create primary inverse buttons.',
+ defaultValue: 'false',
},
{
propType: 'reason',
@@ -112,6 +113,12 @@ export const exampleProps = {
),
},
+ {
+ propType: 'isLoading',
+ type: 'bool',
+ defaultValue: 'false',
+ note: 'set this to true to display Spinner and disable the button',
+ },
],
};
diff --git a/docs/examples/SpinnerButtonExample.jsx b/docs/examples/SpinnerButtonExample.jsx
deleted file mode 100644
index e9a27cb55..000000000
--- a/docs/examples/SpinnerButtonExample.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import React from 'react';
-import Example from '../components/Example';
-import { SpinnerButton } from '../../src/dist-entry';
-
-class SpinnerButtonExample extends React.Component {
- constructor() {
- super();
- this.state = {
- isLoading: false,
- };
- this.onClick = () => {
- this.setState({ isLoading: true });
- setTimeout(() => {
- this.setState({ isLoading: false });
- }, 400 + Math.floor(Math.random() * 1200) + 1); // simulate a random wait interval
- };
- }
-
- render() {
- const onClick = this.onClick;
- const { isLoading } = this.state;
- return (
-
- Save Details
-
- );
- }
-}
-
-const exampleProps = {
- componentName: 'SpinnerButton',
- notes: (
-
- Extends the above
Button component with added loading state.
-
- ),
- designNotes: (
-
- Spinner button is used when we have a delayed response fetching
- information/data and require to inform the user on-click that we working to deliver their action.
-
- ),
- exampleCodeSnippet: `
- Save Details
- `,
- propTypes: [
- {
- propType: 'isLoading',
- type: 'bool',
- defaultValue: 'false',
- note: (
-
- When isLoading is true the button is disabled.
-
- ),
- },
- {
- propType: 'onClick',
- type: 'func',
- note: (
-
- Should set isLoading to true, and reset to false upon completion.
-
- ),
- },
- ],
-};
-
-export default () => (
-
-
-
-);
diff --git a/src/components/adslot-ui/SpinnerButton/index.jsx b/src/components/adslot-ui/SpinnerButton/index.jsx
deleted file mode 100644
index 79f6c1219..000000000
--- a/src/components/adslot-ui/SpinnerButton/index.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/* eslint-disable react/prop-types */
-import _ from 'lodash';
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import { Button } from 'third-party';
-import Spinner from 'alexandria/Spinner';
-import { expandDts } from 'lib/utils';
-
-require('./styles.scss');
-
-class SpinnerButton extends React.PureComponent {
- constructor(props) {
- super(props);
- this.props = props;
- }
-
- render() {
- const { isLoading, children, dts } = this.props;
- return (
-
- {isLoading ? (
-
-
-
- ) : null}
- {children}
-
- );
- }
-}
-
-SpinnerButton.propTypes = _.assign(
- {
- isLoading: PropTypes.bool,
- dts: PropTypes.string,
- },
- Button.propTypes
-);
-
-SpinnerButton.defaultProps = {
- isLoading: false,
-};
-
-export default SpinnerButton;
diff --git a/src/components/adslot-ui/SpinnerButton/index.spec.jsx b/src/components/adslot-ui/SpinnerButton/index.spec.jsx
deleted file mode 100644
index 1ae53c250..000000000
--- a/src/components/adslot-ui/SpinnerButton/index.spec.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import { shallow } from 'enzyme';
-import SpinnerButton from 'adslot-ui/SpinnerButton';
-import { Button } from 'third-party';
-import Spinner from 'alexandria/Spinner';
-
-describe('SpinnerButtonComponent', () => {
- it('should render with defaults', () => {
- const element = shallow(
-
- Test
-
- );
- expect(element.find(Spinner)).to.have.length(0);
-
- const buttonElement = element.find(Button);
- expect(buttonElement.prop('disabled')).to.equal(true);
- expect(buttonElement.prop('reason')).to.equal('Reason 1');
- expect(buttonElement.prop('isLoading')).to.equal(undefined);
- expect(
- element
- .children()
- .last()
- .text()
- ).to.equal('Test');
- });
-
- it('should pass props to button', () => {
- const element = shallow(
-
- Test
-
- );
- expect(element.find(Spinner)).to.have.length(1);
-
- const buttonElement = element.find('Button[data-test-selector="test"]');
- expect(buttonElement.prop('bsStyle')).to.equal('primary');
- expect(buttonElement.prop('bsSize')).to.equal('lg');
- expect(buttonElement.prop('className')).to.equal('spinner-button-component my-class');
- expect(buttonElement.prop('isLoading')).to.equal(undefined);
- });
-
- it('should be disabled in loading mode', () => {
- const buttonElement = shallow(Test ).find('Button');
-
- expect(buttonElement.prop('disabled')).to.equal(true);
- });
-
- it('should honour disabled when not loading', () => {
- const buttonElement = shallow(Test ).find('Button');
-
- expect(buttonElement.prop('isLoading')).to.equal(undefined);
- expect(buttonElement.prop('disabled')).to.equal(true);
- });
-
- it('should ignore disabled when loading', () => {
- const buttonElement = shallow(
-
- Test
-
- ).find('Button');
- expect(buttonElement.prop('disabled')).to.equal(true);
- });
-});
diff --git a/src/components/adslot-ui/index.js b/src/components/adslot-ui/index.js
index bbf60f613..8043e0470 100644
--- a/src/components/adslot-ui/index.js
+++ b/src/components/adslot-ui/index.js
@@ -11,7 +11,6 @@ import PagedGrid from 'adslot-ui/PagedGrid';
import Panel from 'adslot-ui/Panel';
import Search from 'adslot-ui/Search';
import SearchBar from 'adslot-ui/SearchBar';
-import SpinnerButton from 'adslot-ui/SpinnerButton';
import SplitPane from 'adslot-ui/SplitPane';
import Textarea from 'adslot-ui/Textarea';
import TextEllipsis from 'adslot-ui/TextEllipsis';
@@ -41,7 +40,6 @@ export {
Panel,
Search,
SearchBar,
- SpinnerButton,
SplitPane,
Textarea,
TextEllipsis,
diff --git a/src/components/third-party/bootstrap/Button/index.jsx b/src/components/third-party/bootstrap/Button/index.jsx
index b1e48fc35..c650b1eb4 100644
--- a/src/components/third-party/bootstrap/Button/index.jsx
+++ b/src/components/third-party/bootstrap/Button/index.jsx
@@ -7,9 +7,23 @@ import classNames from 'classnames';
import BootstrapButton from 'react-bootstrap/lib/Button';
import BootstrapPopover from 'react-bootstrap/lib/Popover';
import BootstrapOverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
+import Spinner from 'alexandria/Spinner';
import { expandDts } from 'lib/utils';
+import './styles.scss';
class Button extends React.PureComponent {
+ renderSpinner() {
+ if (this.props.isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ return null;
+ }
+
renderWithReason() {
const popover = (
@@ -24,15 +38,20 @@ class Button extends React.PureComponent {
}
renderButton() {
- const { inverse, children, dts, className } = this.props;
+ const { inverse, children, dts, className, isLoading, disabled } = this.props;
+ const classes = classNames('button-component', className, {
+ 'btn-inverse': inverse && !/btn-inverse/.test(className),
+ });
return (
- {children}
+ {this.renderSpinner()}
+ {children}
);
}
@@ -48,12 +67,14 @@ Button.propTypes = _.assign(
inverse: PropTypes.bool,
reason: PropTypes.string,
dts: PropTypes.string,
+ isLoading: PropTypes.bool,
},
BootstrapButton.propTypes
);
Button.defaultProps = {
inverse: false,
+ isLoading: false,
};
export default Button;
diff --git a/src/components/third-party/bootstrap/Button/index.spec.jsx b/src/components/third-party/bootstrap/Button/index.spec.jsx
index 9bcdcd896..10debcc7f 100644
--- a/src/components/third-party/bootstrap/Button/index.spec.jsx
+++ b/src/components/third-party/bootstrap/Button/index.spec.jsx
@@ -1,8 +1,9 @@
import React from 'react';
import { shallow } from 'enzyme';
-import { Button } from 'third-party';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import BootstrapButton from 'react-bootstrap/lib/Button';
+import { Button } from 'third-party';
+import Spinner from 'alexandria/Spinner';
describe('ButtonComponent', () => {
it('should render Bootstrap Button', () => {
@@ -12,12 +13,12 @@ describe('ButtonComponent', () => {
it('should support legacy classname btn-inverse for non-breaking change', () => {
const element = shallow(Test );
- expect(element.prop('className')).to.equal('btn-inverse');
+ expect(element.prop('className')).to.equal('button-component btn-inverse');
});
it('should support className prop', () => {
const element = shallow(Test );
- expect(element.prop('className')).to.equal('all the-classes');
+ expect(element.prop('className')).to.equal('button-component all the-classes');
});
it('should not duplicate btn-inverse class if both legacy and new are used', () => {
@@ -26,12 +27,12 @@ describe('ButtonComponent', () => {
Test
);
- expect(element.prop('className')).to.equal('btn-inverse');
+ expect(element.prop('className')).to.equal('button-component btn-inverse');
});
it('should render inverse button with btn-inverse class', () => {
const element = shallow(Test );
- expect(element.prop('className')).to.equal('btn-inverse');
+ expect(element.prop('className')).to.equal('button-component btn-inverse');
});
it('should support data-test-selectors', () => {
@@ -54,4 +55,19 @@ describe('ButtonComponent', () => {
expect(overlay).to.have.length(1);
expect(shallow(overlay.prop('overlay')).text()).to.eql('Because');
});
+
+ it('should render Spinner if isLoading is true', () => {
+ const element = shallow(Spinner );
+ expect(element.find(Spinner)).to.have.length(1);
+ });
+
+ it('should only allow bsSize medium or small on Spinner', () => {
+ const element = shallow(
+
+ Spinner
+
+ );
+ const spinnerEl = element.find(Spinner);
+ expect(spinnerEl.prop('size')).to.equal('medium');
+ });
});
diff --git a/src/components/adslot-ui/SpinnerButton/styles.scss b/src/components/third-party/bootstrap/Button/styles.scss
similarity index 94%
rename from src/components/adslot-ui/SpinnerButton/styles.scss
rename to src/components/third-party/bootstrap/Button/styles.scss
index 0252b2215..ec06d21ae 100644
--- a/src/components/adslot-ui/SpinnerButton/styles.scss
+++ b/src/components/third-party/bootstrap/Button/styles.scss
@@ -1,4 +1,4 @@
-.spinner-button-component {
+.button-component {
position: relative;
&-children-container {
diff --git a/src/dist-entry/core.js b/src/dist-entry/core.js
index 56308e566..bb60b682f 100644
--- a/src/dist-entry/core.js
+++ b/src/dist-entry/core.js
@@ -61,7 +61,6 @@ import {
Panel,
Search,
SearchBar,
- SpinnerButton,
SplitPane,
Textarea,
TextEllipsis,
@@ -117,7 +116,6 @@ export {
Select,
Slicey,
Spinner,
- SpinnerButton,
SplitPane,
Statistic,
SvgSymbol,