├── .babelrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── UPGRADING.md ├── examples ├── App.vue ├── components │ ├── componentExample.vue │ └── pluginExample.vue ├── index.html └── index.js ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── src ├── css │ └── index.css ├── index.js ├── js │ ├── Component.vue │ ├── api.js │ ├── helpers.js │ └── trapFocusMixin.js └── loaders │ ├── bars.vue │ ├── dots.vue │ ├── index.js │ └── spinner.vue ├── types └── index.d.ts ├── webpack.config.dev.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "forceAllTransforms": false, 8 | "targets": { 9 | "browsers": [ 10 | "defaults", 11 | "not dead", 12 | "not ie 11" 13 | ] 14 | } 15 | } 16 | ] 17 | ], 18 | "env": { 19 | "test": { 20 | "presets": [ 21 | [ 22 | "@babel/preset-env", 23 | { 24 | "targets": { 25 | "node": "current" 26 | } 27 | } 28 | ] 29 | ] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | 9 | # Unix-style newlines with a newline ending every file 10 | end_of_line = lf 11 | insert_final_newline = true 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | 15 | [*.php] 16 | indent_size = 4 17 | 18 | # Override for blade since its mostly html 19 | [*.blade.php] 20 | indent_size = 2 21 | 22 | [*.md] 23 | trim_trailing_whitespace = false 24 | 25 | # These properties supported by few editors 26 | [*.js] 27 | curly_bracket_next_line = false 28 | spaces_around_operators = true 29 | indent_brace_style = 1TBS 30 | spaces_around_brackets = both 31 | 32 | [*.{scss,css,js,ts,html,json,vue,yml,babelrc,eslintrc}] 33 | indent_size = 2 34 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # https://git-scm.com/book/en/Customizing-Git-Git-Attributes 2 | 3 | # Auto detect text files and perform LF normalization 4 | * text=auto 5 | 6 | # Don't diff or textually merge source maps 7 | *.map binary 8 | 9 | # Avoid unreadable diffs for generated text files, eg: *.min.js 10 | *.min.* binary 11 | 12 | # Image files 13 | *.jpg binary 14 | *.jpeg binary 15 | *.png binary 16 | *.gif binary 17 | *.ico binary 18 | 19 | # Export ignore 20 | tests export-ignore 21 | __test__ export-ignore 22 | .github export-ignore 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # http://git-scm.com/docs/gitignore 2 | 3 | # various IDEs 4 | .idea/ 5 | .vscode/ 6 | 7 | # logs and cache 8 | *.log 9 | npm-debug.log* 10 | .sass-cache 11 | .cache 12 | .php_cs.cache 13 | 14 | # OS generated files 15 | [Tt]humbs.db 16 | ehthumbs.db 17 | *~ 18 | .*~ 19 | ._* 20 | *.bak 21 | *.save 22 | *.swp 23 | 24 | # Recycle bin folder used by different os 25 | .Trash-* 26 | $RECYCLE.BIN/ 27 | 28 | # Windows shortcuts 29 | *.lnk 30 | 31 | # Folder config file 32 | [Dd]esktop.ini 33 | *.DS_Store 34 | .DS_Store? 35 | 36 | # node packages 37 | node_modules/ 38 | 39 | # Security tokens 40 | *.pem 41 | *.pub 42 | *.crt 43 | *.key 44 | 45 | # Project related 46 | *.tgz 47 | /docs/ 48 | /dist/ 49 | /coverage/ 50 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | auto-install-peers=false 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### [6.0.6](https://github.com/ankurk91/vue-loading-overlay/compare/6.0.5...6.0.6) 4 | 5 | * Fix: Typescript def, #126 6 | 7 | ### [6.0.5](https://github.com/ankurk91/vue-loading-overlay/compare/6.0.4...6.0.5) 8 | 9 | * Fix: Typescript def, #123 10 | 11 | ### [6.0.4](https://github.com/ankurk91/vue-loading-overlay/compare/6.0.3...6.0.4) 12 | 13 | * Fix issue, #119 14 | 15 | ### [6.0.0](https://github.com/ankurk91/vue-loading-overlay/compare/5.0.3...6.0.0) 16 | 17 | * Remove plugin from default export 18 | * Remove `blur` prop 19 | * Change dist CSS file name 20 | * Rename CSS class names 21 | 22 | ### [5.0.1](https://github.com/ankurk91/vue-loading-overlay/compare/4.0.4...5.0.1) 23 | 24 | * Allow composition API usage, [#88](https://github.com/ankurk91/vue-loading-overlay/issues/88) 25 | * Now you can import package like 26 | 27 | ```js 28 | // New way of importing 29 | import {useLoading} from 'vue-loading-overlay'; 30 | import {Component} from 'vue-loading-overlay'; 31 | import {Plugin} from 'vue-loading-overlay'; 32 | 33 | // The good old way still works as before 34 | import VueLoading from 'vue-loading-overlay'; 35 | ``` 36 | 37 | * (Breaking) Use named export in web browser environment 38 | 39 | ```diff 40 | - app.use(VueLoading) 41 | + app.use(VueLoading.Plugin) 42 | ``` 43 | 44 | ### [4.0.4](https://github.com/ankurk91/vue-loading-overlay/compare/4.0.3...4.0.4) 45 | 46 | * Fix: Composition API usage, [#88](https://github.com/ankurk91/vue-loading-overlay/issues/88) 47 | 48 | ### [4.0.3](https://github.com/ankurk91/vue-loading-overlay/compare/4.0.2...4.0.3) 49 | 50 | * Fix: Possible SSR issue 51 | 52 | ### [4.0.2](https://github.com/ankurk91/vue-loading-overlay/compare/4.0.1...4.0.2) 53 | 54 | * Fix: usage as plugin, in-correct parameters were being passed 55 | 56 | ### [4.0.0](https://github.com/ankurk91/vue-loading-overlay/compare/3.4.2...4.0.0) :warning: 57 | 58 | * Drop support for Vue v2.x and add support for Vue v3.x 59 | * Drop IE 11 support 60 | 61 | ### [3.4.2](https://github.com/ankurk91/vue-loading-overlay/compare/3.4.1...3.4.2) 62 | 63 | * Fix: [#64](https://github.com/ankurk91/vue-loading-overlay/issues/64) 64 | 65 | ### [3.4.1](https://github.com/ankurk91/vue-loading-overlay/compare/3.4.0...3.4.1) 66 | 67 | * Add type definitions 68 | 69 | ### [3.4.0](https://github.com/ankurk91/vue-loading-overlay/compare/3.3.4...3.4.0) 70 | 71 | * Add: Lock scroll feature, [#51](https://github.com/ankurk91/vue-loading-overlay/issues/51) 72 | * Add: `blur` prop to blur the background 73 | 74 | ### [3.3.4](https://github.com/ankurk91/vue-loading-overlay/compare/3.3.3...3.3.4) 75 | 76 | * Fix: restore broken IE 11 support. :warning: IE 11 support will be removed in next major version. 77 | 78 | ### [3.3.3](https://github.com/ankurk91/vue-loading-overlay/compare/3.3.2...3.3.3) 79 | 80 | * Fix: [#26](https://github.com/ankurk91/vue-loading-overlay/issues/26) by introducing `enforceFocus` prop 81 | 82 | ### [3.3.2](https://github.com/ankurk91/vue-loading-overlay/compare/3.3.1...3.3.2) 83 | 84 | * Fix: revert [#44](https://github.com/ankurk91/vue-loading-overlay/issues/44) 85 | to fix [#46](https://github.com/ankurk91/vue-loading-overlay/issues/46) 86 | 87 | ### [3.3.1](https://github.com/ankurk91/vue-loading-overlay/compare/3.3.0...3.3.1) 88 | 89 | * Fix: 90 | - [#42](https://github.com/ankurk91/vue-loading-overlay/issues/42) 91 | - [#44](https://github.com/ankurk91/vue-loading-overlay/issues/44) 92 | 93 | ### [3.3.0](https://github.com/ankurk91/vue-loading-overlay/compare/3.2.0...3.3.0) 94 | 95 | * Increase `z-index` value to `9999` 96 | 97 | ### [3.2.0](https://github.com/ankurk91/vue-loading-overlay/compare/3.1.1...3.2.0) 98 | 99 | * Add: `z-index` prop 100 | 101 | ### [3.1.1](https://github.com/ankurk91/vue-loading-overlay/compare/3.1.0...3.1.1) 102 | 103 | * Fix: `onCancel` prop default value to empty function 104 | 105 | ### [3.1.0](https://github.com/ankurk91/vue-loading-overlay/compare/3.0.1...3.1.0) 106 | 107 | * Add: `bars` loader type 108 | 109 | ### [3.0.1](https://github.com/ankurk91/vue-loading-overlay/compare/3.0.0...3.0.1) 110 | 111 | * Add: `opacity` prop 112 | 113 | ### [3.0.0](https://github.com/ankurk91/vue-loading-overlay/compare/2.2.2...3.0.0) (breaking) 114 | 115 | * Changed: 116 | - use SVG instead of CSS animation 117 | - rename `animation` prop to `transition` 118 | - rename `close` event to `hide` 119 | - `onCancel` callback will be called only when cancelled by user 120 | - use `v-show` instead of `v-if` 121 | - CSS classes has been prefixed with `vld` 122 | - Output CSS file name has been renamed `dist/vue-loading.css`, removed **`.min`** from name 123 | * Added: see docs for usage 124 | - add `loader` prop 125 | - add `color` and `backgroundColor` prop 126 | - add `height` and `width` prop 127 | - add `before` and `after` slots 128 | - add second argument to `$loading.show(props?,slots?)` method to accept slots 129 | * Removed: 130 | - SCSS has been removed completely 131 | * Other: 132 | - live example available on gh-pages 133 | 134 | ### [2.2.2](https://github.com/ankurk91/vue-loading-overlay/compare/2.2.1...2.2.2) 135 | 136 | * Fix: SSR issue [#18](https://github.com/ankurk91/vue-loading-overlay/pull/18) 137 | 138 | ### [2.2.1](https://github.com/ankurk91/vue-loading-overlay/compare/2.2.0...2.2.1) 139 | 140 | * Fix: regression in trap focus feature 141 | * Fix: regression in `z-index` issue 142 | * Docs: updated demo examples 143 | 144 | ### [2.2.0](https://github.com/ankurk91/vue-loading-overlay/compare/2.1.0...2.2.0) 145 | 146 | * Add: default slot to override the loading indicator 147 | * Add: trap `focus` feature, user will not be able to tab on elements those are behind the loading overlay 148 | * a11y: use `aria-live` 149 | * Fix: detecting `window` object 150 | * Fix: `z-index` issue on loading element 151 | * Test: add tests 152 | * Docs: update readme with better examples 153 | 154 | ### [2.1.0](https://github.com/ankurk91/vue-loading-overlay/compare/2.0.4...2.1.0) 155 | 156 | * Add: allow loader to be restricted to a container element 157 | * Chore: auto pre-fixer 158 | 159 | ### [2.0.4](https://github.com/ankurk91/vue-loading-overlay/compare/2.0.3...2.0.4) 160 | 161 | * Chore: `dist` now includes non-minified js file as well 162 | 163 | ### [2.0.3](https://github.com/ankurk91/vue-loading-overlay/compare/2.0.2...2.0.3) 164 | 165 | * Fix: webpack build config, [#3](https://github.com/ankurk91/vue-loading-overlay/issues/3) 166 | 167 | ### [2.0.2](https://github.com/ankurk91/vue-loading-overlay/compare/2.0.1...2.0.2) 168 | 169 | * Fix: Don't call `onCancel` callback function when loader is not active 170 | 171 | ### [2.0.1](https://github.com/ankurk91/vue-loading-overlay/compare/2.0.0...2.0.1) 172 | 173 | * Fix: was not working in non module environments 174 | 175 | ### [2.0.0](https://github.com/ankurk91/vue-loading-overlay/compare/1.0.0...2.0.0) (breaking) 176 | 177 | * Fix: v1.0.0 was completely broken due to a webpack configuration 178 | * Change: check `readme.md` file for updated usage instruction 179 | 180 | ### 1.0.0 181 | 182 | * Initial release 183 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Ankur Kumar 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 | # Vue Loading Overlay Component 2 | 3 | [![downloads](https://badgen.net/npm/dt/vue-loading-overlay)](https://npm-stat.com/charts.html?package=vue-loading-overlay&from=2018-01-01) 4 | [![jsdelivr](https://data.jsdelivr.com/v1/package/npm/vue-loading-overlay/badge?style=rounded)](https://www.jsdelivr.com/package/npm/vue-loading-overlay) 5 | [![npm-version](https://badgen.net/npm/v/vue-loading-overlay)](https://www.npmjs.com/package/vue-loading-overlay) 6 | [![github-tag](https://badgen.net/github/tag/ankurk91/vue-loading-overlay)](https://github.com/ankurk91/vue-loading-overlay/tags) 7 | [![build](https://github.com/ankurk91/vue-loading-overlay/workflows/build/badge.svg)](https://github.com/ankurk91/vue-loading-overlay/actions) 8 | [![license](https://badgen.net/github/license/ankurk91/vue-loading-overlay)](LICENSE.txt) 9 | ![TypeScript](https://badgen.net/badge/icon/Typed?icon=typescript&label&labelColor=blue&color=555555) 10 | 11 | Vue.js component for full screen loading indicator 12 | 13 | ## [Demo](https://ankurk91.github.io/vue-loading-overlay/) or [JSFiddle](https://jsfiddle.net/ankurk91/2ou37bc8/) 14 | 15 | ### Version matrix 16 | 17 | | Vue.js version | Package version | Branch | 18 | | :--- |:---------------:|-----------------------------------------------------------------:| 19 | | 2.x | 3.x | [3.x](https://github.com/ankurk91/vue-loading-overlay/tree/v3.x) | 20 | | 3.x | 6.x | `main` | 21 | 22 | ## Installation 23 | 24 | ```bash 25 | npm install vue-loading-overlay@^6.0 26 | ``` 27 | 28 | ## Usage 29 | 30 | #### As component 31 | 32 | ```html 33 | 34 | 45 | 46 | 74 | ``` 75 | 76 | ### As plugin 77 | 78 | Initialise the plugin in your app 79 | 80 | ```js 81 | import {createApp} from 'vue'; 82 | import {LoadingPlugin} from 'vue-loading-overlay'; 83 | import 'vue-loading-overlay/dist/css/index.css'; 84 | // Your app initialization logic goes here 85 | const app = createApp({}); 86 | app.use(LoadingPlugin); 87 | app.mount('#app'); 88 | ``` 89 | 90 | Then use the plugin in your components 91 | 92 | ```html 93 | 94 | 103 | 104 | 130 | ``` 131 | 132 | #### or same with Composition API 133 | 134 | ```html 135 | 157 | ``` 158 | 159 | ## Available props 160 | 161 | The component accepts these props: 162 | 163 | | Attribute | Type | Default | Description | 164 | | :--- | :---: | :---: | :--- | 165 | | active | Boolean | `false` | Show loading by default when `true`, use it as `v-model:active` | 166 | | can-cancel | Boolean | `false` | Allow user to cancel by pressing ESC or clicking outside | 167 | | on-cancel | Function | `()=>{}` | Do something upon cancel, works in conjunction with `can-cancel` | 168 | | is-full-page | Boolean | `true` | When `false`; limit loader to its container^ | 169 | | transition | String | `fade` | Transition name | 170 | | color | String | `#000` | Customize the color of loading icon | 171 | | height | Number | * | Customize the height of loading icon | 172 | | width | Number | * | Customize the width of loading icon | 173 | | loader | String | `spinner` | Name of icon shape you want use as loader, `spinner` or `dots` or `bars` | 174 | | background-color | String | `#fff` | Customize the overlay background color | 175 | | opacity | Number | `0.5` | Customize the overlay background opacity | 176 | | z-index | Number | `9999` | Customize the overlay z-index | 177 | | enforce-focus | Boolean | `true` | Force focus on loader | 178 | | lock-scroll | Boolean | `false` | Freeze the scrolling during full screen loader | 179 | 180 | * ^When `is-full-page` is set to `false`, the container element should be positioned as `position: relative`. You can 181 | use CSS helper class `vl-parent`. 182 | * *The default `height` and `width` values may vary based on the `loader` prop value 183 | 184 | ## Available slots 185 | 186 | The component accepts these slots: 187 | 188 | * `default` - Replace the animated icon with yours 189 | * `before` - Place anything before the animated icon, you may need to style this. 190 | * `after` - Place anything after the animated icon, you may need to style this. 191 | 192 | ## API methods 193 | 194 | ### `this.$loading.show(?propsData,?slots)` 195 | 196 | ```js 197 | import {h} from 'vue'; 198 | 199 | let loader = this.$loading.show({ 200 | // Pass props by their camelCased names 201 | container: this.$refs.loadingContainer, 202 | canCancel: true, // default false 203 | onCancel: this.yourCallbackMethod, 204 | color: '#000000', 205 | loader: 'spinner', 206 | width: 64, 207 | height: 64, 208 | backgroundColor: '#ffffff', 209 | opacity: 0.5, 210 | zIndex: 999, 211 | }, { 212 | // Pass slots by their names 213 | default: h('your-custom-loader-component-name'), 214 | }); 215 | // hide loader whenever you want 216 | loader.hide(); 217 | ``` 218 | 219 | ## Global configs 220 | 221 | You can set props and slots for all future instances when using as plugin 222 | 223 | ```js 224 | app.use(LoadingPlugin, { 225 | // props 226 | color: 'red' 227 | }, { 228 | // slots 229 | }) 230 | ``` 231 | 232 | Further you can override any prop or slot when creating new instances 233 | 234 | ```js 235 | let loader = this.$loading.show({ 236 | color: 'blue' 237 | }, { 238 | // override slots 239 | }); 240 | ``` 241 | 242 | ## Use directly in browser (with CDN) 243 | 244 | ```html 245 | 246 | 247 | 248 | 249 | 250 | 251 | 257 | ``` 258 | 259 | ## Run examples on your localhost 260 | 261 | * Clone this repo 262 | * Make sure you have node-js `>=20.11` and [pnpm](https://pnpm.io/) `>=8.x` pre-installed 263 | * Install dependencies `pnpm install` 264 | * Run webpack dev server `npm start` 265 | * This should open the demo page in your default web browser 266 | 267 | ## Testing 268 | 269 | * This package is using [Jest](https://github.com/facebook/jest) 270 | and [vue-test-utils](https://github.com/vuejs/test-utils) for testing. 271 | * Execute tests with this command `npm test` 272 | 273 | ## License 274 | 275 | [MIT](LICENSE.txt) License 276 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | ## From v5.x to v6.x 4 | 5 | If you have been consuming the plugin then you have to use named imports now 6 | 7 | ```diff 8 | - import LoadingPlugin from 'vue-loading-overlay'; 9 | + import {LoadingPlugin} from 'vue-loading-overlay'; 10 | app.use(LoadingPlugin) 11 | ``` 12 | 13 | Change CSS import file name as follows 14 | 15 | ```diff 16 | - import 'vue-loading-overlay/dist/vue-loading.css'; 17 | + import 'vue-loading-overlay/dist/css/index.css'; 18 | ``` 19 | 20 | If you have been using the CSS class names, then change them as follows, notice 21 | all CSS class names has been prefixed with `vl` now 22 | 23 | ```diff 24 | -
25 | +
26 | ``` 27 | 28 | If you have been consuming this package via CDN then 29 | 30 | ```diff 31 | - app.use(VueLoading.Plugin); 32 | + app.use(VueLoading.LoadingPlugin); 33 | ``` 34 | 35 | ## From v4.x to v5.x 36 | 37 | If you are using the package directly from a CDN, Then you need to use named exports now 38 | 39 | ```diff 40 | - app.use(VueLoading) 41 | + app.use(VueLoading.Plugin) 42 | ``` 43 | 44 | There is no breaking change if you are consuming the package through a module bundler like webpack. 45 | 46 | ## From v3.4 to v4.x 47 | 48 | If you have been consuming the component, update your code as follows: 49 | 50 | ```diff 51 | - 52 | + 53 | ``` 54 | 55 | Everything else should be automatically covered in vue v2 to vue v3 upgrade guide. 56 | 57 | ## From v2.x to v3.x 58 | 59 | #### Styling 60 | 61 | * CSS file name has been changed, now you need to import this file instead 62 | 63 | ```js 64 | import 'vue-loading-overlay/dist/vue-loading.css'; 65 | ``` 66 | 67 | * If you have been importing SCSS files to override colors then you should use props instead since SCSS has been 68 | removed. 69 | 70 | #### Component API 71 | 72 | * Rename `animation` prop to `transition` 73 | * Rename `close` event to `hide` 74 | -------------------------------------------------------------------------------- /examples/App.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 43 | 44 | -------------------------------------------------------------------------------- /examples/components/componentExample.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 110 | -------------------------------------------------------------------------------- /examples/components/pluginExample.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 113 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js Loading Overlay - Demo 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import {createApp} from 'vue'; 4 | 5 | import 'bootstrap/dist/css/bootstrap.min.css'; 6 | 7 | import App from './App.vue'; 8 | import {LoadingPlugin} from "../src/index"; 9 | 10 | const app = createApp(App); 11 | app.use(LoadingPlugin); 12 | app.mount('#app') 13 | 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'jsdom', 3 | collectCoverage: true, 4 | testEnvironmentOptions: { 5 | testURL: 'http://localhost', 6 | customExportConditions: [ 7 | 'node', 8 | 'node-addons', 9 | ], 10 | }, 11 | transform: { 12 | '^.+\\.js$': 'babel-jest', 13 | '.*\\.(vue)$': '@vue/vue3-jest' 14 | }, 15 | moduleFileExtensions: [ 16 | 'js', 17 | 'json', 18 | 'jsx', 19 | 'node', 20 | 'vue', 21 | 'css' 22 | ], 23 | moduleNameMapper: { 24 | '\\.(css|less|scss)$': '/__test__/__mocks__/styleMock.js' 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-loading-overlay", 3 | "version": "6.0.6", 4 | "description": "Vue.js component for full screen loading indicator.", 5 | "main": "dist/index.js", 6 | "types": "types/index.d.ts", 7 | "style": "dist/css/index.css", 8 | "files": [ 9 | "src", 10 | "dist", 11 | "types" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/ankurk91/vue-loading-overlay.git" 16 | }, 17 | "keywords": [ 18 | "vue", 19 | "loading", 20 | "loader", 21 | "overlay", 22 | "spinner" 23 | ], 24 | "author": "ankurk91", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/ankurk91/vue-loading-overlay/issues" 28 | }, 29 | "homepage": "https://github.com/ankurk91/vue-loading-overlay", 30 | "scripts": { 31 | "test": "jest --runInBand", 32 | "test:watch": "npm run test --watch --notify", 33 | "start": "npm run dev", 34 | "dev": "webpack serve --node-env=development --progress --hot --config=webpack.config.dev.js", 35 | "docs": "webpack --node-env=production --config=webpack.config.dev.js --progress --mode=production", 36 | "build": "webpack --node-env=production --progress --mode=production", 37 | "prepublishOnly": "npm run test && npm run build" 38 | }, 39 | "devDependencies": { 40 | "@babel/core": "^7.25.2", 41 | "@babel/preset-env": "^7.25.4", 42 | "@vue/compiler-sfc": "^3.5.1", 43 | "@vue/test-utils": "^2.4.6", 44 | "@vue/vue3-jest": "^29.2.6", 45 | "babel-jest": "^29.7.0", 46 | "babel-loader": "^9.1.3", 47 | "bootstrap": "^4.6.2", 48 | "css-loader": "^7.1.2", 49 | "file-loader": "^6.2.0", 50 | "html-webpack-plugin": "^5.6.0", 51 | "jest": "^29.7.0", 52 | "jest-environment-jsdom": "^29.7.0", 53 | "mini-css-extract-plugin": "^2.9.1", 54 | "style-loader": "^4.0.0", 55 | "vue": "^3.5.1", 56 | "vue-loader": "^17.4.2", 57 | "webpack": "^5.94.0", 58 | "webpack-cli": "^5.1.4", 59 | "webpack-dev-server": "^5.1.0" 60 | }, 61 | "peerDependencies": { 62 | "vue": "^3.2.0" 63 | }, 64 | "engines": { 65 | "node": ">=12.13.0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/css/index.css: -------------------------------------------------------------------------------- 1 | .vl-shown { 2 | overflow: hidden; 3 | } 4 | 5 | .vl-overlay { 6 | bottom: 0; 7 | left: 0; 8 | position: absolute; 9 | right: 0; 10 | top: 0; 11 | align-items: center; 12 | display: none; 13 | justify-content: center; 14 | overflow: hidden; 15 | z-index: 9999; 16 | } 17 | 18 | .vl-overlay.vl-active { 19 | display: flex; 20 | } 21 | 22 | .vl-overlay.vl-full-page { 23 | z-index: 9999; 24 | position: fixed; 25 | } 26 | 27 | .vl-overlay .vl-background { 28 | bottom: 0; 29 | left: 0; 30 | position: absolute; 31 | right: 0; 32 | top: 0; 33 | background: #fff; 34 | opacity: 0.5; 35 | } 36 | 37 | .vl-overlay .vl-icon, .vl-parent { 38 | position: relative; 39 | } 40 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {useLoading} from './js/api'; 2 | import Component from './js/Component.vue'; 3 | import './css/index.css'; 4 | 5 | const LoadingPlugin = (app, props = {}, slots = {}) => { 6 | const instance = useLoading(props, slots); 7 | app.config.globalProperties.$loading = instance; 8 | app.provide('$loading', instance) 9 | }; 10 | 11 | export default Component; 12 | export {useLoading, LoadingPlugin, Component} 13 | 14 | -------------------------------------------------------------------------------- /src/js/Component.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 167 | -------------------------------------------------------------------------------- /src/js/api.js: -------------------------------------------------------------------------------- 1 | import {createComponent} from './helpers'; 2 | import LoadingComponent from './Component.vue'; 3 | 4 | export function useLoading(globalProps = {}, globalSlots = {}) { 5 | 6 | return { 7 | show(props = globalProps, slots = globalSlots) { 8 | const forceProps = { 9 | programmatic: true, 10 | lockScroll: true, 11 | isFullPage: false, 12 | active: true, 13 | } 14 | 15 | const propsData = {...globalProps, ...props, ...forceProps}; 16 | let container = propsData.container; 17 | 18 | if (!propsData.container) { 19 | container = document.body; 20 | propsData.isFullPage = true; 21 | } 22 | 23 | const mergedSlots = {...globalSlots, ...slots}; 24 | const instance = createComponent(LoadingComponent, propsData, container, mergedSlots); 25 | 26 | return { 27 | hide: instance.ctx.hide 28 | } 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/js/helpers.js: -------------------------------------------------------------------------------- 1 | import {h, render} from 'vue'; 2 | 3 | export function removeElement(el) { 4 | if (typeof el.remove !== 'undefined') { 5 | el.remove() 6 | } else { 7 | el.parentNode?.removeChild(el) 8 | } 9 | } 10 | 11 | // Taken from https://github.com/moyoujun/vue3-loading-overlay/blob/master/src/index.ts 12 | export function createComponent(component, props, parentContainer, slots = {}) { 13 | const vNode = h(component, props, slots) 14 | const container = document.createElement('div'); 15 | container.classList.add('vld-container') 16 | parentContainer.appendChild(container); 17 | render(vNode, container); 18 | 19 | return vNode.component 20 | } 21 | 22 | export function hasWindow() { 23 | return typeof window !== 'undefined'; 24 | } 25 | 26 | export const MayBeHTMLElement = hasWindow() ? window.HTMLElement : Object; 27 | -------------------------------------------------------------------------------- /src/js/trapFocusMixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | mounted() { 3 | if (this.enforceFocus) { 4 | document.addEventListener('focusin', this.focusIn) 5 | } 6 | }, 7 | methods: { 8 | focusIn(event) { 9 | // Ignore when loading is not active 10 | if (!this.isActive) return; 11 | 12 | if ( 13 | // Event target is the loading div element itself 14 | event.target === this.$el || 15 | // Event target is inside the loading div 16 | this.$el.contains(event.target) 17 | ) return; 18 | 19 | // Use container as parent when available otherwise use parent element when isFullPage is false 20 | let parent = this.container ? this.container : (this.isFullPage ? null : this.$el.parentElement); 21 | 22 | if ( 23 | // Always prevent when loading is full screen 24 | this.isFullPage || 25 | // When a parent exist means loader is running inside a container 26 | // When loading is NOT full screen and event target is inside the given container 27 | (parent && parent.contains(event.target)) 28 | ) { 29 | event.preventDefault(); 30 | this.$el.focus() 31 | } 32 | } 33 | }, 34 | beforeUnmount() { 35 | document.removeEventListener('focusin', this.focusIn) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/loaders/bars.vue: -------------------------------------------------------------------------------- 1 | 30 | 51 | -------------------------------------------------------------------------------- /src/loaders/dots.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 57 | -------------------------------------------------------------------------------- /src/loaders/index.js: -------------------------------------------------------------------------------- 1 | import Spinner from './spinner.vue' 2 | import Dots from './dots.vue' 3 | import Bars from './bars.vue' 4 | 5 | export default { 6 | Spinner, 7 | Dots, 8 | Bars, 9 | } 10 | -------------------------------------------------------------------------------- /src/loaders/spinner.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 41 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import type {App, DefineComponent} from 'vue' 2 | 3 | export type LoaderType = 'spinner' | 'dots' | 'bars' 4 | 5 | export interface Props { 6 | active?: boolean, 7 | canCancel?: boolean, 8 | onCancel?: () => any, 9 | isFullPage?: boolean, 10 | transition?: string, 11 | color?: string, 12 | height?: number, 13 | width?: number, 14 | loader?: LoaderType | string, 15 | backgroundColor?: string, 16 | opacity?: number, 17 | zIndex?: number, 18 | enforceFocus?: boolean, 19 | lockScroll?: boolean, 20 | pauseOnHover?: boolean, 21 | container?: Object | HTMLElement | Function, 22 | } 23 | 24 | export interface Slots { 25 | default?: any 26 | before?: any 27 | after?: any 28 | } 29 | 30 | export interface ActiveLoader { 31 | hide(): void 32 | } 33 | 34 | export interface PluginApi { 35 | show(props?: Props, slots?: Slots): ActiveLoader 36 | } 37 | 38 | declare module 'vue' { 39 | interface ComponentCustomProperties { 40 | readonly $loading: PluginApi; 41 | } 42 | } 43 | 44 | declare const LoadingPlugin: (app: App, props?: Props, slots?: Slots) => void 45 | declare const Component: DefineComponent void, 'update:active': (value: boolean) => void }> 46 | 47 | declare function useLoading(globalProps?: Props, globalSlots?: Slots): PluginApi 48 | 49 | export {LoadingPlugin, Component, useLoading}; 50 | 51 | export default Component 52 | -------------------------------------------------------------------------------- /webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const path = require('path'); 5 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | const {VueLoaderPlugin} = require('vue-loader'); 7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 8 | const TerserPlugin = require('terser-webpack-plugin'); 9 | 10 | const isProduction = process.env.NODE_ENV === 'production'; 11 | 12 | module.exports = { 13 | mode: 'development', 14 | context: __dirname, 15 | resolve: { 16 | modules: [ 17 | path.resolve(__dirname, 'node_modules'), 18 | ], 19 | alias: { 20 | vue: "@vue/runtime-dom" 21 | }, 22 | }, 23 | entry: './examples/index.js', 24 | output: { 25 | clean: true, 26 | path: path.resolve(__dirname, 'docs'), 27 | publicPath: '', 28 | filename: 'js/[name].[chunkhash].js' 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.vue$/, 34 | loader: 'vue-loader', 35 | exclude: /node_modules/, 36 | }, 37 | { 38 | test: /\.js$/, 39 | loader: 'babel-loader', 40 | exclude: /node_modules/, 41 | }, 42 | { 43 | test: /\.css$/, 44 | use: [ 45 | isProduction ? MiniCssExtractPlugin.loader : 46 | { 47 | loader: 'style-loader', 48 | }, 49 | { 50 | loader: 'css-loader', 51 | }, 52 | ], 53 | }, 54 | { 55 | test: /\.jpe?g$|\.gif$|\.png$/i, 56 | loader: 'file-loader', 57 | options: { 58 | name: '[path][name]-[contenthash].[ext]', 59 | } 60 | }, 61 | { 62 | test: /\.(woff|woff2|eot|ttf|svg)(\?.*$|$)/, 63 | loader: 'file-loader', 64 | options: { 65 | name: '[path][name]-[contenthash].[ext]', 66 | } 67 | } 68 | ] 69 | }, 70 | optimization: { 71 | runtimeChunk: false, 72 | splitChunks: { 73 | chunks: 'all', 74 | }, 75 | minimizer: [], 76 | }, 77 | plugins: [ 78 | new HtmlWebpackPlugin({ 79 | inject: true, 80 | hash: false, 81 | template: './examples/index.html', 82 | minify: { 83 | removeComments: isProduction, 84 | collapseWhitespace: isProduction, 85 | removeAttributeQuotes: isProduction, 86 | minifyJS: isProduction, 87 | minifyCSS: isProduction, 88 | minifyURLs: isProduction, 89 | } 90 | }), 91 | new webpack.DefinePlugin({ 92 | __VUE_OPTIONS_API__: true, 93 | __VUE_PROD_DEVTOOLS__: true 94 | }), 95 | new VueLoaderPlugin(), 96 | ], 97 | devServer: { 98 | host: 'localhost', 99 | port: 9002, 100 | open: true, 101 | client: { 102 | overlay: { 103 | warnings: false, 104 | errors: true 105 | }, 106 | }, 107 | static: path.resolve(process.cwd(), 'docs'), 108 | }, 109 | devtool: isProduction ? false : 'eval-cheap-source-map', 110 | performance: { 111 | hints: false, 112 | }, 113 | stats: { 114 | modules: false, 115 | children: false, 116 | entrypoints: false, 117 | } 118 | }; 119 | 120 | if (isProduction) { 121 | module.exports.plugins.push( 122 | new MiniCssExtractPlugin({ 123 | filename: 'css/demo-[chunkhash].css', 124 | }), 125 | ); 126 | module.exports.optimization.minimizer.push( 127 | new TerserPlugin({ 128 | extractComments: false, 129 | terserOptions: { 130 | output: { 131 | comments: false, 132 | }, 133 | compress: { 134 | drop_debugger: true, 135 | drop_console: true 136 | } 137 | } 138 | }), 139 | ); 140 | } 141 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const path = require('path'); 5 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 6 | const TerserPlugin = require('terser-webpack-plugin'); 7 | const {VueLoaderPlugin} = require('vue-loader'); 8 | 9 | module.exports = { 10 | context: __dirname, 11 | resolve: { 12 | modules: [ 13 | path.resolve(__dirname, 'node_modules'), 14 | ], 15 | alias: { 16 | vue: "@vue/runtime-dom" 17 | }, 18 | }, 19 | entry: { 20 | 'index': './src/index.js', 21 | 'index.min': './src/index.js', 22 | }, 23 | externals: { 24 | 'vue': { 25 | commonjs: 'vue', 26 | commonjs2: 'vue', 27 | amd: 'vue', 28 | root: 'Vue' 29 | }, 30 | }, 31 | output: { 32 | clean: true, 33 | path: path.resolve(__dirname, 'dist'), 34 | filename: '[name].js', 35 | library: { 36 | name: 'VueLoading', 37 | type: 'umd', 38 | umdNamedDefine: true, 39 | }, 40 | globalObject: 'this', 41 | pathinfo: false, 42 | }, 43 | module: { 44 | rules: [ 45 | { 46 | test: /\.vue$/, 47 | loader: 'vue-loader', 48 | exclude: /node_modules/, 49 | }, 50 | { 51 | test: /\.js$/, 52 | loader: 'babel-loader', 53 | exclude: /node_modules/, 54 | }, 55 | { 56 | test: /\.css$/, 57 | use: [ 58 | MiniCssExtractPlugin.loader, 59 | { 60 | loader: 'css-loader', 61 | options: { 62 | sourceMap: false, 63 | } 64 | }, 65 | ], 66 | }, 67 | ] 68 | }, 69 | optimization: { 70 | usedExports: false, 71 | minimizer: [ 72 | new TerserPlugin({ 73 | include: /\.min\.js$/, 74 | extractComments: false, 75 | terserOptions: { 76 | output: { 77 | comments: false, 78 | }, 79 | compress: { 80 | drop_console: true 81 | } 82 | } 83 | }), 84 | ] 85 | }, 86 | plugins: [ 87 | new MiniCssExtractPlugin({ 88 | filename: 'css/index.css', 89 | }), 90 | new VueLoaderPlugin(), 91 | ], 92 | devtool: false, 93 | performance: { 94 | hints: false, 95 | }, 96 | stats: { 97 | modules: false, 98 | children: false, 99 | entrypoints: false, 100 | } 101 | }; 102 | --------------------------------------------------------------------------------