├── .babelrc
├── .eslintrc
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── .gitignore
├── README.md
├── package.json
├── public
│ └── index.html
└── src
│ ├── App.jsx
│ ├── demo.css
│ └── index.js
├── package.json
├── src
├── LaddaButton.jsx
├── constants.js
└── index.js
└── test
├── .eslintrc
├── .setup.js
└── LaddaButton-test.jsx
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"],
3 | "plugins": [
4 | "transform-regenerator",
5 | "transform-flow-strip-types"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "airbnb",
4 | "rules": {
5 | "semi": [2, "never"],
6 | "import/prefer-default-export": [0, "never"],
7 | "import/no-extraneous-dependencies": [
8 | "error", { "devDependencies": true }
9 | ]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
39 | dist
40 |
41 | # Webstorm
42 | .idea
43 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6.1"
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [6.0.0] - 2018-02-10
6 | ### Changed
7 | - Support `react@16.x.x`
8 |
9 | ## [5.0.7] - 2017-05-12
10 | ### Changed
11 | - Use external prop-types
12 |
13 | ## [5.0.6] - 2017-02-13
14 | ### Changed
15 | - Fixed a bug where setting `loading` to `false` would remove the `disabled` property from the button.
16 |
17 | ## [5.0.5] - 2016-12-31
18 | ### Changed
19 | - Disable button when loading
20 |
21 | ## [5.0.4] - 2016-11-09
22 | ### Changed
23 | - Use `ladda` as a dependency instead of a peerDependency
24 |
25 | ## [5.0.1] - 2016-09-22
26 | ### Changed
27 | - Support `react@15.x.x`
28 |
29 | ## [5.0.0] - 2016-09-17
30 | ### Changed
31 | - Refactor
32 | - Use Babel/ES7 for compilation
33 | - Fixed React warning described in #36
34 | - Changed prop names to the actual [data attributes that Ladda uses](https://github.com/hakimel/Ladda#html)
35 |
36 | ## [4.0.0] - ?
37 |
38 | ## [3.0.0] - 2015-07-11
39 | ### Changed
40 | - New props for `LaddaButton` that do not collide with existing element props (`buttonStyle` instead of `style`)
41 | - Gave `LaddaButton` ownership of the `button` component. Any props applied to the `LaddaButton` are applied to the wrapped `button`. The children of the `LaddaButton` are rendered inside `ladda-label`.
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2014, ∞) Jason Sommer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | react-ladda
2 | ===========
3 |
4 | [](https://travis-ci.org/jsdir/react-ladda)
5 | [](https://david-dm.org/jsdir/react-ladda)
6 | [](https://www.npmjs.org/package/react-ladda)
7 | [](https://codeclimate.com/github/jsdir/react-ladda)
8 |
9 | A React wrapper for [Ladda buttons](https://github.com/hakimel/Ladda). [Example](https://github.com/jsdir/react-ladda/blob/master/example/README.md)
10 |
11 | ## Installation
12 |
13 | `react-ladda` can be installed directly through npm:
14 |
15 | ```sh
16 | $ npm install --save react-ladda
17 | ```
18 |
19 | ## Usage
20 |
21 | `LaddaButton` is a React component that renders a [Ladda button](https://github.com/hakimel/Ladda). You can change the button's loading state and progress using the `loading` and `progress` props.
22 |
23 | ```jsx
24 | import React, { Component } from 'react';
25 |
26 | import LaddaButton, { XL, SLIDE_UP } from 'react-ladda';
27 |
28 | class App extends Component {
29 |
30 | state = { loading: false };
31 |
32 | toggle() {
33 | this.setState({
34 | loading: !this.state.loading,
35 | progress: 0.5,
36 | });
37 | }
38 |
39 | render() {
40 | return (
41 |
51 | Click Here!
52 |
53 | );
54 | }
55 | };
56 |
57 | ReactDOM.render( , document.body);
58 | ```
59 |
60 | Although this package doesn't include the styles for the Ladda buttons, there are many different ways to include them. The easiest way is to add the following tag to your document:
61 |
62 | ```html
63 |
64 | ```
65 |
66 | ## Props
67 |
68 | All of the native [Ladda button options](https://github.com/hakimel/Ladda#html) are supported through props:
69 |
70 | Prop | Type | Description
71 | -------------------- | --------- | -----------
72 | `loading` | `boolean` | Displays the button's loading indicator
73 | `progress` | `number` | Number from 0.0 to 1.0
74 | `data-color` | `string` | Color applied to the button (`{green,red,blue,purple,mint}`)
75 | `data-size` | `string` | A [button size](#sizes)
76 | `data-style` | `string` | A [button style](#styles)
77 | `data-spinner-size` | `number` | Number representing the size of the spinner in pixels
78 | `data-spinner-color` | `string` | Color applied to the spinner (eg. `#eee`)
79 | `data-spinner-lines` | `number` | Number of spokes in the spinner
80 |
81 | ## Sizes and Styles
82 |
83 | Ladda comes with a variety of different [sizes and styles](http://lab.hakim.se/ladda/) that you can use. Button sizes and styles can be directly imported from `react-ladda`:
84 |
85 | ```js
86 | import LaddaButton, { XS, EXPAND_LEFT } from 'react-ladda'
87 | ```
88 |
89 | ### Sizes
90 |
91 | - `XS`
92 | - `S`
93 | - `L`
94 | - `XL`
95 |
96 | ### Styles
97 |
98 | - `CONTRACT`
99 | - `CONTRACT_OVERLAY`
100 | - `EXPAND_LEFT`
101 | - `EXPAND_RIGHT`
102 | - `EXPAND_UP`
103 | - `EXPAND_DOWN`
104 | - `SLIDE_LEFT`
105 | - `SLIDE_RIGHT`
106 | - `SLIDE_UP`
107 | - `SLIDE_DOWN`
108 | - `ZOOM_IN`
109 | - `ZOOM_OUT`
110 |
111 | ## Development
112 |
113 | After cloning and running `npm install`, you can use the following `npm` commands for easier development:
114 |
115 | Command | Description
116 | --------------- | -----------
117 | `npm test` | Runs the test suite
118 | `npm run watch` | Runs the test suite and reruns when any source or test file changes
119 | `npm run lint` | Lints both the source and test files
120 | `npm run build` | Compiles the source into ES5 and outputs the results into `dist`
121 |
122 | _Contributions are more than welcome!_
123 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | React Ladda Button Example
2 | ==============================
3 |
4 | This is a runnable demo showing how to use `react-ladda`
5 |
6 | ## Running Example
7 |
8 | **In the example directory, run:**
9 | ```
10 | $ npm install
11 | $ npm start
12 | ```
13 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.6.1"
7 | },
8 | "dependencies": {
9 | "react": "^15.3.2",
10 | "react-dom": "^15.3.2",
11 | "react-ladda": "^5.0.3"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ladda
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import LaddaButton, {
3 | EXPAND_LEFT,
4 | EXPAND_RIGHT,
5 | EXPAND_UP,
6 | EXPAND_DOWN,
7 | CONTRACT,
8 | CONTRACT_OVERLAY,
9 | SLIDE_LEFT,
10 | SLIDE_RIGHT,
11 | SLIDE_UP,
12 | SLIDE_DOWN,
13 | ZOOM_IN,
14 | ZOOM_OUT
15 | } from 'react-ladda'
16 |
17 | import './demo.css'
18 |
19 | class App extends Component {
20 | state = {
21 | expLeft: false,
22 | expRight: false,
23 | expUp: false,
24 | expDown: false,
25 | expContract: false,
26 | expOverlay: false,
27 | expSlideLeft: false,
28 | expSlideRight: false,
29 | expSlideUp: false,
30 | expSlideDown: false,
31 | expZoomIn: false,
32 | expZoomOut: false,
33 | }
34 |
35 | toggle(name) {
36 | this.setState({
37 | [name]: !this.state[name],
38 | progress: 0.5,
39 | })
40 | }
41 |
42 | render() {
43 | return (
44 |
45 |
46 |
Ladda
47 |
48 | A UI concept which merges loading indicators into the action that invoked them.
49 | Primarily intended for use with forms where
50 | it gives users immediate feedback upon submit rather than leaving them wondering
51 | while the browser does its thing. For a
52 | real-world example, check out any of the forms on slides.com .
53 |
54 |
55 | expand-left
56 | this.toggle('expLeft')}
59 | data-color="green"
60 | data-style={EXPAND_LEFT}
61 | >
62 | Submit!
63 |
64 |
65 |
66 | expand-right
67 | this.toggle('expRight')}
70 | data-color="green"
71 | data-style={EXPAND_RIGHT}
72 | >
73 | Submit!
74 |
75 |
76 |
77 |
78 | expand-up
79 | this.toggle('expUp')}
82 | data-color="green"
83 | data-style={EXPAND_UP}
84 | >
85 | Submit!
86 |
87 |
88 |
89 |
90 | expand-down
91 | this.toggle('expDown')}
94 | data-color="green"
95 | data-style={EXPAND_DOWN}
96 | >
97 | Submit!
98 |
99 |
100 |
101 | {/* Set 2 */}
102 |
103 | contract
104 | this.toggle('expContract')}
107 | data-color="red"
108 | data-style={CONTRACT}
109 | >
110 | Submit!
111 |
112 |
113 |
114 |
115 | contract-overlay
116 | this.toggle('expOverlay')}
119 | data-color="red"
120 | data-style={CONTRACT_OVERLAY}
121 | >
122 | Submit!
123 |
124 |
125 |
126 |
127 | zoom-in
128 | this.toggle('expZoomIn')}
131 | data-color="red"
132 | data-style={ZOOM_IN}
133 | >
134 | Submit!
135 |
136 |
137 |
138 |
139 | zoom-out
140 | this.toggle('expZoomOut')}
143 | data-color="red"
144 | data-style={ZOOM_OUT}
145 | >
146 | Submit!
147 |
148 |
149 |
150 | {/* Set 3 */}
151 |
152 |
153 | slide-left
154 | this.toggle('expSlideLeft')}
157 | data-color="blue"
158 | data-style={SLIDE_LEFT}
159 | >
160 | Submit!
161 |
162 |
163 |
164 |
165 | slide-right
166 | this.toggle('expSlideRight')}
169 | data-color="blue"
170 | data-style={SLIDE_RIGHT}
171 | >
172 | Submit!
173 |
174 |
175 |
176 |
177 | slide-up
178 | this.toggle('expSlideUp')}
181 | data-color="blue"
182 | data-style={SLIDE_UP}
183 | >
184 | Submit!
185 |
186 |
187 |
188 |
189 | slide-down
190 | this.toggle('expSlideDown')}
193 | data-color="blue"
194 | data-style={SLIDE_DOWN}
195 | >
196 | Submit!
197 |
198 |
199 |
200 |
201 | )
202 | }
203 | }
204 |
205 | export default App
206 |
--------------------------------------------------------------------------------
/example/src/demo.css:
--------------------------------------------------------------------------------
1 | /* Styles used specifically for the demo page */
2 |
3 | body {
4 | background: #f5f5f5;
5 | font-family: monospace;
6 | font-size: 14px;
7 | color: #333333;
8 | }
9 |
10 | button {
11 | outline: 0;
12 | }
13 |
14 | .examples {
15 | max-width: 670px;
16 | margin: 2em auto;
17 | padding: 4em;
18 | background: #fff;
19 | text-align: center
20 | }
21 | .examples .intro {
22 | margin-bottom: 3em;
23 | line-height: 1.4em;
24 | font-size: 16px;
25 | text-align: left;
26 | }
27 | .examples .intro h1 {
28 | margin-top: 0;
29 | font-size: 18px;
30 | }
31 |
32 | .examples .outro {
33 | display: block;
34 | text-align: right;
35 | margin-top: 3em;
36 | }
37 | .examples section {
38 | display: inline-block;
39 | width: 24%;
40 | min-width: 160px;
41 | margin-bottom: 2em;
42 | text-align: center;
43 | vertical-align: top;
44 | }
45 | .examples section h3 {
46 | color: #bbb;
47 | font-weight: normal;
48 | font-size: 15px;
49 | }
50 |
51 | .sharing {
52 | float: left;
53 | }
54 |
--------------------------------------------------------------------------------
/example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | ReactDOM.render(
5 | ,
6 | document.getElementById('root')
7 | );
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-ladda",
3 | "version": "6.0.0",
4 | "description": "React wrapper for Ladda buttons",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "watch": "./node_modules/.bin/mocha -w --watch-extensions=jsx test/.setup.js test/**/*-test.jsx",
8 | "test": "./node_modules/.bin/mocha test/.setup.js test/**/*-test.jsx",
9 | "lint": "./node_modules/.bin/eslint src/**/* test/**/*",
10 | "build": "npm run lint && ./node_modules/.bin/babel src --out-dir dist",
11 | "prepublish": "npm run build"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/jsdir/react-ladda.git"
16 | },
17 | "keywords": [
18 | "react",
19 | "component",
20 | "boilerplate"
21 | ],
22 | "author": "Jason Sommer",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/jsdir/react-ladda/issues"
26 | },
27 | "homepage": "https://github.com/jsdir/react-ladda#readme",
28 | "dependencies": {
29 | "ladda": "^1.0.0",
30 | "prop-types": "^15.5.8"
31 | },
32 | "devDependencies": {
33 | "babel-cli": "^6.14.0",
34 | "babel-eslint": "^6.1.2",
35 | "babel-plugin-transform-flow-strip-types": "^6.8.0",
36 | "babel-plugin-transform-regenerator": "^6.4.4",
37 | "babel-preset-es2015": "^6.3.13",
38 | "babel-preset-react": "^6.3.13",
39 | "babel-preset-stage-0": "^6.3.13",
40 | "babel-register": "^6.4.3",
41 | "chai": "^3.5.0",
42 | "chai-enzyme": "^1.0.0-beta.0",
43 | "cheerio": "^1.0.0-rc.2",
44 | "enzyme": "^3.0.0",
45 | "enzyme-adapter-react-16": "^1.1.1",
46 | "eslint": "^3.7.0",
47 | "eslint-config-airbnb": "^12.0.0",
48 | "eslint-plugin-import": "^1.16.0",
49 | "eslint-plugin-jsx-a11y": "^2.2.2",
50 | "eslint-plugin-react": "^6.3.0",
51 | "jsdom": "^8.0.1",
52 | "mocha": "^2.4.5",
53 | "react": "^16.0.0",
54 | "react-dom": "^16.0.0",
55 | "react-test-renderer": "^16.2.0",
56 | "sinon": "^1.17.5",
57 | "sinon-chai": "^2.8.0"
58 | },
59 | "peerDependencies": {
60 | "react": "^16.0.0",
61 | "react-dom": "^16.0.0"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/LaddaButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import Ladda from 'ladda'
4 |
5 | import { SIZES, STYLES } from './constants'
6 |
7 | const isUndefined = value => typeof value === 'undefined'
8 |
9 | const OMITTED_PROPS = [
10 | 'loading',
11 | 'progress',
12 | ]
13 |
14 | const omit = (data, keys) => {
15 | const result = {}
16 | Object.keys(data).forEach((key) => {
17 | if (keys.indexOf(key) === -1) {
18 | result[key] = data[key]
19 | }
20 | })
21 |
22 | return result
23 | }
24 |
25 | export default
26 | class LaddaButton extends Component {
27 |
28 | static propTypes = {
29 | children: PropTypes.node,
30 | className: PropTypes.string,
31 | progress: PropTypes.number,
32 | loading: PropTypes.bool,
33 | disabled: PropTypes.bool,
34 |
35 | // Ladda props
36 | // eslint-disable-next-line react/no-unused-prop-types
37 | 'data-color': PropTypes.oneOf(['green', 'red', 'blue', 'purple', 'mint']),
38 | // eslint-disable-next-line react/no-unused-prop-types
39 | 'data-size': PropTypes.oneOf(SIZES),
40 | // eslint-disable-next-line react/no-unused-prop-types
41 | 'data-style': PropTypes.oneOf(STYLES),
42 | // eslint-disable-next-line react/no-unused-prop-types
43 | 'data-spinner-size': PropTypes.number,
44 | // eslint-disable-next-line react/no-unused-prop-types
45 | 'data-spinner-color': PropTypes.string,
46 | // eslint-disable-next-line react/no-unused-prop-types
47 | 'data-spinner-lines': PropTypes.number,
48 | };
49 |
50 | componentDidMount() {
51 | this.laddaInstance = Ladda.create(this.node)
52 |
53 | if (this.props.loading) {
54 | this.laddaInstance.start()
55 | }
56 |
57 | if (!isUndefined(this.props.progress)) {
58 | this.laddaInstance.setProgress(this.props.progress)
59 | }
60 | }
61 |
62 | componentWillReceiveProps(nextProps) {
63 | this.updateLaddaInstance(nextProps)
64 | }
65 |
66 | componentWillUnmount() {
67 | this.laddaInstance.remove()
68 | }
69 |
70 | setNode = (node) => {
71 | this.node = node
72 | }
73 |
74 | updateLaddaInstance = (props) => {
75 | if (props.loading !== this.props.loading) {
76 | if (props.loading) {
77 | this.laddaInstance.start()
78 | } else if (props.disabled) {
79 | // .stop removes the attribute "disabled"
80 | // .disable calls .stop then adds the attribute "disabled"
81 | // see https://github.com/hakimel/Ladda/blob/master/js/ladda.js
82 | this.laddaInstance.disable()
83 | } else {
84 | this.laddaInstance.stop()
85 | }
86 | }
87 |
88 | if (props.progress !== this.props.progress) {
89 | this.laddaInstance.setProgress(props.progress)
90 | }
91 | }
92 |
93 | render() {
94 | return (
95 |
101 |
102 | {this.props.children}
103 |
104 |
105 | )
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | export const XS = 'xs'
2 | export const S = 's'
3 | export const L = 'l'
4 | export const XL = 'xl'
5 |
6 | export const SIZES = [
7 | XS,
8 | S,
9 | L,
10 | XL,
11 | ]
12 |
13 | export const CONTRACT = 'contract'
14 | export const CONTRACT_OVERLAY = 'contract-overlay'
15 | export const EXPAND_LEFT = 'expand-left'
16 | export const EXPAND_RIGHT = 'expand-right'
17 | export const EXPAND_UP = 'expand-up'
18 | export const EXPAND_DOWN = 'expand-down'
19 | export const SLIDE_LEFT = 'slide-left'
20 | export const SLIDE_RIGHT = 'slide-right'
21 | export const SLIDE_UP = 'slide-up'
22 | export const SLIDE_DOWN = 'slide-down'
23 | export const ZOOM_IN = 'zoom-in'
24 | export const ZOOM_OUT = 'zoom-out'
25 |
26 | export const STYLES = [
27 | CONTRACT,
28 | CONTRACT_OVERLAY,
29 | EXPAND_LEFT,
30 | EXPAND_RIGHT,
31 | EXPAND_UP,
32 | EXPAND_DOWN,
33 | SLIDE_LEFT,
34 | SLIDE_RIGHT,
35 | SLIDE_UP,
36 | SLIDE_DOWN,
37 | ZOOM_IN,
38 | ZOOM_OUT,
39 | ]
40 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import LaddaButton from './LaddaButton'
2 |
3 | export default LaddaButton
4 | export * from './constants'
5 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "mocha": true
5 | },
6 | "rules": {
7 | "no-unused-expressions": 0
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/.setup.js:
--------------------------------------------------------------------------------
1 | require('babel-register')();
2 | const { configure } = require('enzyme');
3 | const Adapter = require('enzyme-adapter-react-16');
4 |
5 | configure({ adapter: new Adapter() });
6 | var jsdom = require('jsdom').jsdom;
7 |
8 | var exposedProperties = ['window', 'navigator', 'document'];
9 |
10 | global.document = jsdom('');
11 | global.window = document.defaultView;
12 | Object.keys(document.defaultView).forEach((property) => {
13 | if (typeof global[property] === 'undefined') {
14 | exposedProperties.push(property);
15 | global[property] = document.defaultView[property];
16 | }
17 | });
18 |
19 | global.navigator = {
20 | userAgent: 'node.js'
21 | };
22 |
23 | documentRef = document;
24 |
25 | var chai = require('chai');
26 | chai.use(require('chai-enzyme')());
27 | chai.use(require('sinon-chai'));
28 |
--------------------------------------------------------------------------------
/test/LaddaButton-test.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { findDOMNode } from 'react-dom'
3 | import { expect } from 'chai'
4 | import { render, mount } from 'enzyme'
5 | import sinon from 'sinon'
6 | import Ladda from 'ladda'
7 |
8 | import LaddaButton from '../src/LaddaButton'
9 | import { XL, SLIDE_UP } from '../src/constants'
10 |
11 | describe('LaddaButton', () => {
12 | it('should render the elements correctly', () => {
13 | // The correct markup that Ladda expects is defined here:
14 | // https://github.com/hakimel/Ladda#html
15 | const wrapper = mount(child )
16 | const button = wrapper.find('button.ladda-button')
17 | expect(button).to.be.present()
18 | const label = button.find('span.ladda-label')
19 | expect(label).to.be.present()
20 | expect(label).to.have.text('child')
21 | })
22 |
23 | it('should pass data attributes down to the button', () => {
24 | const wrapper = render(
25 |
33 | )
34 |
35 | expect(wrapper).to.have.attr('data-color').equal('#eee')
36 | expect(wrapper).to.have.attr('data-size').equal(XL)
37 | expect(wrapper).to.have.attr('data-style').equal(SLIDE_UP)
38 | expect(wrapper).to.have.attr('data-spinner-size').equal('30')
39 | expect(wrapper).to.have.attr('data-spinner-color').equal('#ddd')
40 | expect(wrapper).to.have.attr('data-spinner-lines').equal('12')
41 | })
42 |
43 | it('should not pass blacklisted props to the Ladda button', () => {
44 | const wrapper = mount(
45 |
49 | )
50 | const button = wrapper.find('button')
51 | expect(button).to.not.have.prop('loading')
52 | expect(button).to.not.have.prop('progress')
53 | })
54 |
55 | it('should combine classNames correctly', () => {
56 | const wrapper = mount(
57 |
58 | )
59 |
60 | expect(
61 | wrapper.find('button.ladda-button.custom')
62 | ).to.be.present()
63 | })
64 |
65 | it('should pass props down to the button', () => {
66 | const handler = () => {}
67 | const wrapper = mount( )
68 | expect(wrapper.find('button')).prop('onClick').to.eq(handler)
69 | })
70 |
71 | it('should allow `loading` and `progress` to be changed in the same state update', () => {
72 | const wrapper = mount( )
73 |
74 | // Ladda depends on a set `offsetWidth` for calculations.
75 | const node = findDOMNode(wrapper.instance())
76 | node.offsetWidth = 200
77 |
78 | expect(wrapper.html()).not.to.contain('ladda-progress')
79 | wrapper.setProps({ loading: true, progress: 0.4 })
80 | expect(wrapper.html()).to.contain('ladda-progress')
81 | })
82 |
83 | it('should not disable the button if `props.loading` is falsey', () => {
84 | const wrapper = mount( )
85 | expect(wrapper.find('button').prop('disabled')).to.eq(undefined)
86 | })
87 |
88 | it('should disable the button if the `props.disabled` is set', () => {
89 | const wrapper = mount( )
90 | expect(wrapper.find('button').prop('disabled')).to.eq(true)
91 | })
92 |
93 | it('should disable the button if `props.loading` is truthy', () => {
94 | const wrapper = mount( )
95 | expect(wrapper.find('button').prop('disabled')).to.eq(true)
96 | })
97 |
98 | it('should keep the attribute `disabled` after loading', () => {
99 | const wrapper = mount( )
100 | expect(wrapper.find('button')).to.have.attr('disabled')
101 | wrapper.setProps({ loading: true })
102 | wrapper.setProps({ loading: false })
103 | expect(wrapper.find('button')).to.have.attr('disabled')
104 | })
105 |
106 | describe('ladda instance', () => {
107 | let createStub
108 | let laddaInstance
109 |
110 | beforeEach(() => {
111 | createStub = sinon.stub(Ladda, 'create')
112 | laddaInstance = {
113 | remove: sinon.spy(),
114 | setProgress: sinon.spy(),
115 | start: sinon.spy(),
116 | stop: sinon.spy(),
117 | }
118 | createStub.returns(laddaInstance)
119 | })
120 |
121 | afterEach(() => {
122 | createStub.restore()
123 | })
124 |
125 | it('should be maintained for the entire lifecycle of the component', () => {
126 | const wrapper = mount( )
127 | const node = findDOMNode(wrapper.instance())
128 | expect(createStub).to.have.been.calledWithExactly(node)
129 | wrapper.unmount()
130 | expect(laddaInstance.remove).to.have.been.calledWithExactly()
131 | })
132 |
133 | it('should receive setProgress call when progress is set', () => {
134 | const wrapper = mount( )
135 | expect(laddaInstance.setProgress).not.to.have.been.called
136 |
137 | wrapper.setProps({ progress: 0.5 })
138 | expect(laddaInstance.setProgress).to.have.been.calledWithExactly(0.5)
139 | laddaInstance.setProgress.reset()
140 |
141 | wrapper.setProps({ progress: 0.6 })
142 | expect(laddaInstance.setProgress).to.have.been.calledWithExactly(0.6)
143 | laddaInstance.setProgress.reset()
144 |
145 | wrapper.setProps({ progress: 0.6 })
146 | expect(laddaInstance.setProgress).not.to.have.been.called
147 | })
148 |
149 | it('should receive start and stop calls when loading is set', () => {
150 | const wrapper = mount( )
151 | expect(laddaInstance.stop).not.to.have.been.called
152 | expect(laddaInstance.start).not.to.have.been.called
153 |
154 | wrapper.setProps({ loading: true })
155 | expect(laddaInstance.start).to.have.been.calledWithExactly()
156 | laddaInstance.start.reset()
157 |
158 | wrapper.setProps({ loading: true })
159 | expect(laddaInstance.start).not.to.have.been.called
160 |
161 | wrapper.setProps({ loading: false })
162 | expect(laddaInstance.stop).to.have.been.calledWithExactly()
163 | laddaInstance.stop.reset()
164 |
165 | wrapper.setProps({ loading: false })
166 | expect(laddaInstance.stop).not.to.have.been.called
167 | })
168 |
169 | context('when `props.progress` is initially set', () => {
170 | beforeEach(() => {
171 | mount( )
172 | })
173 |
174 | it('should receive a setProgress call ', () => {
175 | expect(laddaInstance.setProgress).to.have.been.calledWithExactly(0.3)
176 | })
177 | })
178 |
179 | context('when `props.loading` is initially set', () => {
180 | beforeEach(() => {
181 | mount( )
182 | })
183 |
184 | it('should receive a start call', () => {
185 | expect(laddaInstance.start).to.have.been.calledWithExactly()
186 | })
187 | })
188 | })
189 | })
190 |
--------------------------------------------------------------------------------