├── .gitattributes ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gruntfile.cjs ├── LICENSE ├── README.md ├── css ├── ladda-themed.scss └── ladda.scss ├── js ├── ladda.d.ts └── ladda.js ├── package.json ├── rollup.config.js └── site ├── bootstrap.html ├── bootstrap3.html ├── bootstrap4.html ├── demo.css ├── form.html ├── form.js ├── index.html ├── index.js └── rtl.html /.gitattributes: -------------------------------------------------------------------------------- 1 | # so website files won't cause project language to be shown as HTML 2 | site/* linguist-documentation 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /dist/ 3 | /site/dist/ 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [2.0.3] - 2021-12-02 10 | ### Fixed 11 | - Deprecated slash as division when using Dart Sass (issue [#109]) 12 | 13 | ## [2.0.2] - 2021-09-01 14 | ### Changed 15 | - Set package type to `module` to better support native ES module imports 16 | - Code cleanup and documentation improvements 17 | 18 | ## [2.0.1] - 2018-05-14 19 | ### Added 20 | - Support for reassigning `$spinnerSize` Sass variable (PR [#81]) 21 | - Re-included Sass files in the npm package 22 | 23 | ## [2.0.0] - 2018-05-13 24 | ### Added 25 | - Built-in TypeScript definitions 26 | - Support for the `style-src 'self';` Content Security Policy 27 | 28 | ### Changed 29 | - Rewritten as a native ES6 module using spin.js v4 30 | 31 | ### Removed 32 | - Deprecated jQuery API 33 | - Deprecated `enable` and `disable` methods 34 | - Bower support 35 | - Support for Internet Explorer 9 (not supported by spin.js v4) 36 | 37 | ## [1.0.6] - 2018-02-04 38 | ### Added 39 | - Support for forms with `novalidate` attribute (issue [#80]) 40 | 41 | ### Fixed 42 | - Protruding outline in Chrome on buttons with a progress bar 43 | 44 | ## [1.0.5] - 2017-09-24 45 | ### Added 46 | - Validation for URL input fields in IE 9 47 | 48 | ### Fixed 49 | - Detection of required HTML5 inputs in IE 9 50 | - Bug where the `stop()` method would remove a button's disabled state even though Ladda was already stopped (issue [#68]) 51 | 52 | ## [1.0.4] - 2017-08-27 53 | ### Fixed 54 | - Incorrect return value for jQuery `isLoading` argument (PR [#62], issue [#65]) 55 | 56 | Note that the Ladda jQuery API is deprecated - it is recommended to use the plain JavaScript API instead. 57 | 58 | ## [1.0.3] - 2017-08-27 59 | ### Changed 60 | - Code cleanup and performance improvements 61 | 62 | ### Deprecated 63 | - Undocumented `enable` and `disable` instance methods 64 | 65 | ## [1.0.2] - 2017-08-27 66 | ### Added 67 | - Support for right-to-left text direction (PR [#66]) 68 | 69 | ### Deprecated 70 | - jQuery API 71 | 72 | ## [1.0.1] - 2017-07-11 73 | ### Fixed 74 | - Bug where focus outline protruded outside button in Chrome 75 | 76 | ### Removed 77 | - Unnecessary `toArray()` function 78 | 79 | ## [1.0.0] - 2016-03-08 80 | ### Added 81 | - `data-spinner-lines` attribute for controlling the number of lines in the spinner (PR [#50]) 82 | 83 | ### Changed 84 | - The `ladda-button` class and `data-style` attribute are now automatically set if missing (PR [#52]) 85 | - `ladda-label` now wraps existing elements instead of reinserting them using `innerHTML` (PR [#55]) 86 | - `checkValidity` is now used to validate forms where supported (PR [#58]) 87 | 88 | ## [0.9.8] - 2015-04-05 89 | ### Added 90 | - `main` field to package.json for easier CommonJS loading (PR [#47]) 91 | - Validity check for email inputs (PR [#48]) 92 | 93 | ### Changed 94 | - Updated spin.js to v2.0.2 (PR [#49]) 95 | 96 | ## [0.9.7] - 2015-01-17 97 | ### Fixed 98 | - The Ladda theme is now baked into the output ladda.min.css file again. Was broken after upgrading grunt Sass in v0.9.5. 99 | 100 | ## [0.9.6] - 2015-01-16 101 | ### Removed 102 | - Unintended references to non-existing sourcemap files that were introduced in v0.9.5 as part of the grunt Sass upgrade. 103 | 104 | ## [0.9.5] - 2015-01-16 105 | ### Fixed 106 | - Validation of required select, radio, and checkbox inputs (PR [#43]) 107 | - The `ladda-spinner` element is no longer created if it already exists (PR [#44]) 108 | 109 | ## [0.9.4] - 2014-06-21 110 | ### Added 111 | - `remove()` method to Ladda instances to stop memory leaks (PR [#36]) 112 | 113 | ### Changed 114 | - Updated from spin.js v1.3 to v2.0 (PR [#37]) 115 | 116 | ## [0.9.3] - 2014-04-16 117 | ### Added 118 | - jQuery wrapper (PR [#33]) 119 | 120 | ### Fixed 121 | - Overlay effect in Safari 122 | - Missing CommonJS requirement 123 | 124 | ## [0.9.2] - 2013-12-03 125 | ### Fixed 126 | - Spinner height is now calculated when spinning starts as opposed to when Ladda is initialized. This fixes spinner sizing issues with buttons that are initially hidden. 127 | 128 | ## [0.9.1] - 2013-11-27 129 | ### Fixed 130 | - Issue where loading animations did not start for buttons outside of forms. This only affected use through the `Ladda.bind()` method. 131 | 132 | ## [0.9.0] - 2013-10-23 133 | ### Changed 134 | - Ladda now confirms that all `required` fields in its parent form are filled out before starting the spinning animation. Note that this only applies to buttons bound using `Ladda.bind()`. 135 | 136 | ### Removed 137 | - jQuery dependencies 138 | 139 | ## [0.8.0] - 2013-09-05 140 | ### Added 141 | - `data-spinner-color` attribute for configuring spinner color 142 | 143 | ### Changed 144 | - Disabled pointer events on spinner element 145 | 146 | ### Fixed 147 | - Array conversion bug which prevented binding Ladda to a selector 148 | - Default `z-index` value, was `initial` but should be `auto` 149 | 150 | ## [0.7.0] - 2013-07-19 151 | ### Added 152 | - `startAfter(delay)` method 153 | 154 | ### Changed 155 | - Limit progress value to number between `0` and `1` 156 | 157 | ### Fixed 158 | - Issue that prevented forms from submitting 159 | - Error that caused IE 8 to blow up on page load (still not supported, though) 160 | 161 | ## [0.6.0] - 2013-07-07 162 | ### Added 163 | - `data-spinner-size` attribute for setting explicit pixel size of spinner 164 | 165 | ### Changed 166 | - `ladda-label` wrapper is now automatically created if it doesn't exist 167 | 168 | ## [0.5.2] - 2013-06-27 169 | ### Added 170 | - bower.json 171 | 172 | ### Fixed 173 | - Error when passing element to `Ladda.create()` 174 | 175 | ## [0.5.1] - 2013-06-19 176 | ### Added 177 | - Bootstrap integration example 178 | 179 | ## [0.5.0] - 2013-06-19 180 | ### Changed 181 | - Split visual and functional styles into separate stylesheets for framework compatibility (issue [#20]) 182 | - Spinner size is now automatically calculated using JavaScript 183 | 184 | ## [0.4.2] - 2013-06-14 185 | ### Added 186 | - Size options (issue [#15]) 187 | - Mint color preset 188 | 189 | ### Changed 190 | - All settings are now applied via `data-*` attributes 191 | 192 | ## [0.4.1] - 2013-06-14 193 | ### Added 194 | - `enable` and `disable` helper methods 195 | 196 | ## [0.4.0] - 2013-06-14 197 | ### Added 198 | - Common.js / AMD module support 199 | - Grunt build file and minified files in /dist folder 200 | 201 | ### Changed 202 | - Migrated from plain CSS to Sass 203 | 204 | ## [0.3.0] - 2013-06-08 205 | ### Added 206 | - Built-in progress bars which can be controlled using `setProgress` method 207 | 208 | ### Changed 209 | - Replaced spinner GIF with spin.js 210 | - `spinner` and `label` classes are now prefixed with `ladda-` 211 | 212 | ### Removed 213 | - Hardcoded timeout 214 | 215 | ## [0.2.0] - 2013-06-05 216 | ### Added 217 | - Simple JavaScript API 218 | - Instructions in readme 219 | - MIT license 220 | 221 | ## [0.1.0] - 2013-06-05 222 | - Initial release 223 | 224 | [Unreleased]: https://github.com/hakimel/Ladda/compare/2.0.3...HEAD 225 | [2.0.3]: https://github.com/hakimel/Ladda/compare/2.0.2...2.0.3 226 | [2.0.2]: https://github.com/hakimel/Ladda/compare/2.0.1...2.0.2 227 | [2.0.1]: https://github.com/hakimel/Ladda/compare/2.0.0...2.0.1 228 | [2.0.0]: https://github.com/hakimel/Ladda/compare/1.0.6...2.0.0 229 | [1.0.6]: https://github.com/hakimel/Ladda/compare/1.0.5...1.0.6 230 | [1.0.5]: https://github.com/hakimel/Ladda/compare/1.0.4...1.0.5 231 | [1.0.4]: https://github.com/hakimel/Ladda/compare/1.0.3...1.0.4 232 | [1.0.3]: https://github.com/hakimel/Ladda/compare/1.0.2...1.0.3 233 | [1.0.2]: https://github.com/hakimel/Ladda/compare/1.0.1...1.0.2 234 | [1.0.1]: https://github.com/hakimel/Ladda/compare/1.0.0...1.0.1 235 | [1.0.0]: https://github.com/hakimel/Ladda/compare/0.9.8...1.0.0 236 | [0.9.8]: https://github.com/hakimel/Ladda/compare/0.9.7...0.9.8 237 | [0.9.7]: https://github.com/hakimel/Ladda/compare/0.9.6...0.9.7 238 | [0.9.6]: https://github.com/hakimel/Ladda/compare/0.9.5...0.9.6 239 | [0.9.5]: https://github.com/hakimel/Ladda/compare/0.9.4...0.9.5 240 | [0.9.4]: https://github.com/hakimel/Ladda/compare/0.9.3...0.9.4 241 | [0.9.3]: https://github.com/hakimel/Ladda/compare/0.9.2...0.9.3 242 | [0.9.2]: https://github.com/hakimel/Ladda/compare/0.9.1...0.9.2 243 | [0.9.1]: https://github.com/hakimel/Ladda/compare/0.9.0...0.9.1 244 | [0.9.0]: https://github.com/hakimel/Ladda/compare/0.8.0...0.9.0 245 | [0.8.0]: https://github.com/hakimel/Ladda/compare/0.7.0...0.8.0 246 | [0.7.0]: https://github.com/hakimel/Ladda/compare/0.6.0...0.7.0 247 | [0.6.0]: https://github.com/hakimel/Ladda/compare/0.5.2...0.6.0 248 | [0.5.2]: https://github.com/hakimel/Ladda/compare/0.5.1...0.5.2 249 | [0.5.1]: https://github.com/hakimel/Ladda/compare/0.5.0...0.5.1 250 | [0.5.0]: https://github.com/hakimel/Ladda/compare/0.4.2...0.5.0 251 | [0.4.2]: https://github.com/hakimel/Ladda/compare/0.4.1...0.4.2 252 | [0.4.1]: https://github.com/hakimel/Ladda/compare/0.4.0...0.4.1 253 | [0.4.0]: https://github.com/hakimel/Ladda/compare/0.3.0...0.4.0 254 | [0.3.0]: https://github.com/hakimel/Ladda/compare/0.2.0...0.3.0 255 | [0.2.0]: https://github.com/hakimel/Ladda/compare/0.1.0...0.2.0 256 | [0.1.0]: https://github.com/hakimel/Ladda/tree/0.1.0 257 | 258 | [#109]: https://github.com/hakimel/Ladda/issues/109 259 | [#81]: https://github.com/hakimel/Ladda/pull/81 260 | [#80]: https://github.com/hakimel/Ladda/issues/80 261 | [#68]: https://github.com/hakimel/Ladda/issues/68 262 | [#66]: https://github.com/hakimel/Ladda/pull/66 263 | [#65]: https://github.com/hakimel/Ladda/issues/65 264 | [#62]: https://github.com/hakimel/Ladda/pull/62 265 | [#58]: https://github.com/hakimel/Ladda/pull/58 266 | [#55]: https://github.com/hakimel/Ladda/pull/55 267 | [#52]: https://github.com/hakimel/Ladda/pull/52 268 | [#50]: https://github.com/hakimel/Ladda/pull/50 269 | [#49]: https://github.com/hakimel/Ladda/pull/49 270 | [#48]: https://github.com/hakimel/Ladda/pull/48 271 | [#47]: https://github.com/hakimel/Ladda/pull/47 272 | [#44]: https://github.com/hakimel/Ladda/pull/44 273 | [#43]: https://github.com/hakimel/Ladda/pull/43 274 | [#37]: https://github.com/hakimel/Ladda/pull/37 275 | [#36]: https://github.com/hakimel/Ladda/pull/36 276 | [#33]: https://github.com/hakimel/Ladda/pull/33 277 | [#20]: https://github.com/hakimel/Ladda/issues/20 278 | [#15]: https://github.com/hakimel/Ladda/issues/15 279 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Clone the repository and run `npm install` to install development dependencies and compile the project. 4 | Then run `npm start` to watch files for changes and start a static file server for viewing the test site. 5 | Open http://localhost:8000/ in your browser to view the site. 6 | -------------------------------------------------------------------------------- /Gruntfile.cjs: -------------------------------------------------------------------------------- 1 | const sass = require('sass'); 2 | 3 | module.exports = function (grunt) { 4 | 'use strict'; 5 | 6 | // Project configuration 7 | grunt.initConfig({ 8 | sass: { 9 | options: { 10 | implementation: sass, 11 | outputStyle: 'compressed', 12 | }, 13 | dist: { 14 | files: { 15 | 'dist/ladda.min.css': 'css/ladda-themed.scss', 16 | 'dist/ladda-themeless.min.css': 'css/ladda.scss' 17 | } 18 | } 19 | }, 20 | 21 | jshint: { 22 | options: { 23 | // enforcing 24 | esversion: 6, 25 | curly: true, 26 | eqeqeq: true, 27 | freeze: true, 28 | futurehostile: true, 29 | globals: { 30 | module: false, 31 | console: false, 32 | define: false 33 | }, 34 | latedef: "nofunc", 35 | maxparams: 3, 36 | noarg: true, 37 | nocomma: true, 38 | nonbsp: true, 39 | nonew: true, 40 | undef: true, 41 | unused: true, 42 | // environments 43 | browser: true, 44 | node: true, 45 | }, 46 | files: [ 'Gruntfile.cjs', 'js/ladda.js' ] 47 | }, 48 | 49 | connect: { 50 | server: { 51 | options: { 52 | port: 8000, 53 | base: 'site', 54 | } 55 | } 56 | }, 57 | 58 | copy: { 59 | css: { 60 | files: [ 61 | { src: ['dist/ladda*.min.css'], dest: 'site/' } 62 | ] 63 | } 64 | }, 65 | 66 | watch: { 67 | main: { 68 | files: [ 'Gruntfile.js', 'js/ladda.js' ], 69 | tasks: 'js', 70 | options: { 71 | livereload: true, 72 | }, 73 | }, 74 | theme: { 75 | files: [ 'css/*.scss' ], 76 | tasks: 'css', 77 | options: { 78 | livereload: true, 79 | }, 80 | } 81 | } 82 | 83 | }); 84 | 85 | // Dependencies 86 | grunt.loadNpmTasks('grunt-contrib-jshint'); 87 | grunt.loadNpmTasks('grunt-contrib-watch'); 88 | grunt.loadNpmTasks('grunt-sass'); 89 | grunt.loadNpmTasks('grunt-contrib-connect'); 90 | grunt.loadNpmTasks('grunt-contrib-copy'); 91 | 92 | // Default task 93 | grunt.registerTask('default', ['jshint', 'css']); 94 | 95 | // Theme task 96 | grunt.registerTask('css', ['sass', 'copy']); 97 | 98 | // Serve presentation locally 99 | grunt.registerTask('serve', ['connect', 'watch']); 100 | }; 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017 Hakim El Hattab, http://hakim.se 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ladda 2 | 3 | Buttons with built-in loading indicators, effectively bridging the gap between action and feedback. 4 | 5 | [Check out the demo page](https://lab.hakim.se/ladda/). 6 | 7 | ## Installation 8 | 9 | `npm install ladda` 10 | 11 | ### Module bundling 12 | 13 | Ladda 2.x is distributed as a standard ES6 module. Since not all browsers/environments support native 14 | ES6 modules, it is recommended to use a bundler such as Rollup, 15 | Parcel, or Webpack to create 16 | a production-ready code bundle. 17 | 18 | ## Usage 19 | 20 | ### CSS 21 | 22 | You will need to include ONE of the two style sheets in the **/dist** directory. 23 | If you want the button styles used on the demo page, use the **ladda.min.css** file. 24 | If you want to have the functional buttons without the visual style (colors, padding, etc.), 25 | use the **ladda-themeless.min.css** file. 26 | 27 | ### HTML 28 | 29 | Below is an example of a button using the `expand-right` animation style. 30 | 31 | ```html 32 | 33 | ``` 34 | 35 | When the JS code runs to bind Ladda to the button, the `ladda-button` class 36 | will be automatically added if it doesn't already exist. Additionally, a span 37 | with class `ladda-label` will automatically wrap the button text, resulting 38 | in the following DOM structure: 39 | 40 | ```html 41 | 44 | ``` 45 | 46 | Buttons accept the following attributes: 47 | - **data-style**: one of the button styles *[required]* 48 | - expand-left, expand-right, expand-up, expand-down 49 | - contract, contract-overlay 50 | - zoom-in, zoom-out 51 | - slide-left, slide-right, slide-up, slide-down 52 | - **data-color**: green/red/blue/purple/mint 53 | - **data-size**: xs/s/l/xl, defaults to medium 54 | - **data-spinner-size**: pixel dimensions of spinner, defaults to dynamic size based on the button height 55 | - **data-spinner-color**: a hex code or any named CSS color, defaults to `#fff` 56 | - **data-spinner-lines**: the number of lines for the spinner, defaults to `12` 57 | 58 | ### JavaScript 59 | 60 | Start by importing the Ladda module: 61 | 62 | ```javascript 63 | import * as Ladda from 'ladda'; 64 | ``` 65 | 66 | The following approach is recommended for JavaScript control over your buttons: 67 | 68 | ```javascript 69 | // Create a new instance of ladda for the specified button 70 | var l = Ladda.create(document.querySelector('.my-button')); 71 | 72 | // Start loading 73 | l.start(); 74 | 75 | // Will display a progress bar for 50% of the button width 76 | l.setProgress(0.5); 77 | 78 | // Stop loading 79 | l.stop(); 80 | 81 | // Toggle between loading/not loading states 82 | l.toggle(); 83 | 84 | // Check the current state 85 | l.isLoading(); 86 | 87 | // Delete the button's ladda instance 88 | l.remove(); 89 | ``` 90 | 91 | To show the loading animation for a form that is submitted to the server 92 | (always resulting in a page reload) the `bind()` method can be used: 93 | 94 | ```javascript 95 | // Automatically trigger the loading animation on click 96 | Ladda.bind('button[type=submit]'); 97 | 98 | // Same as the above but automatically stops after two seconds 99 | Ladda.bind('button[type=submit]', {timeout: 2000}); 100 | ``` 101 | 102 | Note: when using the `bind()` method on buttons that are inside a form, 103 | loading indicators will not be shown until the form is valid. 104 | 105 | All loading animations on the page can be stopped by using: 106 | 107 | ```javascript 108 | Ladda.stopAll(); 109 | ``` 110 | 111 | ## Browser support 112 | 113 | Ladda has been tested in Firefox, Microsoft Edge, Chrome, and Internet Explorer 11. 114 | It also Should Work™ in Safari and Internet Explorer 10. 115 | 116 | ## Changelog 117 | 118 | 119 | 120 | ## License 121 | 122 | MIT 123 | -------------------------------------------------------------------------------- /css/ladda-themed.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Ladda including the default theme. 3 | */ 4 | 5 | @import "ladda"; 6 | 7 | /************************************* 8 | * CONFIG 9 | */ 10 | 11 | $green: #2aca76; 12 | $blue: #53b5e6; 13 | $red: #ea8557; 14 | $purple: #9973C2; 15 | $mint: #16a085; 16 | 17 | 18 | /************************************* 19 | * BUTTON THEME 20 | */ 21 | 22 | .ladda-button { 23 | background: #666; 24 | border: 0; 25 | padding: 14px 18px; 26 | font-size: 18px; 27 | cursor: pointer; 28 | 29 | color: #fff; 30 | border-radius: 2px; 31 | border: 1px solid transparent; 32 | 33 | -webkit-appearance: none; 34 | -webkit-font-smoothing: antialiased; 35 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 36 | 37 | &:hover { 38 | border-color: rgba( 0, 0, 0, 0.07 ); 39 | background-color: #888; 40 | } 41 | 42 | @include buttonColor( 'green', $green ); 43 | @include buttonColor( 'blue', $blue ); 44 | @include buttonColor( 'red', $red ); 45 | @include buttonColor( 'purple', $purple ); 46 | @include buttonColor( 'mint', $mint ); 47 | 48 | &[disabled], 49 | &[data-loading] { 50 | border-color: rgba( 0, 0, 0, 0.07 ); 51 | 52 | &, &:hover { 53 | cursor: default; 54 | background-color: #999; 55 | } 56 | } 57 | 58 | &[data-size=xs] { 59 | padding: 4px 8px; 60 | 61 | .ladda-label { 62 | font-size: 0.7em; 63 | } 64 | } 65 | 66 | &[data-size=s] { 67 | padding: 6px 10px; 68 | 69 | .ladda-label { 70 | font-size: 0.9em; 71 | } 72 | } 73 | 74 | &[data-size=l] .ladda-label { 75 | font-size: 1.2em; 76 | } 77 | 78 | &[data-size=xl] .ladda-label { 79 | font-size: 1.5em; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /css/ladda.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Ladda 3 | * http://lab.hakim.se/ladda 4 | * MIT licensed 5 | * 6 | * Copyright (C) 2018 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | /************************************* 11 | * CONFIG 12 | */ 13 | 14 | @use "sass:math"; 15 | 16 | $spinnerSize: 32px !default; 17 | 18 | 19 | /************************************* 20 | * MIXINS 21 | */ 22 | 23 | @mixin buttonColor( $name, $color ) { 24 | &[data-color=#{$name}] { 25 | background: $color; 26 | 27 | &:hover { 28 | background-color: lighten( $color, 5% ); 29 | } 30 | } 31 | } 32 | 33 | 34 | /************************************* 35 | * Opacity animation for spin.js 36 | */ 37 | 38 | @keyframes ladda-spinner-line-fade { 39 | 0%, 100% { 40 | opacity: 0.22; /* minimum opacity */ 41 | } 42 | 1% { 43 | opacity: 1; 44 | } 45 | } 46 | 47 | 48 | /************************************* 49 | * BUTTON BASE 50 | */ 51 | 52 | .ladda-button { 53 | position: relative; 54 | } 55 | 56 | 57 | /* Spinner animation */ 58 | .ladda-button .ladda-spinner { 59 | position: absolute; 60 | z-index: 2; 61 | display: inline-block; 62 | width: $spinnerSize; 63 | top: 50%; 64 | margin-top: 0; 65 | opacity: 0; 66 | pointer-events: none; 67 | } 68 | 69 | /* Button label */ 70 | .ladda-button .ladda-label { 71 | position: relative; 72 | z-index: 3; 73 | } 74 | 75 | /* Progress bar */ 76 | .ladda-button .ladda-progress { 77 | position: absolute; 78 | width: 0; 79 | height: 100%; 80 | left: 0; 81 | top: 0; 82 | background: rgba( 0, 0, 0, 0.2 ); 83 | display: none; 84 | transition: 0.1s linear all; 85 | } 86 | 87 | .ladda-button[data-loading] .ladda-progress { 88 | display: block; 89 | } 90 | 91 | 92 | /************************************* 93 | * EASING 94 | */ 95 | 96 | .ladda-button, 97 | .ladda-button .ladda-spinner, 98 | .ladda-button .ladda-label { 99 | transition: 0.3s cubic-bezier(0.175, 0.885, 0.320, 1.275) all; 100 | } 101 | 102 | .ladda-button[data-style=zoom-in], 103 | .ladda-button[data-style=zoom-in] .ladda-spinner, 104 | .ladda-button[data-style=zoom-in] .ladda-label, 105 | .ladda-button[data-style=zoom-out], 106 | .ladda-button[data-style=zoom-out] .ladda-spinner, 107 | .ladda-button[data-style=zoom-out] .ladda-label { 108 | transition: 0.3s ease all; 109 | } 110 | 111 | 112 | /************************************* 113 | * EXPAND RIGHT 114 | */ 115 | 116 | .ladda-button[data-style=expand-right] { 117 | .ladda-spinner { 118 | right: math.div($spinnerSize, -2) + 10; 119 | } 120 | 121 | &[data-size="s"] .ladda-spinner, 122 | &[data-size="xs"] .ladda-spinner { 123 | right: math.div($spinnerSize, -2) + 4; 124 | } 125 | 126 | &[data-loading] { 127 | padding-right: 56px; 128 | 129 | .ladda-spinner { 130 | opacity: 1; 131 | } 132 | 133 | &[data-size="s"], 134 | &[data-size="xs"] { 135 | padding-right: 40px; 136 | } 137 | } 138 | } 139 | 140 | 141 | /************************************* 142 | * EXPAND LEFT 143 | */ 144 | 145 | .ladda-button[data-style=expand-left] { 146 | .ladda-spinner { 147 | left: $spinnerSize * 0.5 + 10; 148 | } 149 | 150 | &[data-size="s"] .ladda-spinner, 151 | &[data-size="xs"] .ladda-spinner { 152 | left: 4px; 153 | } 154 | 155 | &[data-loading] { 156 | padding-left: 56px; 157 | 158 | .ladda-spinner { 159 | opacity: 1; 160 | } 161 | 162 | &[data-size="s"], 163 | &[data-size="xs"] { 164 | padding-left: 40px; 165 | } 166 | } 167 | } 168 | 169 | 170 | /************************************* 171 | * EXPAND UP 172 | */ 173 | 174 | .ladda-button[data-style=expand-up] { 175 | overflow: hidden; 176 | 177 | .ladda-spinner { 178 | top: -$spinnerSize; 179 | left: 50%; 180 | margin-left: 0; 181 | } 182 | 183 | &[data-loading] { 184 | padding-top: 54px; 185 | 186 | .ladda-spinner { 187 | opacity: 1; 188 | top: ($spinnerSize * 0.5) + 10; 189 | margin-top: 0; 190 | } 191 | 192 | &[data-size="s"], 193 | &[data-size="xs"] { 194 | padding-top: 32px; 195 | 196 | .ladda-spinner { 197 | top: 4px; 198 | } 199 | } 200 | } 201 | } 202 | 203 | 204 | /************************************* 205 | * EXPAND DOWN 206 | */ 207 | 208 | .ladda-button[data-style=expand-down] { 209 | overflow: hidden; 210 | 211 | .ladda-spinner { 212 | top: 62px; 213 | left: 50%; 214 | margin-left: 0; 215 | } 216 | 217 | &[data-size="s"] .ladda-spinner, 218 | &[data-size="xs"] .ladda-spinner { 219 | top: 40px; 220 | } 221 | 222 | &[data-loading] { 223 | padding-bottom: 54px; 224 | 225 | .ladda-spinner { 226 | opacity: 1; 227 | } 228 | 229 | &[data-size="s"], 230 | &[data-size="xs"] { 231 | padding-bottom: 32px; 232 | } 233 | } 234 | } 235 | 236 | 237 | /************************************* 238 | * SLIDE LEFT 239 | */ 240 | .ladda-button[data-style=slide-left] { 241 | overflow: hidden; 242 | 243 | .ladda-label { 244 | position: relative; 245 | } 246 | 247 | .ladda-spinner { 248 | left: 100%; 249 | margin-left: 0; 250 | } 251 | 252 | &[data-loading] { 253 | .ladda-label { 254 | opacity: 0; 255 | left: -100%; 256 | } 257 | 258 | .ladda-spinner { 259 | opacity: 1; 260 | left: 50%; 261 | } 262 | } 263 | } 264 | 265 | 266 | /************************************* 267 | * SLIDE RIGHT 268 | */ 269 | .ladda-button[data-style=slide-right] { 270 | overflow: hidden; 271 | 272 | .ladda-label { 273 | position: relative; 274 | } 275 | 276 | .ladda-spinner { 277 | right: 100%; 278 | margin-left: 0; 279 | left: $spinnerSize * 0.5; 280 | 281 | [dir="rtl"] & { 282 | right: auto; 283 | } 284 | } 285 | 286 | &[data-loading] { 287 | .ladda-label { 288 | opacity: 0; 289 | left: 100%; 290 | } 291 | 292 | .ladda-spinner { 293 | opacity: 1; 294 | left: 50%; 295 | } 296 | } 297 | } 298 | 299 | 300 | /************************************* 301 | * SLIDE UP 302 | */ 303 | .ladda-button[data-style=slide-up] { 304 | overflow: hidden; 305 | 306 | .ladda-label { 307 | position: relative; 308 | } 309 | 310 | .ladda-spinner { 311 | left: 50%; 312 | margin-left: 0; 313 | margin-top: 1em; 314 | } 315 | 316 | &[data-loading] { 317 | .ladda-label { 318 | opacity: 0; 319 | top: -1em; 320 | } 321 | 322 | .ladda-spinner { 323 | opacity: 1; 324 | margin-top: 0; 325 | } 326 | } 327 | } 328 | 329 | 330 | /************************************* 331 | * SLIDE DOWN 332 | */ 333 | .ladda-button[data-style=slide-down] { 334 | overflow: hidden; 335 | 336 | .ladda-label { 337 | position: relative; 338 | } 339 | 340 | .ladda-spinner { 341 | left: 50%; 342 | margin-left: 0; 343 | margin-top: -2em; 344 | } 345 | 346 | &[data-loading] { 347 | .ladda-label { 348 | opacity: 0; 349 | top: 1em; 350 | } 351 | 352 | .ladda-spinner { 353 | opacity: 1; 354 | margin-top: 0; 355 | } 356 | } 357 | } 358 | 359 | 360 | /************************************* 361 | * ZOOM-OUT 362 | */ 363 | 364 | .ladda-button[data-style=zoom-out] { 365 | overflow: hidden; 366 | 367 | .ladda-label { 368 | position: relative; 369 | display: inline-block; 370 | } 371 | 372 | .ladda-spinner { 373 | left: 50%; 374 | margin-left: $spinnerSize; 375 | transform: scale(2.5); 376 | } 377 | 378 | &[data-loading] { 379 | .ladda-label { 380 | opacity: 0; 381 | transform: scale(0.5); 382 | } 383 | 384 | .ladda-spinner { 385 | opacity: 1; 386 | margin-left: 0; 387 | transform: none; 388 | } 389 | } 390 | } 391 | 392 | 393 | /************************************* 394 | * ZOOM-IN 395 | */ 396 | 397 | .ladda-button[data-style=zoom-in] { 398 | overflow: hidden; 399 | 400 | .ladda-label { 401 | position: relative; 402 | display: inline-block; 403 | } 404 | 405 | .ladda-spinner { 406 | left: 50%; 407 | margin-left: math.div($spinnerSize, -2); 408 | transform: scale(0.2); 409 | } 410 | 411 | &[data-loading] { 412 | .ladda-label { 413 | opacity: 0; 414 | transform: scale(2.2); 415 | } 416 | 417 | .ladda-spinner { 418 | opacity: 1; 419 | margin-left: 0; 420 | transform: none; 421 | } 422 | } 423 | } 424 | 425 | 426 | /************************************* 427 | * CONTRACT 428 | */ 429 | 430 | .ladda-button[data-style=contract] { 431 | overflow: hidden; 432 | width: 100px; 433 | 434 | .ladda-spinner { 435 | left: 50%; 436 | margin-left: 0; 437 | } 438 | 439 | &[data-loading] { 440 | border-radius: 50%; 441 | width: 52px; 442 | 443 | .ladda-label { 444 | opacity: 0; 445 | } 446 | 447 | .ladda-spinner { 448 | opacity: 1; 449 | } 450 | } 451 | } 452 | 453 | 454 | /************************************* 455 | * OVERLAY 456 | */ 457 | 458 | .ladda-button[data-style=contract-overlay] { 459 | overflow: hidden; 460 | width: 100px; 461 | box-shadow: 0px 0px 0px 2000px rgba(0,0,0,0); 462 | 463 | .ladda-spinner { 464 | left: 50%; 465 | margin-left: 0; 466 | } 467 | 468 | &[data-loading] { 469 | border-radius: 50%; 470 | width: 52px; 471 | box-shadow: 0px 0px 0px 2000px rgba(0,0,0,0.8); 472 | 473 | .ladda-label { 474 | opacity: 0; 475 | } 476 | 477 | .ladda-spinner { 478 | opacity: 1; 479 | } 480 | } 481 | } 482 | 483 | 484 | [dir="rtl"] .ladda-spinner > div { 485 | left: 25% !important; 486 | } 487 | -------------------------------------------------------------------------------- /js/ladda.d.ts: -------------------------------------------------------------------------------- 1 | export interface LaddaButton { 2 | start(): LaddaButton, 3 | startAfter(delay: number): LaddaButton, 4 | stop(): LaddaButton, 5 | toggle(): LaddaButton, 6 | setProgress(progress: number): void, 7 | isLoading(): boolean, 8 | remove(): void, 9 | } 10 | 11 | export interface BindOptions { 12 | /** 13 | * Number of milliseconds to wait before automatically cancelling the animation. 14 | */ 15 | timeout?: number, 16 | 17 | /** 18 | * A function to be called with the Ladda instance when a target button is clicked. 19 | */ 20 | callback?: (instance: LaddaButton) => void, 21 | } 22 | 23 | /** 24 | * Creates a new instance of Ladda which wraps the target button element. 25 | */ 26 | export function create(button: HTMLButtonElement): LaddaButton; 27 | 28 | /** 29 | * Binds the target buttons to automatically enter the loading state when clicked. 30 | * @param target Either an HTML element or a CSS selector. 31 | */ 32 | export function bind(target: HTMLElement | string, options?: BindOptions): void; 33 | 34 | /** 35 | * Stops all current loading animations. 36 | */ 37 | export function stopAll(): void; 38 | -------------------------------------------------------------------------------- /js/ladda.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Ladda 3 | * http://lab.hakim.se/ladda 4 | * MIT licensed 5 | * 6 | * Copyright (C) 2018 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | import {Spinner} from 'spin.js'; 10 | 11 | // All currently instantiated instances of Ladda 12 | var ALL_INSTANCES = []; 13 | 14 | /** 15 | * Creates a new instance of Ladda which wraps the 16 | * target button element. 17 | * 18 | * @return An API object that can be used to control 19 | * the loading animation state. 20 | */ 21 | export function create(button) { 22 | if (typeof button === 'undefined') { 23 | console.warn("Ladda button target must be defined."); 24 | return; 25 | } 26 | 27 | // The button must have the class "ladda-button" 28 | if (!button.classList.contains('ladda-button')) { 29 | button.classList.add('ladda-button'); 30 | } 31 | 32 | // Style is required, default to "expand-right" 33 | if (!button.hasAttribute('data-style')) { 34 | button.setAttribute('data-style', 'expand-right'); 35 | } 36 | 37 | // The text contents must be wrapped in a ladda-label 38 | // element, create one if it doesn't already exist 39 | if (!button.querySelector('.ladda-label')) { 40 | var laddaLabel = document.createElement('span'); 41 | laddaLabel.className = 'ladda-label'; 42 | wrapContent(button, laddaLabel); 43 | } 44 | 45 | // The spinner component 46 | var spinnerWrapper = button.querySelector('.ladda-spinner'); 47 | 48 | // Wrapper element for the spinner 49 | if (!spinnerWrapper) { 50 | spinnerWrapper = document.createElement('span'); 51 | spinnerWrapper.className = 'ladda-spinner'; 52 | } 53 | 54 | button.appendChild(spinnerWrapper); 55 | 56 | // Timer used to delay starting/stopping 57 | var timer; 58 | var spinner; 59 | 60 | var instance = { 61 | /** 62 | * Enter the loading state. 63 | */ 64 | start: function() { 65 | // Create the spinner if it doesn't already exist 66 | if (!spinner) { 67 | spinner = createSpinner(button); 68 | } 69 | 70 | button.disabled = true; 71 | button.setAttribute('data-loading', ''); 72 | 73 | clearTimeout(timer); 74 | spinner.spin(spinnerWrapper); 75 | 76 | this.setProgress(0); 77 | 78 | return this; // chain 79 | }, 80 | 81 | /** 82 | * Enter the loading state, after a delay. 83 | */ 84 | startAfter: function(delay) { 85 | clearTimeout(timer); 86 | timer = setTimeout(function() { instance.start(); }, delay); 87 | 88 | return this; // chain 89 | }, 90 | 91 | /** 92 | * Exit the loading state. 93 | */ 94 | stop: function() { 95 | if (instance.isLoading()) { 96 | button.disabled = false; 97 | button.removeAttribute('data-loading'); 98 | } 99 | 100 | // Kill the animation after a delay to make sure it 101 | // runs for the duration of the button transition 102 | clearTimeout(timer); 103 | 104 | if (spinner) { 105 | timer = setTimeout(function() { spinner.stop(); }, 1000); 106 | } 107 | 108 | return this; // chain 109 | }, 110 | 111 | /** 112 | * Toggle the loading state on/off. 113 | */ 114 | toggle: function() { 115 | return this.isLoading() ? this.stop() : this.start(); 116 | }, 117 | 118 | /** 119 | * Sets the width of the visual progress bar inside of 120 | * this Ladda button 121 | * 122 | * @param {number} progress in the range of 0-1 123 | */ 124 | setProgress: function(progress) { 125 | // Cap it 126 | progress = Math.max(Math.min(progress, 1), 0); 127 | 128 | var progressElement = button.querySelector('.ladda-progress'); 129 | 130 | // Remove the progress bar if we're at 0 progress 131 | if (progress === 0 && progressElement && progressElement.parentNode) { 132 | progressElement.parentNode.removeChild(progressElement); 133 | } else { 134 | if (!progressElement) { 135 | progressElement = document.createElement('div'); 136 | progressElement.className = 'ladda-progress'; 137 | button.appendChild(progressElement); 138 | } 139 | 140 | progressElement.style.width = ((progress || 0) * button.offsetWidth) + 'px'; 141 | } 142 | }, 143 | 144 | isLoading: function() { 145 | return button.hasAttribute('data-loading'); 146 | }, 147 | 148 | remove: function() { 149 | clearTimeout(timer); 150 | button.disabled = false; 151 | button.removeAttribute('data-loading'); 152 | 153 | if (spinner) { 154 | spinner.stop(); 155 | spinner = null; 156 | } 157 | 158 | ALL_INSTANCES.splice(ALL_INSTANCES.indexOf(instance), 1); 159 | } 160 | }; 161 | 162 | ALL_INSTANCES.push(instance); 163 | 164 | return instance; 165 | } 166 | 167 | /** 168 | * Binds the target buttons to automatically enter the 169 | * loading state when clicked. 170 | * 171 | * @param target Either an HTML element or a CSS selector. 172 | * @param options 173 | * - timeout Number of milliseconds to wait before 174 | * automatically cancelling the animation. 175 | * - callback A function to be called with the Ladda 176 | * instance when a target button is clicked. 177 | */ 178 | export function bind(target, options) { 179 | var targets; 180 | 181 | if (typeof target === 'string') { 182 | targets = document.querySelectorAll(target); 183 | } else if (typeof target === 'object') { 184 | targets = [target]; 185 | } else { 186 | throw new Error('target must be string or object'); 187 | } 188 | 189 | options = options || {}; 190 | 191 | for (var i = 0; i < targets.length; i++) { 192 | bindElement(targets[i], options); 193 | } 194 | } 195 | 196 | /** 197 | * Stops ALL current loading animations. 198 | */ 199 | export function stopAll() { 200 | for (var i = 0, len = ALL_INSTANCES.length; i < len; i++) { 201 | ALL_INSTANCES[i].stop(); 202 | } 203 | } 204 | 205 | /** 206 | * Get the first ancestor node from an element, having a 207 | * certain type. 208 | * 209 | * @param elem An HTML element 210 | * @param type an HTML tag type (uppercased) 211 | * 212 | * @return An HTML element 213 | */ 214 | function getAncestorOfTagType(elem, type) { 215 | while (elem.parentNode && elem.tagName !== type) { 216 | elem = elem.parentNode; 217 | } 218 | 219 | return (type === elem.tagName) ? elem : undefined; 220 | } 221 | 222 | function createSpinner(button) { 223 | var height = button.offsetHeight, 224 | spinnerColor, 225 | spinnerLines; 226 | 227 | if (height === 0) { 228 | // We may have an element that is not visible so 229 | // we attempt to get the height in a different way 230 | height = parseFloat(window.getComputedStyle(button).height); 231 | } 232 | 233 | // If the button is tall we can afford some padding 234 | if (height > 32) { 235 | height *= 0.8; 236 | } 237 | 238 | // Prefer an explicit height if one is defined 239 | if (button.hasAttribute('data-spinner-size')) { 240 | height = parseInt(button.getAttribute('data-spinner-size'), 10); 241 | } 242 | 243 | // Allow buttons to specify the color of the spinner element 244 | if (button.hasAttribute('data-spinner-color')) { 245 | spinnerColor = button.getAttribute('data-spinner-color'); 246 | } 247 | 248 | // Allow buttons to specify the number of lines of the spinner 249 | if (button.hasAttribute('data-spinner-lines')) { 250 | spinnerLines = parseInt(button.getAttribute('data-spinner-lines'), 10); 251 | } 252 | 253 | var radius = height * 0.2, 254 | length = radius * 0.6, 255 | width = radius < 7 ? 2 : 3; 256 | 257 | return new Spinner({ 258 | color: spinnerColor || '#fff', 259 | lines: spinnerLines || 12, 260 | radius: radius, 261 | length: length, 262 | width: width, 263 | animation: 'ladda-spinner-line-fade', 264 | zIndex: 'auto', 265 | top: 'auto', 266 | left: 'auto', 267 | className: '' 268 | }); 269 | } 270 | 271 | function wrapContent(node, wrapper) { 272 | var r = document.createRange(); 273 | r.selectNodeContents(node); 274 | r.surroundContents(wrapper); 275 | node.appendChild(wrapper); 276 | } 277 | 278 | function bindElement(element, options) { 279 | if (typeof element.addEventListener !== 'function') { 280 | return; 281 | } 282 | 283 | var instance = create(element); 284 | var timeout = -1; 285 | 286 | element.addEventListener('click', function() { 287 | // If the button belongs to a form, make sure all the 288 | // fields in that form are filled out 289 | var valid = true; 290 | var form = getAncestorOfTagType(element, 'FORM'); 291 | 292 | if (typeof form !== 'undefined' && !form.hasAttribute('novalidate')) { 293 | // Modern form validation 294 | if (typeof form.checkValidity === 'function') { 295 | valid = form.checkValidity(); 296 | } 297 | } 298 | 299 | if (valid) { 300 | // This is asynchronous to avoid an issue where disabling 301 | // the button prevents forms from submitting 302 | instance.startAfter(1); 303 | 304 | // Set a loading timeout if one is specified 305 | if (typeof options.timeout === 'number') { 306 | clearTimeout(timeout); 307 | timeout = setTimeout(instance.stop, options.timeout); 308 | } 309 | 310 | // Invoke callbacks 311 | if (typeof options.callback === 'function') { 312 | options.callback.apply(null, [instance]); 313 | } 314 | } 315 | 316 | }, false); 317 | } 318 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ladda", 3 | "version": "2.0.3", 4 | "description": "Buttons with built-in loading indicators", 5 | "homepage": "https://lab.hakim.se/ladda/", 6 | "files": [ 7 | "css/*.scss", 8 | "dist/*.css", 9 | "js/ladda.d.ts", 10 | "js/ladda.js" 11 | ], 12 | "type": "module", 13 | "main": "./js/ladda.js", 14 | "types": "./js/ladda.d.ts", 15 | "scripts": { 16 | "test": "grunt jshint --gruntfile Gruntfile.cjs", 17 | "prepare": "grunt --gruntfile Gruntfile.cjs && rollup -c", 18 | "start": "grunt serve --gruntfile Gruntfile.cjs" 19 | }, 20 | "author": "Hakim El Hattab https://hakim.se", 21 | "contributors": [ 22 | "Theodore Brown https://theodorejb.me" 23 | ], 24 | "repository": { 25 | "type": "git", 26 | "url": "git://github.com/hakimel/Ladda.git" 27 | }, 28 | "devDependencies": { 29 | "grunt": "^1.4.1", 30 | "grunt-contrib-connect": "^3.0.0", 31 | "grunt-contrib-copy": "^1.0.0", 32 | "grunt-contrib-jshint": "^3.1.1", 33 | "grunt-contrib-watch": "^1.1.0", 34 | "grunt-sass": "^3.1.0", 35 | "rollup": "^2.60.2", 36 | "rollup-plugin-node-resolve": "^5.2.0", 37 | "sass": "^1.44.0" 38 | }, 39 | "license": "MIT", 40 | "dependencies": { 41 | "spin.js": "^4.1.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | 3 | export default [ 4 | { 5 | input: 'site/index.js', 6 | output: { 7 | file: 'site/dist/index-bundle.js', 8 | format: 'iife' 9 | }, 10 | plugins: [resolve()] 11 | }, 12 | { 13 | input: 'site/form.js', 14 | output: { 15 | file: 'site/dist/form-bundle.js', 16 | format: 'iife' 17 | }, 18 | plugins: [resolve()] 19 | }, 20 | ]; 21 | -------------------------------------------------------------------------------- /site/bootstrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda: Bootstrap compatibility test 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Ladda Bootstrap 5 test

17 |
18 | 19 |
20 |

expand-left

21 | 22 |
23 | 24 |
25 |

expand-right

26 | 27 |
28 | 29 |
30 |

expand-up

31 | 32 |
33 | 34 |
35 |

expand-down

36 | 37 |
38 | 39 | 40 |
41 |

zoom-in

42 | 43 |
44 | 45 |
46 |

zoom-out

47 | 48 |
49 | 50 | 51 |
52 |

slide-left

53 | 54 |
55 | 56 |
57 |

slide-right

58 | 59 |
60 | 61 |
62 |

slide-up

63 | 64 |
65 | 66 |
67 |

slide-down

68 | 69 |
70 | 71 |

Built-in progress bar

72 | 73 |
74 |

expand-right

75 | 76 |
77 | 78 |
79 |

contract

80 | 81 |
82 | 83 |

Sizes

84 | 85 |
86 |

Small

87 | 88 |
89 | 90 |
91 |

Large

92 | 93 |
94 | 95 |

Buttons in forms containing required inputs

96 | 97 |
98 |
99 |
100 | 101 |
102 |
103 | 104 |
105 |
106 |
107 |
108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /site/bootstrap3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda: Bootstrap compatibility test 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Ladda Bootstrap 3 test

17 |
18 | 19 |
20 |

expand-left

21 | 22 |
23 | 24 |
25 |

expand-right

26 | 27 |
28 | 29 |
30 |

expand-up

31 | 32 |
33 | 34 |
35 |

expand-down

36 | 37 |
38 | 39 | 40 |
41 |

zoom-in

42 | 43 |
44 | 45 |
46 |

zoom-out

47 | 48 |
49 | 50 | 51 |
52 |

slide-left

53 | 54 |
55 | 56 |
57 |

slide-right

58 | 59 |
60 | 61 |
62 |

slide-up

63 | 64 |
65 | 66 |
67 |

slide-down

68 | 69 |
70 | 71 |

Built-in progress bar

72 | 73 |
74 |

expand-right

75 | 76 |
77 | 78 |
79 |

contract

80 | 81 |
82 | 83 |

Sizes

84 | 85 |
86 |

Small

87 | 88 |
89 | 90 |
91 |

Large

92 | 93 |
94 | 95 |

Buttons in forms containing required inputs

96 | 97 |
98 |
99 |
100 | 101 |
102 |
103 | 105 |
106 |
107 |
108 |
109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /site/bootstrap4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda: Bootstrap compatibility test 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Ladda Bootstrap 4 test

17 |
18 | 19 |
20 |

expand-left

21 | 22 |
23 | 24 |
25 |

expand-right

26 | 27 |
28 | 29 |
30 |

expand-up

31 | 32 |
33 | 34 |
35 |

expand-down

36 | 37 |
38 | 39 | 40 |
41 |

zoom-in

42 | 43 |
44 | 45 |
46 |

zoom-out

47 | 48 |
49 | 50 | 51 |
52 |

slide-left

53 | 54 |
55 | 56 |
57 |

slide-right

58 | 59 |
60 | 61 |
62 |

slide-up

63 | 64 |
65 | 66 |
67 |

slide-down

68 | 69 |
70 | 71 |

Built-in progress bar

72 | 73 |
74 |

expand-right

75 | 76 |
77 | 78 |
79 |

contract

80 | 81 |
82 | 83 |

Sizes

84 | 85 |
86 |

Small

87 | 88 |
89 | 90 |
91 |

Large

92 | 93 |
94 | 95 |

Buttons in forms containing required inputs

96 | 97 |
98 |
99 |
100 | 101 |
102 |
103 | 105 |
106 |
107 |
108 |
109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /site/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 | font-weight: bold; 31 | } 32 | 33 | .examples h3 { 34 | font-size: 17px; 35 | } 36 | 37 | .examples .outro { 38 | display: block; 39 | text-align: right; 40 | margin-top: 3em; 41 | } 42 | .examples section { 43 | display: inline-block; 44 | width: 24%; 45 | min-width: 160px; 46 | margin-bottom: 2em; 47 | text-align: center; 48 | vertical-align: top; 49 | } 50 | .examples section h3 { 51 | color: #bbb; 52 | font-weight: normal; 53 | } 54 | 55 | 56 | .sharing { 57 | float: left; 58 | } 59 | 60 | .fork { 61 | position: absolute; 62 | top: 0; 63 | right: 0; 64 | border: none; 65 | } 66 | -------------------------------------------------------------------------------- /site/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda: Form test 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Ladda Form Validation

14 |

15 | This page can be used to test that Ladda does NOT start spinning when submitting an invalid form. 16 |

17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /site/form.js: -------------------------------------------------------------------------------- 1 | import * as Ladda from '../js/ladda.js'; 2 | 3 | Ladda.bind('button[type=submit]'); 4 | -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Ladda

16 |

17 | A UI concept which merges loading indicators into the action that invoked them. Primarily intended for use with forms where 18 | it gives users immediate feedback upon submit rather than leaving them wondering while the browser does its thing. For a 19 | real-world example, check out any of the forms on slides.com. 20 |

21 |
22 | 23 |
24 |

expand-left

25 | 26 |
27 | 28 |
29 |

expand-right

30 | 31 |
32 | 33 |
34 |

expand-up

35 | 36 |
37 | 38 |
39 |

expand-down

40 | 41 |
42 | 43 | 44 |
45 |

contract

46 | 47 |
48 | 49 |
50 |

contract-overlay

51 | 52 |
53 | 54 |
55 |

zoom-in

56 | 57 |
58 | 59 |
60 |

zoom-out

61 | 62 |
63 | 64 | 65 |
66 |

slide-left

67 | 68 |
69 | 70 |
71 |

slide-right

72 | 73 |
74 | 75 |
76 |

slide-up

77 | 78 |
79 | 80 |
81 |

slide-down

82 | 83 |
84 | 85 |

Built-in progress bar

86 | 87 |
88 |

expand-right

89 | 90 |
91 | 92 |
93 |

contract

94 | 95 |
96 | 97 |

Sizes

98 | 99 |
100 |

Extra Small

101 | 102 |
103 | 104 |
105 |

Small

106 | 107 |
108 | 109 |
110 |

Large

111 | 112 |
113 | 114 |
115 |

Extra Large

116 | 117 |
118 | 119 | 125 |
126 | 127 | 128 | 129 | Fork me on GitHub 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /site/index.js: -------------------------------------------------------------------------------- 1 | import * as Ladda from '../js/ladda.js'; 2 | 3 | // Bind normal buttons 4 | Ladda.bind('.button-demo button', { timeout: 2000 }); 5 | 6 | // Bind progress buttons and simulate loading progress 7 | Ladda.bind('.progress-demo button', { 8 | callback: function (instance) { 9 | var progress = 0; 10 | var interval = setInterval(function () { 11 | progress = Math.min(progress + Math.random() * 0.1, 1); 12 | instance.setProgress(progress); 13 | 14 | if (progress === 1) { 15 | instance.stop(); 16 | clearInterval(interval); 17 | } 18 | }, 200); 19 | } 20 | }); 21 | 22 | // You can control loading explicitly using the JavaScript API 23 | // as outlined below: 24 | 25 | // var l = Ladda.create( document.querySelector( 'button' ) ); 26 | // l.start(); 27 | // l.stop(); 28 | // l.toggle(); 29 | // l.isLoading(); 30 | // l.setProgress( 0-1 ); 31 | -------------------------------------------------------------------------------- /site/rtl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ladda 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Ladda RTL support

15 |
16 | 17 |
18 |
19 |

expand-left

20 | 21 |
22 | 23 |
24 |

expand-right

25 | 26 |
27 | 28 |
29 |

expand-up

30 | 31 |
32 | 33 |
34 |

expand-down

35 | 36 |
37 | 38 | 39 |
40 |

contract

41 | 42 |
43 | 44 |
45 |

contract-overlay

46 | 47 |
48 | 49 |
50 |

zoom-in

51 | 52 |
53 | 54 |
55 |

zoom-out

56 | 57 |
58 | 59 | 60 |
61 |

slide-left

62 | 63 |
64 | 65 |
66 |

slide-right

67 | 68 |
69 | 70 |
71 |

slide-up

72 | 73 |
74 | 75 |
76 |

slide-down

77 | 78 |
79 | 80 |

Built-in progress bar

81 | 82 |
83 |

expand-right

84 | 85 |
86 | 87 |
88 |

contract

89 | 90 |
91 | 92 |

Sizes

93 | 94 |
95 |

Extra Small

96 | 97 |
98 | 99 |
100 |

Small

101 | 102 |
103 | 104 |
105 |

Large

106 | 107 |
108 | 109 |
110 |

Extra Large

111 | 112 |
113 |
114 |
115 | 116 | 117 | 118 | 119 | --------------------------------------------------------------------------------