Skip to content

Commit

Permalink
Update: SpinnerButtonComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
sonhanguyen committed Dec 20, 2016
1 parent 8b17bc5 commit fe3f253
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .sass-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ rules:
indentation: 2
leading-zero: 2
nesting-depth: [2, max-depth: 4]
property-sort-order: 2
property-sort-order: 0
property-units: [2, global: ['px', 's']]
quotes: 2
shorthand-values: 2
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
],
"author": "Adslot",
"devDependencies": {
"alexandria-adslot": "^4.0.0",
"alexandria-adslot": "^4.0.1",
"autoprefixer": "^6.5.3",
"babel-core": "^6.18.2",
"babel-eslint": "^6.1.2",
Expand Down
20 changes: 20 additions & 0 deletions src/components/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import moment from 'moment';
import {
Accordion,
Button,
SpinnerButton,
Checkbox,
ConfirmModal,
DatePicker,
Expand Down Expand Up @@ -327,6 +328,25 @@ class AppComponent extends React.Component {
<div className="btn btn-inverse btn-success">Div</div>
</div>

<h3>Spinner Buttons</h3>
<div className="btn-panel">
<SpinnerButton isLoading className="btn-borderless" bsSize="sm">
Small Borderless
</SpinnerButton>
<SpinnerButton isLoading bsStyle="success" bsSize="large">
Big Success
</SpinnerButton>
<SpinnerButton
isLoading
bsStyle="primary"
loadingHoverElement="stay put"
>
Primary
</SpinnerButton>
<SpinnerButton disabled>
Disabled
</SpinnerButton>
</div>

<h1>Tabs</h1>
<div className="btn-panel">
Expand Down
48 changes: 48 additions & 0 deletions src/components/adslotUi/SpinnerButtonComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import _ from 'lodash';
import React, { PropTypes } from 'react';
import classNames from 'classnames';

import Button from 'react-bootstrap/lib/Button';
import { Spinner } from 'alexandria-adslot';
import 'styles/adslotUi/SpinnerButton.scss';
import expandDts from '../../helpers/expandDtsHelper';

const SpinnerButton = (props) => {
const {
isLoading,
children,
loadingHoverElement = children,
dts,
} = props;

return (
<Button
disabled={isLoading || props.disabled}
{..._.pick(props, _.keys(Button.propTypes))}
className={classNames('spinner-button-component', props.className)}
{...expandDts(dts)}
>
<div className={`spinner-container ${isLoading ? '' : 'spinner-button-hidden'}`}>
<div className="spinner-button-spinner">
<Spinner size={_.includes(['lg', 'large'], props.bsSize) ? 'medium' : 'small'} />
</div>
<div className="spinner-button-hidden">{loadingHoverElement}</div>
</div>
<div className={isLoading ? 'spinner-button-hidden' : null}>{children}</div>
</Button>
);
};

SpinnerButton.propTypes = _.assign({
isLoading: PropTypes.bool,
loadingHoverElement: PropTypes.node,
dts: PropTypes.string,
}, Button.propTypes);

SpinnerButton.defaultProps = {
isLoading: false,
};

// SpinnerButton.Spinner = Spinner;

export default SpinnerButton;
18 changes: 10 additions & 8 deletions src/components/distributionEntry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Export the consumable components.
import Accordion from 'components/adslotUi/AccordionComponent';
import Button from 'react-bootstrap/lib/Button';
import SearchBar from 'components/adslotUi/SearchBarComponent';
import Checkbox from 'react-icheck/lib/Checkbox';
import ConfirmModal from 'components/adslotUi/ConfirmModalComponent';
Expand All @@ -23,6 +22,8 @@ import SplitPane from 'components/adslotUi/SplitPaneComponent';
import Tab from 'react-bootstrap/lib/Tab';
import Tabs from 'react-bootstrap/lib/Tabs';
import Toggle from 'react-toggle';
import SpinnerButton from 'components/adslotUi/SpinnerButtonComponent';
import Button from 'react-bootstrap/lib/Button';
import TreePickerGrid from 'components/adslotUi/TreePickerGridComponent';
import TreePickerNav from 'components/adslotUi/TreePickerNavComponent';
import TreePickerNode from 'components/adslotUi/TreePickerNodeComponent';
Expand Down Expand Up @@ -50,19 +51,20 @@ import {
Totals,
} from 'alexandria-adslot';

require('styles/_bootstrap-custom.scss');
require('styles/_icheck-custom.scss');
require('styles/_react-select-custom.scss');
require('styles/_react-toggle-custom.scss');
require('styles/_react-datepicker-custom.scss');
import 'styles/_bootstrap-custom.scss';
import 'styles/_icheck-custom.scss';
import 'styles/_react-select-custom.scss';
import 'styles/_react-toggle-custom.scss';
import 'styles/_react-datepicker-custom.scss';

module.exports = {
export {
Accordion,
Alert,
Avatar,
BorderedWell,
Breadcrumb,
Button,
SpinnerButton,
Card,
Checkbox,
ConfirmModal,
Expand All @@ -88,7 +90,7 @@ module.exports = {
Radio,
RadioGroup,
SearchBar,
SearchField: Search,
Search as SearchField,
Select,
Slicey,
SplitPane,
Expand Down
2 changes: 1 addition & 1 deletion src/examples/exampleEntry.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ExampleForm from './components/forms';
import ExampleSelect from './components/selects';

module.exports = {
export {
ExampleForm,
ExampleSelect,
};
48 changes: 48 additions & 0 deletions src/styles/adslotUi/SpinnerButton.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.spinner-button {
@mixin fill-area {
position: absolute;
right: 0;
left: 0;
margin-right: auto;
margin-left: auto;
}

&-hidden {
visibility: hidden;
}

&-spinner {
@include fill-area;
}

&-component {

.spinner-container {
@include fill-area;

&:hover {

.spinner-button-spinner {
visibility: hidden;
}

.spinner-button-hidden {
visibility: initial;
}
}

// workaround for vertical centering
.spinner-component {
.spinner {
&-small {
margin-top: 1px;
}

&-medium {
margin-top: -3px;
}
}
}
}
}
}
51 changes: 51 additions & 0 deletions test/components/adslotUi/SpinnerButtonComponentTest.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import SpinnerButton from 'components/adslotUi/SpinnerButtonComponent';
import { shallow } from 'enzyme';
import assert from 'assert';

describe('SpinnerButtonComponent', () => {
it('should render with defaults', () => {
const element = shallow(<SpinnerButton>Test</SpinnerButton>);
assert(element.find('Spinner'));
const buttonElement = element.find('Button');
assert(!buttonElement.prop('disabled'));
assert(!buttonElement.prop('isLoading'));
expect(element.children().last().text()).to.equal('Test');
});

it('should pass props to button', () => {
const element = shallow(
<SpinnerButton dts="test" bsStyle="primary" bsSize="lg" isLoading>Test</SpinnerButton>
);

const buttonElement = element.find('Button[data-test-selector="test"]');
expect(buttonElement.prop('bsStyle')).to.equal('primary');
expect(buttonElement.prop('bsSize')).to.equal('lg');
assert(!buttonElement.prop('isLoading'));
});

it('should accept custom loading hover element', () => {
const element = shallow(
<SpinnerButton loadingHoverElement="loading…">Test</SpinnerButton>
);
expect(element.children().first().text()).to.contains('loading…');
});

it('should be disabled in loading mode', () => {
const element = shallow(
<SpinnerButton>Test</SpinnerButton>
);
element.setProps({ isLoading: true });
const buttonElement = element.find('Button');
assert(buttonElement.prop('disabled'));
});

it('should have disabled state controled by disabled prop if present regardless of isLoading prop', () => {
const element = shallow(
<SpinnerButton isLoading="false" disabled>Test</SpinnerButton>
);

const buttonElement = element.find('Button');
assert(buttonElement.prop('disabled'));
});
});

0 comments on commit fe3f253

Please sign in to comment.