├── static ├── .gitkeep ├── example1.gif ├── example2.gif ├── example3.gif └── example4.gif ├── .github ├── FUNDING.yml └── workflows │ ├── node.js.yml │ └── deploy-on-merge.yml ├── public ├── favicon.ico └── index.html ├── src ├── assets │ └── logo.png ├── components │ ├── css │ │ ├── base.css │ │ ├── dual-ring.css │ │ ├── pulse.css │ │ ├── ripple.css │ │ ├── loadbar.css │ │ ├── circle-solid-spin.css │ │ ├── facebook.css │ │ ├── hourglass.css │ │ ├── clock.css │ │ ├── hydrogen.css │ │ ├── ring.css │ │ ├── wordpress.css │ │ ├── double-bounce.css │ │ ├── rotating-plane.css │ │ ├── three-bounce.css │ │ ├── heart.css │ │ ├── ellipsis.css │ │ ├── wave.css │ │ ├── chasing-dots.css │ │ ├── grid.css │ │ ├── fade-in.css │ │ ├── circle-fade.css │ │ ├── loaders-css.css │ │ ├── cube-grid.css │ │ ├── wandering-cubes.css │ │ ├── roller.css │ │ ├── moon.css │ │ ├── folding-cube.css │ │ ├── circle.css │ │ ├── fading-circle.css │ │ └── loaders.css │ ├── Spinner.vue │ └── spinners.js ├── main.js ├── index.js └── Example.vue ├── babel.config.js ├── .npmignore ├── .gitignore ├── index.html ├── vite.example.config.js ├── .eslintrc.js ├── postcss.config.js ├── vite.config.js ├── LICENSE ├── test └── smoke.js ├── package.json ├── postcss-plugins.js └── README.md /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: tonpc64 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /static/example1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/static/example1.gif -------------------------------------------------------------------------------- /static/example2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/static/example2.gif -------------------------------------------------------------------------------- /static/example3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/static/example3.gif -------------------------------------------------------------------------------- /static/example4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonPC64/vue-spinkit/HEAD/static/example4.gif -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { targets: { node: 'current' } }] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/components/css/base.css: -------------------------------------------------------------------------------- 1 | .sk-spinner { 2 | color: #333; 3 | } 4 | 5 | .sk-spinner > div { 6 | background-color: currentColor; 7 | } 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /public/ 2 | /src/ 3 | /build/ 4 | /config/ 5 | /static/ 6 | .babelrc 7 | .editconfig 8 | .eslintignore 9 | .eslintrc.js 10 | .postcssrc.js 11 | bili.config.js 12 | index.html 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /build 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-spinkit (dev) 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './Example.vue' 3 | // Import the library entry for its side-effects (injects CSS at runtime). 4 | // This keeps example styles working during dev without emitting a separate CSS file during library build. 5 | import './index.js' 6 | 7 | Vue.config.productionTip = false 8 | 9 | new Vue({ 10 | render: h => h(App), 11 | }).$mount('#app') 12 | -------------------------------------------------------------------------------- /vite.example.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue2' 3 | 4 | // This config builds the example app (index.html + src) into `dist/` for hosting. 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | root: process.cwd(), 8 | build: { 9 | outDir: 'dist', 10 | emptyOutDir: true, 11 | rollupOptions: { 12 | input: 'index.html' 13 | } 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /src/components/css/dual-ring.css: -------------------------------------------------------------------------------- 1 | .sk-dual-ring { 2 | display: inline-block; 3 | width: 64px; 4 | height: 64px; 5 | } 6 | 7 | .sk-dual-ring:after { 8 | content: " "; 9 | display: block; 10 | width: 46px; 11 | height: 46px; 12 | margin: 1px; 13 | border-radius: 50%; 14 | border: 5px solid currentColor; 15 | border-color: currentColor transparent currentColor transparent; 16 | animation: sk-dual-ring 1.2s linear infinite; 17 | } 18 | 19 | @keyframes sk-dual-ring { 20 | 0% { 21 | transform: rotate(0deg); 22 | } 23 | 100% { 24 | transform: rotate(360deg); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | es6: true 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:vue/essential' 10 | ], 11 | parserOptions: { 12 | parser: '@babel/eslint-parser', 13 | ecmaVersion: 2020, 14 | sourceType: 'module', 15 | requireConfigFile: false, 16 | babelOptions: { 17 | presets: ['@babel/preset-env'] 18 | } 19 | }, 20 | rules: { 21 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 23 | 'vue/multi-word-component-names': 'off' 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/css/pulse.css: -------------------------------------------------------------------------------- 1 | .sk-pulse > div { 2 | width: 27px; 3 | height: 27px; 4 | background-color: currentColor; 5 | border-radius: 100%; 6 | 7 | -webkit-animation: sk-scaleout 1.0s infinite ease-in-out; 8 | animation: sk-scaleout 1.0s infinite ease-in-out; 9 | } 10 | 11 | @-webkit-keyframes sk-scaleout { 12 | 0% { -webkit-transform: scale(0.0) } 13 | 100% { 14 | -webkit-transform: scale(1.0); 15 | opacity: 0; 16 | } 17 | } 18 | 19 | @keyframes sk-scaleout { 20 | 0% { 21 | transform: scale(0.0); 22 | -webkit-transform: scale(0.0); 23 | } 100% { 24 | transform: scale(1.0); 25 | -webkit-transform: scale(1.0); 26 | opacity: 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/css/ripple.css: -------------------------------------------------------------------------------- 1 | .sk-ripple { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-ripple div { 8 | position: absolute; 9 | border: 4px solid currentColor; 10 | opacity: 1; 11 | border-radius: 50%; 12 | animation: sk-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; 13 | } 14 | .sk-ripple div:nth-child(2) { 15 | animation-delay: -0.5s; 16 | } 17 | @keyframes sk-ripple { 18 | 0% { 19 | top: 28px; 20 | left: 28px; 21 | width: 0; 22 | height: 0; 23 | opacity: 1; 24 | } 25 | 100% { 26 | top: -1px; 27 | left: -1px; 28 | width: 58px; 29 | height: 58px; 30 | opacity: 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/css/loadbar.css: -------------------------------------------------------------------------------- 1 | .sk-loadbar { 2 | width: 50px; 3 | height: 18px; 4 | border: 1px currentColor solid; 5 | border-radius: 4px; 6 | background: linear-gradient(-60deg, transparent 0%, transparent 50%, currentColor 50%, currentColor 75%, transparent 75%, transparent); 7 | background-size: 20px 30px; 8 | background-position: 0px 0px; 9 | -webkit-animation: skLoadBar 0.8s infinite linear; 10 | animation: skLoadBar 0.8s infinite linear; 11 | } 12 | @-webkit-keyframes skLoadBar { 13 | from { background-position: 0px 0px; } 14 | to { background-position: -20px 0px; } 15 | } 16 | @keyframes skLoadBar { 17 | from { background-position: 0px 0px; } 18 | to { background-position: -20px 0px; } 19 | } 20 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <%= htmlWebpackPlugin.options.title %> 11 | 12 | 13 | 14 | 15 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/css/circle-solid-spin.css: -------------------------------------------------------------------------------- 1 | .sk-circle-solid-spin { 2 | display: inline-block; 3 | transform: translateZ(1px); 4 | } 5 | 6 | .sk-circle-solid-spin > div { 7 | display: inline-block; 8 | width: 51px; 9 | height: 51px; 10 | margin: 6px; 11 | border-radius: 50%; 12 | animation: sk-circle-solid-spin 2.4s cubic-bezier(0, 0.2, 0.8, 1) infinite; 13 | } 14 | 15 | @keyframes sk-circle-solid-spin { 16 | 0%, 100% { 17 | animation-timing-function: cubic-bezier(0.5, 0, 1, 0.5); 18 | } 19 | 0% { 20 | transform: rotateY(0deg); 21 | } 22 | 50% { 23 | transform: rotateY(1800deg); 24 | animation-timing-function: cubic-bezier(0, 0.5, 0.5, 1); 25 | } 26 | 100% { 27 | transform: rotateY(3600deg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/css/facebook.css: -------------------------------------------------------------------------------- 1 | .sk-facebook { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-facebook div { 8 | display: inline-block; 9 | position: absolute; 10 | left: 6px; 11 | width: 13px; 12 | background: currentColor; 13 | animation: sk-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite; 14 | } 15 | .sk-facebook div:nth-child(1) { 16 | left: 6px; 17 | animation-delay: -0.24s; 18 | } 19 | .sk-facebook div:nth-child(2) { 20 | left: 26px; 21 | animation-delay: -0.12s; 22 | } 23 | .sk-facebook div:nth-child(3) { 24 | left: 45px; 25 | animation-delay: 0; 26 | } 27 | @keyframes sk-facebook { 28 | 0% { 29 | top: 6px; 30 | height: 51px; 31 | } 32 | 50%, 100% { 33 | top: 19px; 34 | height: 26px; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | node-version: [18.x, 20.x, 22.x] 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | cache: 'npm' 23 | - name: Install dependencies 24 | run: npm ci 25 | - name: Run ESLint 26 | run: npm run lint 27 | - name: Build library 28 | run: npm run build 29 | - name: Build example (for deploy) 30 | run: npm run build:example 31 | - name: Run smoke test 32 | run: npm test 33 | -------------------------------------------------------------------------------- /src/components/css/hourglass.css: -------------------------------------------------------------------------------- 1 | .sk-hourglass { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-hourglass:after { 8 | content: " "; 9 | display: block; 10 | border-radius: 50%; 11 | width: 0; 12 | height: 0; 13 | margin: 6px; 14 | box-sizing: border-box; 15 | border: 26px solid currentColor; 16 | border-color: currentColor transparent currentColor transparent; 17 | animation: sk-hourglass 1.2s infinite; 18 | } 19 | @keyframes sk-hourglass { 20 | 0% { 21 | transform: rotate(0); 22 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 23 | } 24 | 50% { 25 | transform: rotate(900deg); 26 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 27 | } 28 | 100% { 29 | transform: rotate(1800deg); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/css/clock.css: -------------------------------------------------------------------------------- 1 | .sk-clock { 2 | border: 1px currentColor solid; 3 | border-radius: 50%; 4 | position: relative; 5 | height: 30px; 6 | width: 30px; 7 | } 8 | .sk-clock:before { 9 | content:''; 10 | border-left: 1px currentColor solid; 11 | position: absolute; 12 | top: 2px; 13 | width: 1px; 14 | height: calc( 50% - 2px ); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | -ms-transform-origin: 0% 100%; 18 | -webkit-transform-origin: 0% 100%; 19 | transform-origin: 0% 100%; 20 | -webkit-animation: skClock 1s infinite linear; 21 | animation: skClock 1s infinite linear; 22 | } 23 | @-webkit-keyframes skClock { 24 | from { -webkit-transform: rotate(0deg); } 25 | to { -webkit-transform: rotate(359deg); } 26 | } 27 | @keyframes skClock { 28 | from { transform: rotate(0deg); } 29 | to { transform: rotate(359deg); } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/css/hydrogen.css: -------------------------------------------------------------------------------- 1 | .sk-hydrogen { 2 | position: relative; 3 | border: 1px currentColor solid; 4 | border-radius: 50%; 5 | -webkit-animation: skHydro 0.6s infinite linear; 6 | animation: skHydro 0.6s infinite linear; 7 | height: 30px; 8 | width: 30px; 9 | } 10 | .sk-hydrogen:before, .sk-hydrogen:after { 11 | content: ''; 12 | position: absolute; 13 | width: 10px; 14 | height: 10px; 15 | background-color: currentColor; 16 | border-radius: 50%; 17 | } 18 | .sk-hydrogen:before { 19 | top: calc( 50% - 5px ); 20 | left: calc( 50% - 5px ); 21 | } 22 | .sk-hydrogen:after { 23 | top: -1px; 24 | left: -1px; 25 | } 26 | @-webkit-keyframes skHydro { 27 | from { -webkit-transform: rotate(0deg); } 28 | to { -webkit-transform: rotate(359deg); } 29 | } 30 | @keyframes skHydro { 31 | from { transform: rotate(0deg); } 32 | to { transform: rotate(359deg); } 33 | } 34 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | // Modern PostCSS 8 plugins to replace deprecated ones 2 | const trimPlugin = () => { 3 | return { 4 | postcssPlugin: 'vue-scoped-trim', 5 | Once(root) { 6 | // Clean up empty rules and whitespace 7 | root.walkRules(rule => { 8 | if (rule.nodes && rule.nodes.length === 0) { 9 | rule.remove() 10 | } 11 | }) 12 | } 13 | } 14 | } 15 | trimPlugin.postcss = true 16 | 17 | const addIdPlugin = () => { 18 | return { 19 | postcssPlugin: 'vue-scoped-id', 20 | Rule() { 21 | // Scoped CSS functionality - handled by Vue SFC compiler 22 | // This plugin is mainly a placeholder to prevent deprecated warnings 23 | } 24 | } 25 | } 26 | addIdPlugin.postcss = true 27 | 28 | module.exports = { 29 | plugins: [ 30 | require('autoprefixer'), 31 | trimPlugin(), 32 | addIdPlugin() 33 | ] 34 | } -------------------------------------------------------------------------------- /src/components/css/ring.css: -------------------------------------------------------------------------------- 1 | .sk-ring { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-ring div { 8 | background: transparent; 9 | box-sizing: border-box; 10 | display: block; 11 | position: absolute; 12 | width: 51px; 13 | height: 51px; 14 | margin: 6px; 15 | border: 6px solid currentColor; 16 | border-radius: 50%; 17 | animation: sk-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; 18 | border-color: currentColor transparent transparent transparent; 19 | } 20 | .sk-ring div:nth-child(1) { 21 | animation-delay: -0.45s; 22 | } 23 | .sk-ring div:nth-child(2) { 24 | animation-delay: -0.3s; 25 | } 26 | .sk-ring div:nth-child(3) { 27 | animation-delay: -0.15s; 28 | } 29 | @keyframes sk-ring { 30 | 0% { 31 | transform: rotate(0deg); 32 | } 33 | 100% { 34 | transform: rotate(360deg); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/css/wordpress.css: -------------------------------------------------------------------------------- 1 | .sk-wordpress > div { 2 | width: 27px; 3 | height: 27px; 4 | background-color: currentColor; 5 | display: inline-block; 6 | border-radius: 27px; 7 | position: relative; 8 | 9 | -webkit-animation: sk-inner-circle 1s linear infinite; 10 | animation: sk-inner-circle 1s linear infinite; 11 | } 12 | 13 | .sk-wordpress > div::after { 14 | content: ''; 15 | display: block; 16 | background-color: #fff; 17 | width: 8px; 18 | height: 8px; 19 | position: absolute; 20 | border-radius: 8px; 21 | top: 5px; 22 | left: 5px; 23 | } 24 | 25 | @-webkit-keyframes sk-inner-circle { 26 | 0% { -webkit-transform: rotate(0); } 27 | 100% { -webkit-transform: rotate(360deg); } 28 | } 29 | 30 | @keyframes sk-inner-circle { 31 | 0% { transform: rotate(0); -webkit-transform:rotate(0); } 32 | 100% { transform: rotate(360deg); -webkit-transform:rotate(360deg); } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/css/double-bounce.css: -------------------------------------------------------------------------------- 1 | .sk-double-bounce { 2 | width: 27px; 3 | height: 27px; 4 | position: relative; 5 | } 6 | 7 | .sk-double-bounce > div { 8 | width: 100%; 9 | height: 100%; 10 | border-radius: 50%; 11 | background-color: currentColor; 12 | opacity: 0.6; 13 | position: absolute; 14 | top: 0; 15 | left: 0; 16 | 17 | -webkit-animation: sk-bounce 2.0s infinite ease-in-out; 18 | animation: sk-bounce 2.0s infinite ease-in-out; 19 | } 20 | 21 | .sk-double-bounce > div:last-child { 22 | -webkit-animation-delay: -1.0s; 23 | animation-delay: -1.0s; 24 | } 25 | 26 | @-webkit-keyframes sk-bounce { 27 | 0%, 100% { -webkit-transform: scale(0.0) } 28 | 50% { -webkit-transform: scale(1.0) } 29 | } 30 | 31 | @keyframes sk-bounce { 32 | 0%, 100% { 33 | transform: scale(0.0); 34 | -webkit-transform: scale(0.0); 35 | } 50% { 36 | transform: scale(1.0); 37 | -webkit-transform: scale(1.0); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/css/rotating-plane.css: -------------------------------------------------------------------------------- 1 | .sk-rotating-plane > div { 2 | width: 27px; 3 | height: 27px; 4 | background-color: currentColor; 5 | 6 | -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out; 7 | animation: sk-rotateplane 1.2s infinite ease-in-out; 8 | } 9 | 10 | @-webkit-keyframes sk-rotateplane { 11 | 0% { -webkit-transform: perspective(120px) } 12 | 50% { -webkit-transform: perspective(120px) rotateY(180deg) } 13 | 100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) } 14 | } 15 | 16 | @keyframes sk-rotateplane { 17 | 0% { 18 | transform: perspective(120px) rotateX(0deg) rotateY(0deg); 19 | -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg); 20 | } 50% { 21 | transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 22 | -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 23 | } 100% { 24 | transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 25 | -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue2' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()], 6 | css: { 7 | postcss: { 8 | plugins: [ 9 | require('autoprefixer') 10 | ] 11 | } 12 | }, 13 | build: { 14 | outDir: 'build', 15 | minify: 'terser', 16 | terserOptions: { 17 | compress: { 18 | drop_console: true, 19 | drop_debugger: true, 20 | pure_funcs: ['console.log'] 21 | } 22 | }, 23 | lib: { 24 | entry: 'src/index.js', 25 | name: 'VueSpinkit', 26 | fileName: 'vue-spinkit.common', 27 | formats: ['umd'] 28 | }, 29 | rollupOptions: { 30 | external: ['vue'], 31 | output: { 32 | inlineDynamicImports: true, 33 | // force a single filename for the library bundle so it matches package.json "main" 34 | entryFileNames: 'vue-spinkit.common.js', 35 | exports: 'named', 36 | globals: { 37 | vue: 'Vue' 38 | } 39 | } 40 | }, 41 | cssCodeSplit: false 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Pongsatorn 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. -------------------------------------------------------------------------------- /src/components/css/three-bounce.css: -------------------------------------------------------------------------------- 1 | .sk-three-bounce { 2 | height: 18px; 3 | } 4 | 5 | .sk-three-bounce > div { 6 | width: 18px; 7 | height: 18px; 8 | background-color: currentColor; 9 | border-radius: 100%; 10 | display: inline-block; 11 | 12 | -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out; 13 | animation: sk-bouncedelay 1.4s infinite ease-in-out; 14 | /* Prevent first frame from flickering when animation starts */ 15 | -webkit-animation-fill-mode: both; 16 | animation-fill-mode: both; 17 | } 18 | 19 | .sk-three-bounce > div:first-child { 20 | -webkit-animation-delay: -0.32s; 21 | animation-delay: -0.32s; 22 | } 23 | 24 | .sk-three-bounce > div:nth-child(2) { 25 | -webkit-animation-delay: -0.16s; 26 | animation-delay: -0.16s; 27 | } 28 | 29 | @-webkit-keyframes sk-bouncedelay { 30 | 0%, 80%, 100% { -webkit-transform: scale(0.0) } 31 | 40% { -webkit-transform: scale(1.0) } 32 | } 33 | 34 | @keyframes sk-bouncedelay { 35 | 0%, 80%, 100% { 36 | transform: scale(0.0); 37 | -webkit-transform: scale(0.0); 38 | } 40% { 39 | transform: scale(1.0); 40 | -webkit-transform: scale(1.0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/css/heart.css: -------------------------------------------------------------------------------- 1 | .sk-heart { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | transform: rotate(45deg); 7 | transform-origin: 32px 32px; 8 | } 9 | .sk-heart div { 10 | top: 23px; 11 | left: 19px; 12 | position: absolute; 13 | width: 26px; 14 | height: 26px; 15 | background: currentColor; 16 | animation: sk-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1); 17 | } 18 | .sk-heart div:after, 19 | .sk-heart div:before { 20 | content: " "; 21 | position: absolute; 22 | display: block; 23 | width: 26px; 24 | height: 26px; 25 | background: currentColor; 26 | } 27 | .sk-heart div:before { 28 | left: -17px; 29 | border-radius: 50% 0 0 50%; 30 | } 31 | .sk-heart div:after { 32 | top: -17px; 33 | border-radius: 50% 50% 0 0; 34 | } 35 | @keyframes sk-heart { 36 | 0% { 37 | transform: scale(0.95); 38 | } 39 | 5% { 40 | transform: scale(1.1); 41 | } 42 | 39% { 43 | transform: scale(0.85); 44 | } 45 | 45% { 46 | transform: scale(1); 47 | } 48 | 60% { 49 | transform: scale(0.95); 50 | } 51 | 100% { 52 | transform: scale(0.9); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/css/ellipsis.css: -------------------------------------------------------------------------------- 1 | .sk-ellipsis { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-ellipsis div { 8 | position: absolute; 9 | top: 27px; 10 | width: 11px; 11 | height: 11px; 12 | border-radius: 50%; 13 | animation-timing-function: cubic-bezier(0, 1, 1, 0); 14 | } 15 | .sk-ellipsis div:nth-child(1) { 16 | left: 6px; 17 | animation: sk-ellipsis1 0.6s infinite; 18 | } 19 | .sk-ellipsis div:nth-child(2) { 20 | left: 6px; 21 | animation: sk-ellipsis2 0.6s infinite; 22 | } 23 | .sk-ellipsis div:nth-child(3) { 24 | left: 26px; 25 | animation: sk-ellipsis2 0.6s infinite; 26 | } 27 | .sk-ellipsis div:nth-child(4) { 28 | left: 45px; 29 | animation: sk-ellipsis3 0.6s infinite; 30 | } 31 | @keyframes sk-ellipsis1 { 32 | 0% { 33 | transform: scale(0); 34 | } 35 | 100% { 36 | transform: scale(1); 37 | } 38 | } 39 | @keyframes sk-ellipsis3 { 40 | 0% { 41 | transform: scale(1); 42 | } 43 | 100% { 44 | transform: scale(0); 45 | } 46 | } 47 | @keyframes sk-ellipsis2 { 48 | 0% { 49 | transform: translate(0, 0); 50 | } 51 | 100% { 52 | transform: translate(19px, 0); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/css/wave.css: -------------------------------------------------------------------------------- 1 | .sk-wave { 2 | width: 50px; 3 | height: 40px; 4 | text-align: center; 5 | font-size: 10px; 6 | } 7 | 8 | .sk-wave > div { 9 | background-color: currentColor; 10 | height: 100%; 11 | width: 6px; 12 | margin: 0 3px 0 0; 13 | display: inline-block; 14 | 15 | -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; 16 | animation: sk-stretchdelay 1.2s infinite ease-in-out; 17 | } 18 | 19 | .sk-wave > div:nth-child(2) { 20 | -webkit-animation-delay: -1.1s; 21 | animation-delay: -1.1s; 22 | } 23 | 24 | .sk-wave > div:nth-child(3) { 25 | -webkit-animation-delay: -1.0s; 26 | animation-delay: -1.0s; 27 | } 28 | 29 | .sk-wave > div:nth-child(4) { 30 | -webkit-animation-delay: -0.9s; 31 | animation-delay: -0.9s; 32 | } 33 | 34 | .sk-wave > div:nth-child(5) { 35 | -webkit-animation-delay: -0.8s; 36 | animation-delay: -0.8s; 37 | } 38 | 39 | @-webkit-keyframes sk-stretchdelay { 40 | 0%, 40%, 100% { -webkit-transform: scaleY(0.4) } 41 | 20% { -webkit-transform: scaleY(1.0) } 42 | } 43 | 44 | @keyframes sk-stretchdelay { 45 | 0%, 40%, 100% { 46 | transform: scaleY(0.4); 47 | -webkit-transform: scaleY(0.4); 48 | } 20% { 49 | transform: scaleY(1.0); 50 | -webkit-transform: scaleY(1.0); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/css/chasing-dots.css: -------------------------------------------------------------------------------- 1 | .sk-chasing-dots { 2 | width: 27px; 3 | height: 27px; 4 | position: relative; 5 | 6 | -webkit-animation: sk-rotate 2.0s infinite linear; 7 | animation: sk-rotate 2.0s infinite linear; 8 | } 9 | 10 | .sk-chasing-dots > div { 11 | width: 60%; 12 | height: 60%; 13 | display: inline-block; 14 | position: absolute; 15 | top: 0; 16 | background-color: currentColor; 17 | border-radius: 100%; 18 | 19 | -webkit-animation: sk-bounce 2.0s infinite ease-in-out; 20 | animation: sk-bounce 2.0s infinite ease-in-out; 21 | } 22 | 23 | .sk-chasing-dots > div:last-child { 24 | top: auto; 25 | bottom: 0; 26 | 27 | -webkit-animation-delay: -1.0s; 28 | animation-delay: -1.0s; 29 | } 30 | 31 | @-webkit-keyframes sk-rotate { 100% { -webkit-transform: rotate(360deg) }} 32 | @keyframes sk-rotate { 33 | 100% { 34 | transform: rotate(360deg); 35 | -webkit-transform: rotate(360deg); 36 | } 37 | } 38 | 39 | @-webkit-keyframes sk-bounce { 40 | 0%, 100% { -webkit-transform: scale(0.0) } 41 | 50% { -webkit-transform: scale(1.0) } 42 | } 43 | 44 | @keyframes sk-bounce { 45 | 0%, 100% { 46 | transform: scale(0.0); 47 | -webkit-transform: scale(0.0); 48 | } 50% { 49 | transform: scale(1.0); 50 | -webkit-transform: scale(1.0); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/css/grid.css: -------------------------------------------------------------------------------- 1 | .sk-grid { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-grid div { 8 | position: absolute; 9 | width: 13px; 10 | height: 13px; 11 | border-radius: 50%; 12 | animation: sk-grid 1.2s linear infinite; 13 | } 14 | .sk-grid div:nth-child(1) { 15 | top: 6px; 16 | left: 6px; 17 | animation-delay: 0s; 18 | } 19 | .sk-grid div:nth-child(2) { 20 | top: 6px; 21 | left: 26px; 22 | animation-delay: -0.4s; 23 | } 24 | .sk-grid div:nth-child(3) { 25 | top: 6px; 26 | left: 45px; 27 | animation-delay: -0.8s; 28 | } 29 | .sk-grid div:nth-child(4) { 30 | top: 26px; 31 | left: 6px; 32 | animation-delay: -0.4s; 33 | } 34 | .sk-grid div:nth-child(5) { 35 | top: 26px; 36 | left: 26px; 37 | animation-delay: -0.8s; 38 | } 39 | .sk-grid div:nth-child(6) { 40 | top: 26px; 41 | left: 45px; 42 | animation-delay: -1.2s; 43 | } 44 | .sk-grid div:nth-child(7) { 45 | top: 45px; 46 | left: 6px; 47 | animation-delay: -0.8s; 48 | } 49 | .sk-grid div:nth-child(8) { 50 | top: 45px; 51 | left: 26px; 52 | animation-delay: -1.2s; 53 | } 54 | .sk-grid div:nth-child(9) { 55 | top: 45px; 56 | left: 45px; 57 | animation-delay: -1.6s; 58 | } 59 | @keyframes sk-grid { 60 | 0%, 100% { 61 | opacity: 1; 62 | } 63 | 50% { 64 | opacity: 0.5; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/css/fade-in.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes sk-fade-in { 2 | 0% { 3 | opacity: 0; 4 | } 5 | 50% { 6 | opacity: 0; 7 | } 8 | 100% { 9 | opacity: 1; 10 | } 11 | } 12 | 13 | @-moz-keyframes sk-fade-in { 14 | 0% { 15 | opacity: 0; 16 | } 17 | 50% { 18 | opacity: 0; 19 | } 20 | 100% { 21 | opacity: 1; 22 | } 23 | } 24 | 25 | @-ms-keyframes sk-fade-in { 26 | 0% { 27 | opacity: 0; 28 | } 29 | 50% { 30 | opacity: 0; 31 | } 32 | 100% { 33 | opacity: 1; 34 | } 35 | } 36 | 37 | @keyframes sk-fade-in { 38 | 0% { 39 | opacity: 0; 40 | } 41 | 50% { 42 | opacity: 0; 43 | } 44 | 100% { 45 | opacity: 1; 46 | } 47 | } 48 | 49 | .sk-fade-in { 50 | -webkit-animation: sk-fade-in 2s; 51 | -moz-animation: sk-fade-in 2s; 52 | -o-animation: sk-fade-in 2s; 53 | -ms-animation: sk-fade-in 2s; 54 | animation: sk-fade-in 2s; 55 | } 56 | 57 | .sk-fade-in-half-second { 58 | -webkit-animation: sk-fade-in 1s; 59 | -moz-animation: sk-fade-in 1s; 60 | -o-animation: sk-fade-in 1s; 61 | -ms-animation: sk-fade-in 1s; 62 | animation: sk-fade-in 1s; 63 | } 64 | 65 | .sk-fade-in-quarter-second { 66 | -webkit-animation: sk-fade-in 0.5s; 67 | -moz-animation: sk-fade-in 0.5s; 68 | -o-animation: sk-fade-in 0.5s; 69 | -ms-animation: sk-fade-in 0.5s; 70 | animation: sk-fade-in 0.5s; 71 | } 72 | -------------------------------------------------------------------------------- /src/components/css/circle-fade.css: -------------------------------------------------------------------------------- 1 | .sk-circle-fade { 2 | font-size: 10px; 3 | text-indent: -9999em; 4 | width: 32px; 5 | height: 32px; 6 | border-radius: 50%; 7 | background: currentColor; 8 | background: linear-gradient(to right, currentColor 10%, rgba(255, 255, 255, 0) 42%); 9 | position: relative; 10 | -webkit-animation: circleRotate 1.4s infinite linear; 11 | animation: circleRotate 1.4s infinite linear; 12 | -webkit-transform: translateZ(0); 13 | -ms-transform: translateZ(0); 14 | transform: translateZ(0); 15 | } 16 | .sk-circle-fade:before { 17 | width: 50%; 18 | height: 50%; 19 | background: currentColor; 20 | border-radius: 100% 0 0 0; 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | content: ''; 25 | } 26 | .sk-circle-fade:after { 27 | background: #fff; 28 | width: 75%; 29 | height: 75%; 30 | border-radius: 50%; 31 | content: ''; 32 | margin: auto; 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | bottom: 0; 37 | right: 0; 38 | } 39 | @-webkit-keyframes circleRotate { 40 | 0% { 41 | -webkit-transform: rotate(0deg); 42 | transform: rotate(0deg); 43 | } 44 | 100% { 45 | -webkit-transform: rotate(360deg); 46 | transform: rotate(360deg); 47 | } 48 | } 49 | @keyframes circleRotate { 50 | 0% { 51 | -webkit-transform: rotate(0deg); 52 | transform: rotate(0deg); 53 | } 54 | 100% { 55 | -webkit-transform: rotate(360deg); 56 | transform: rotate(360deg); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/smoke.js: -------------------------------------------------------------------------------- 1 | // Simple smoke test to verify the built library can be loaded 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | console.log('🧪 Running smoke test...'); 6 | 7 | // Check if build files exist 8 | const buildDir = path.join(__dirname, '..', 'build'); 9 | const jsFile = path.join(buildDir, 'vue-spinkit.common.js'); 10 | 11 | if (!fs.existsSync(jsFile)) { 12 | console.error('❌ Built JavaScript file not found:', jsFile); 13 | process.exit(1); 14 | } 15 | 16 | // A separate CSS file is optional because the library may inject CSS into the JS bundle. 17 | // If present, we'll report its size; if not, that's fine. 18 | const cssFile = path.join(buildDir, 'style.css'); 19 | 20 | // Check if the JS file can be required 21 | try { 22 | const VueSpinkit = require(jsFile); 23 | if (VueSpinkit && (VueSpinkit.default || VueSpinkit.Spinner)) { 24 | console.log('✅ Built library loads successfully'); 25 | console.log('✅ JS file size:', (fs.statSync(jsFile).size / 1024).toFixed(2), 'KB'); 26 | if (fs.existsSync(cssFile)) { 27 | console.log('ℹ️ Found separate CSS file. Size:', (fs.statSync(cssFile).size / 1024).toFixed(2), 'KB'); 28 | } else { 29 | console.log('ℹ️ No separate CSS file found (styles may be injected by the JS bundle)'); 30 | } 31 | } else { 32 | console.error('❌ Built library does not export expected components'); 33 | process.exit(1); 34 | } 35 | } catch (error) { 36 | console.error('❌ Failed to load built library:', error.message); 37 | process.exit(1); 38 | } 39 | 40 | console.log('🎉 Smoke test passed!'); -------------------------------------------------------------------------------- /src/components/css/loaders-css.css: -------------------------------------------------------------------------------- 1 | .ball-triangle-path > div, 2 | .ball-scale-ripple-multiple > div, 3 | .ball-scale-ripple > div { 4 | background-color: initial; 5 | border-color: currentColor; 6 | } 7 | 8 | .ball-clip-rotate > div { 9 | background-color: initial; 10 | border-top-color: currentColor; 11 | border-right-color: currentColor; 12 | border-left-color: currentColor; 13 | } 14 | 15 | .ball-clip-rotate-pulse > div:first-child { 16 | background-color: currentColor; 17 | } 18 | .ball-clip-rotate-pulse > div:last-child { 19 | background-color: initial; 20 | border-top-color: currentColor; 21 | border-bottom-color: currentColor; 22 | } 23 | 24 | .ball-clip-rotate-multiple > div:first-child { 25 | background-color: initial; 26 | border-right-color: currentColor; 27 | border-left-color: currentColor; 28 | } 29 | .ball-clip-rotate-multiple > div:last-child { 30 | background-color: initial; 31 | border-top-color: currentColor; 32 | border-bottom-color: currentColor; 33 | } 34 | 35 | .triangle-skew-spin > div { 36 | background-color: initial; 37 | border-bottom-color: currentColor; 38 | } 39 | 40 | .pacman > div:nth-child(1), 41 | .pacman > div:nth-child(2) { 42 | background-color: initial; 43 | border-top-color: currentColor; 44 | border-left-color: currentColor; 45 | border-bottom-color: currentColor; 46 | } 47 | 48 | .pacman > div:nth-child(3), 49 | .pacman > div:nth-child(4), 50 | .pacman > div:nth-child(5) { 51 | background-color: currentColor; 52 | } 53 | 54 | .square-spin > div { 55 | background: currentColor; 56 | border-color: currentColor; 57 | } 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-spinkit", 3 | "version": "2.1.5", 4 | "description": "A collection of loading indicators animated with CSS for VueJS", 5 | "author": "Chanwit Piromplad ", 6 | "scripts": { 7 | "serve": "vite", 8 | "dev": "vite", 9 | "build": "vite build", 10 | "build:example": "vite build --config vite.example.config.js", 11 | "deploy:surge": "surge dist vue-spinkit.surge.sh", 12 | "lint": "eslint --ext .js,.vue src", 13 | "test": "node test/smoke.js" 14 | }, 15 | "main": "build/vue-spinkit.common.js", 16 | "files": [ 17 | "build/vue-spinkit.common.js", 18 | "README.md", 19 | "LICENSE" 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/TonPC64/vue-spinkit.git" 24 | }, 25 | "homepage": "http://vue-spinkit.surge.sh", 26 | "keywords": [ 27 | "spinkit", 28 | "vue-spinkit", 29 | "loading", 30 | "vue-loading" 31 | ], 32 | "devDependencies": { 33 | "@babel/core": "^7.23.6", 34 | "@babel/eslint-parser": "^7.23.6", 35 | "@babel/preset-env": "^7.23.6", 36 | "@vitejs/plugin-vue2": "^2.3.3", 37 | "autoprefixer": "^10.4.21", 38 | "eslint": "^8.57.1", 39 | "eslint-plugin-vue": "^9.33.0", 40 | "prismjs": "^1.25.0", 41 | "randomcolor": "^0.6.2", 42 | "terser": "^5.44.0", 43 | "vite": "^6.3.6", 44 | "vue": "^2.7.16", 45 | "vue-template-compiler": "^2.7.16" 46 | }, 47 | "engines": { 48 | "node": ">=16" 49 | }, 50 | "browserslist": [ 51 | "> 1%", 52 | "last 2 versions", 53 | "not dead" 54 | ], 55 | "license": "MIT" 56 | } 57 | -------------------------------------------------------------------------------- /src/components/css/cube-grid.css: -------------------------------------------------------------------------------- 1 | .sk-cube-grid { 2 | width: 39px; 3 | height: 39px; 4 | } 5 | 6 | .sk-cube-grid > div { 7 | width: 33%; 8 | height: 33%; 9 | background-color: currentColor; 10 | float: left; 11 | 12 | 13 | -webkit-animation: sk-scaleDelay 1.3s infinite ease-in-out; 14 | animation: sk-scaleDelay 1.3s infinite ease-in-out; 15 | } 16 | 17 | /* 18 | * Spinner positions 19 | * 1 2 3 20 | * 4 5 6 21 | * 7 8 9 22 | */ 23 | 24 | .sk-cube-grid > div:nth-child(1) { -webkit-animation-delay: 0.2s; animation-delay: 0.2s } 25 | .sk-cube-grid > div:nth-child(2) { -webkit-animation-delay: 0.3s; animation-delay: 0.3s } 26 | .sk-cube-grid > div:nth-child(3) { -webkit-animation-delay: 0.4s; animation-delay: 0.4s } 27 | .sk-cube-grid > div:nth-child(4) { -webkit-animation-delay: 0.1s; animation-delay: 0.1s } 28 | .sk-cube-grid > div:nth-child(5) { -webkit-animation-delay: 0.2s; animation-delay: 0.2s } 29 | .sk-cube-grid > div:nth-child(6) { -webkit-animation-delay: 0.3s; animation-delay: 0.3s } 30 | .sk-cube-grid > div:nth-child(7) { -webkit-animation-delay: 0.0s; animation-delay: 0.0s } 31 | .sk-cube-grid > div:nth-child(8) { -webkit-animation-delay: 0.1s; animation-delay: 0.1s } 32 | .sk-cube-grid > div:nth-child(9) { -webkit-animation-delay: 0.2s; animation-delay: 0.2s } 33 | 34 | @-webkit-keyframes sk-scaleDelay { 35 | 0%, 70%, 100% { -webkit-transform:scale3D(1.0, 1.0, 1.0) } 36 | 35% { -webkit-transform:scale3D(0.0, 0.0, 1.0) } 37 | } 38 | 39 | @keyframes sk-scaleDelay { 40 | 0%, 70%, 100% { -webkit-transform:scale3D(1.0, 1.0, 1.0); transform:scale3D(1.0, 1.0, 1.0) } 41 | 35% { -webkit-transform:scale3D(0.0, 0.0, 1.0); transform:scale3D(0.0, 0.0, 1.0) } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/css/wandering-cubes.css: -------------------------------------------------------------------------------- 1 | .sk-wandering-cubes { 2 | width: 52px; 3 | height: 52px; 4 | position: relative; 5 | } 6 | 7 | .sk-wandering-cubes > div { 8 | background-color: currentColor; 9 | width: 10px; 10 | height: 10px; 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | 15 | -webkit-animation: sk-cubemove 1.8s infinite ease-in-out; 16 | animation: sk-cubemove 1.8s infinite ease-in-out; 17 | } 18 | 19 | .sk-wandering-cubes > div:last-child { 20 | -webkit-animation-delay: -0.9s; 21 | animation-delay: -0.9s; 22 | } 23 | 24 | @-webkit-keyframes sk-cubemove { 25 | 25% { -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5) } 26 | 50% { -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg) } 27 | 75% { -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5) } 28 | 100% { -webkit-transform: rotate(-360deg) } 29 | } 30 | 31 | @keyframes sk-cubemove { 32 | 25% { 33 | transform: translateX(42px) rotate(-90deg) scale(0.5); 34 | -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5); 35 | } 50% { 36 | /* Hack to make FF rotate in the right direction */ 37 | transform: translateX(42px) translateY(42px) rotate(-179deg); 38 | -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg); 39 | } 50.1% { 40 | transform: translateX(42px) translateY(42px) rotate(-180deg); 41 | -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg); 42 | } 75% { 43 | transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5); 44 | -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5); 45 | } 100% { 46 | transform: rotate(-360deg); 47 | -webkit-transform: rotate(-360deg); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/css/roller.css: -------------------------------------------------------------------------------- 1 | .sk-roller { 2 | display: inline-block; 3 | position: relative; 4 | width: 64px; 5 | height: 64px; 6 | } 7 | .sk-roller div { 8 | animation: sk-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; 9 | transform-origin: 32px 32px; 10 | } 11 | .sk-roller div:after { 12 | content: " "; 13 | display: block; 14 | position: absolute; 15 | width: 6px; 16 | height: 6px; 17 | border-radius: 50%; 18 | background: currentColor; 19 | margin: -3px 0 0 -3px; 20 | } 21 | .sk-roller div:nth-child(1) { 22 | animation-delay: -0.036s; 23 | } 24 | .sk-roller div:nth-child(1):after { 25 | top: 50px; 26 | left: 50px; 27 | } 28 | .sk-roller div:nth-child(2) { 29 | animation-delay: -0.072s; 30 | } 31 | .sk-roller div:nth-child(2):after { 32 | top: 54px; 33 | left: 45px; 34 | } 35 | .sk-roller div:nth-child(3) { 36 | animation-delay: -0.108s; 37 | } 38 | .sk-roller div:nth-child(3):after { 39 | top: 57px; 40 | left: 39px; 41 | } 42 | .sk-roller div:nth-child(4) { 43 | animation-delay: -0.144s; 44 | } 45 | .sk-roller div:nth-child(4):after { 46 | top: 58px; 47 | left: 32px; 48 | } 49 | .sk-roller div:nth-child(5) { 50 | animation-delay: -0.18s; 51 | } 52 | .sk-roller div:nth-child(5):after { 53 | top: 57px; 54 | left: 25px; 55 | } 56 | .sk-roller div:nth-child(6) { 57 | animation-delay: -0.216s; 58 | } 59 | .sk-roller div:nth-child(6):after { 60 | top: 54px; 61 | left: 19px; 62 | } 63 | .sk-roller div:nth-child(7) { 64 | animation-delay: -0.252s; 65 | } 66 | .sk-roller div:nth-child(7):after { 67 | top: 50px; 68 | left: 14px; 69 | } 70 | .sk-roller div:nth-child(8) { 71 | animation-delay: -0.288s; 72 | } 73 | .sk-roller div:nth-child(8):after { 74 | top: 45px; 75 | left: 10px; 76 | } 77 | @keyframes sk-roller { 78 | 0% { 79 | transform: rotate(0deg); 80 | } 81 | 100% { 82 | transform: rotate(360deg); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/components/css/moon.css: -------------------------------------------------------------------------------- 1 | .sk-moon { 2 | position: relative; 3 | width: 50px; 4 | height: 50px; 5 | overflow: hidden; 6 | margin:0px auto; 7 | } 8 | 9 | .sk-moon > div { 10 | margin: auto; 11 | position: absolute; 12 | top: 0; 13 | right: 0; 14 | bottom: 0; 15 | left: 0; 16 | width: 32px; 17 | height: 32px; 18 | background-color: transparent; 19 | box-sizing: border-box; 20 | -o-box-sizing: border-box; 21 | -ms-box-sizing: border-box; 22 | -webkit-box-sizing: border-box; 23 | -moz-box-sizing: border-box; 24 | box-shadow: 0 0 8px 1px currentColor; 25 | -o-box-shadow: 0 0 8px 1px currentColor; 26 | -ms-box-shadow: 0 0 8px 1px currentColor; 27 | -webkit-box-shadow: 0 0 8px 1px currentColor; 28 | -moz-box-shadow: 0 0 8px 1px currentColor; 29 | border-bottom: 10px solid currentColor; 30 | border-radius: 50%; 31 | -o-border-radius: 50%; 32 | -ms-border-radius: 50%; 33 | -webkit-border-radius: 50%; 34 | -moz-border-radius: 50%; 35 | animation: spin 1.15s ease infinite; 36 | -o-animation: spin 1.15s ease infinite; 37 | -ms-animation: spin 1.15s ease infinite; 38 | -webkit-animation: spin 1.15s ease infinite; 39 | -moz-animation: spin 1.15s ease infinite; 40 | } 41 | 42 | 43 | @keyframes spin { 44 | from { 45 | transform: rotate(0deg); 46 | } 47 | to { 48 | transform: rotate(360deg); 49 | } 50 | } 51 | 52 | @-o-keyframes spin { 53 | from { 54 | -o-transform: rotate(0deg); 55 | } 56 | to { 57 | -o-transform: rotate(360deg); 58 | } 59 | } 60 | 61 | @-ms-keyframes spin { 62 | from { 63 | -ms-transform: rotate(0deg); 64 | } 65 | to { 66 | -ms-transform: rotate(360deg); 67 | } 68 | } 69 | 70 | @-webkit-keyframes spin { 71 | from { 72 | -webkit-transform: rotate(0deg); 73 | } 74 | to { 75 | -webkit-transform: rotate(360deg); 76 | } 77 | } 78 | 79 | @-moz-keyframes spin { 80 | from { 81 | -moz-transform: rotate(0deg); 82 | } 83 | to { 84 | -moz-transform: rotate(360deg); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/Spinner.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 84 | -------------------------------------------------------------------------------- /src/components/css/folding-cube.css: -------------------------------------------------------------------------------- 1 | .sk-folding-cube { 2 | width: 40px; 3 | height: 40px; 4 | position: relative; 5 | 6 | -webkit-transform: rotateZ(45deg); 7 | transform: rotateZ(45deg); 8 | } 9 | 10 | .sk-folding-cube > div { 11 | background-color: initial; 12 | float: left; 13 | width: 50%; 14 | height: 50%; 15 | position: relative; 16 | 17 | -webkit-transform: scale(1.1); 18 | -ms-transform: scale(1.1); 19 | transform: scale(1.1); 20 | } 21 | .sk-folding-cube > div::before { 22 | content: ''; 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | width: 100%; 27 | height: 100%; 28 | background-color: currentColor; 29 | 30 | -webkit-animation: sk-foldCubeAngle 2.4s infinite linear both; 31 | animation: sk-foldCubeAngle 2.4s infinite linear both; 32 | -webkit-transform-origin: 100% 100%; 33 | -ms-transform-origin: 100% 100%; 34 | transform-origin: 100% 100%; 35 | } 36 | .sk-folding-cube > div:nth-child(2) { 37 | -webkit-transform: scale(1.1) rotateZ(90deg); 38 | transform: scale(1.1) rotateZ(90deg); 39 | } 40 | .sk-folding-cube > div:nth-child(4) { 41 | -webkit-transform: scale(1.1) rotateZ(180deg); 42 | transform: scale(1.1) rotateZ(180deg); 43 | } 44 | .sk-folding-cube > div:nth-child(3) { 45 | -webkit-transform: scale(1.1) rotateZ(270deg); 46 | transform: scale(1.1) rotateZ(270deg); 47 | } 48 | .sk-folding-cube > div:nth-child(2)::before { 49 | -webkit-animation-delay: 0.3s; 50 | animation-delay: 0.3s; 51 | } 52 | .sk-folding-cube > div:nth-child(4)::before { 53 | -webkit-animation-delay: 0.6s; 54 | animation-delay: 0.6s; 55 | } 56 | .sk-folding-cube > div:nth-child(3)::before { 57 | -webkit-animation-delay: 0.9s; 58 | animation-delay: 0.9s; 59 | } 60 | @-webkit-keyframes sk-foldCubeAngle { 61 | 0%, 10% { 62 | -webkit-transform: perspective(140px) rotateX(-180deg); 63 | transform: perspective(140px) rotateX(-180deg); 64 | opacity: 0; 65 | } 25%, 75% { 66 | -webkit-transform: perspective(140px) rotateX(0deg); 67 | transform: perspective(140px) rotateX(0deg); 68 | opacity: 1; 69 | } 90%, 100% { 70 | -webkit-transform: perspective(140px) rotateY(180deg); 71 | transform: perspective(140px) rotateY(180deg); 72 | opacity: 0; 73 | } 74 | } 75 | 76 | @keyframes sk-foldCubeAngle { 77 | 0%, 10% { 78 | -webkit-transform: perspective(140px) rotateX(-180deg); 79 | transform: perspective(140px) rotateX(-180deg); 80 | opacity: 0; 81 | } 25%, 75% { 82 | -webkit-transform: perspective(140px) rotateX(0deg); 83 | transform: perspective(140px) rotateX(0deg); 84 | opacity: 1; 85 | } 90%, 100% { 86 | -webkit-transform: perspective(140px) rotateY(180deg); 87 | transform: perspective(140px) rotateY(180deg); 88 | opacity: 0; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/components/spinners.js: -------------------------------------------------------------------------------- 1 | const spinkitSpinners = { 2 | 'circle': { className: 'sk-circle', divCount: 12 }, 3 | 'cube-grid': { className: 'sk-cube-grid', divCount: 9 }, 4 | 'wave': { className: 'sk-wave', divCount: 5 }, 5 | 'folding-cube': { className: 'sk-folding-cube', divCount: 4 }, 6 | 'three-bounce': { className: 'sk-three-bounce', divCount: 3 }, 7 | 'double-bounce': { className: 'sk-double-bounce', divCount: 2 }, 8 | 'wandering-cubes': { className: 'sk-wandering-cubes', divCount: 2 }, 9 | 'chasing-dots': { className: 'sk-chasing-dots', divCount: 2 }, 10 | 'rotating-plane': { className: 'sk-rotating-plane', divCount: 1 }, 11 | 'pulse': { className: 'sk-pulse', divCount: 1 }, 12 | 'wordpress': { className: 'sk-wordpress', divCount: 1 }, 13 | 'fading-circle': { className: 'sk-fading-circle', divCount: 12 } 14 | } 15 | 16 | const loadersCssSpinners = { 17 | 'square-spin': { divCount: 1 }, 18 | 'ball-grid-beat': { divCount: 9 }, 19 | 'ball-grid-pulse': { divCount: 9 }, 20 | 'line-spin-fade-loader': { divCount: 8 }, 21 | 'ball-spin-fade-loader': { divCount: 8 }, 22 | 'ball-pulse-rise': { divCount: 5 }, 23 | 'line-scale': { divCount: 5 }, 24 | 'line-scale-pulse-out': { divCount: 5 }, 25 | 'line-scale-pulse-out-rapid': { divCount: 5 }, 26 | 'pacman': { divCount: 5 }, 27 | 'line-scale-party': { divCount: 4 }, 28 | 'ball-triangle-path': { divCount: 3 }, 29 | 'ball-scale-multiple': { divCount: 3 }, 30 | 'ball-scale-ripple-multiple': { divCount: 3 }, 31 | 'ball-pulse-sync': { divCount: 3 }, 32 | 'ball-pulse': { divCount: 3 }, 33 | 'ball-beat': { divCount: 3 }, 34 | 'ball-zig-zag': { divCount: 2 }, 35 | 'ball-zig-zag-deflect': { divCount: 2 }, 36 | 'ball-clip-rotate-pulse': { divCount: 2 }, 37 | 'ball-clip-rotate-multiple': { divCount: 2 }, 38 | 'ball-clip-rotate': { divCount: 1 }, 39 | 'ball-scale-ripple': { divCount: 1 }, 40 | 'triangle-skew-spin': { divCount: 1 } 41 | } 42 | 43 | const loadingIOSpinners = { 44 | 'circle-solid-spin': { className: 'sk-circle-solid-spin', divCount: 1 }, 45 | 'dual-ring': { className: 'sk-dual-ring', divCount: 0 }, 46 | 'facebook': { className: 'sk-facebook', divCount: 3 }, 47 | 'heart': { className: 'sk-heart', divCount: 1 }, 48 | 'ring': { className: 'sk-ring', divCount: 4 }, 49 | 'roller': { className: 'sk-roller', divCount: 8 }, 50 | 'ellipsis': { className: 'sk-ellipsis', divCount: 4 }, 51 | 'grid': { className: 'sk-grid', divCount: 9 }, 52 | 'hourglass': { className: 'sk-hourglass', divCount: 0 }, 53 | 'ripple': { className: 'sk-ripple', divCount: 2 } 54 | } 55 | 56 | const awesomeSpinners = { 57 | 'loadbar': { className: 'sk-loadbar', divCount: 0 }, 58 | 'hydrogen': { className: 'sk-hydrogen', divCount: 0 }, 59 | 'clock': { className: 'sk-clock', divCount: 0 }, 60 | 'circle-fade': { className: 'sk-circle-fade', divCount: 0 }, 61 | 'moon': { className: 'sk-moon', divCount: 1 } 62 | } 63 | 64 | export default { 65 | spinkitSpinners, 66 | loadersCssSpinners, 67 | loadingIOSpinners, 68 | awesomeSpinners, 69 | allSpinners: { 70 | ...spinkitSpinners, 71 | ...loadersCssSpinners, 72 | ...loadingIOSpinners, 73 | ...awesomeSpinners 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Library entrypoint for vue-spinkit 2 | import Spinner from './components/Spinner.vue' 3 | 4 | // Import CSS files as raw text and inject at runtime so Vite doesn't emit a separate CSS asset. 5 | // This keeps the final build as a single JS file containing both JS and CSS. 6 | import baseCss from './components/css/base.css?raw' 7 | import fadeInCss from './components/css/fade-in.css?raw' 8 | import rotatingPlaneCss from './components/css/rotating-plane.css?raw' 9 | import doubleBounceCss from './components/css/double-bounce.css?raw' 10 | import waveCss from './components/css/wave.css?raw' 11 | import wanderingCubesCss from './components/css/wandering-cubes.css?raw' 12 | import pulseCss from './components/css/pulse.css?raw' 13 | import chasingDotsCss from './components/css/chasing-dots.css?raw' 14 | import threeBounceCss from './components/css/three-bounce.css?raw' 15 | import circleCss from './components/css/circle.css?raw' 16 | import cubeGridCss from './components/css/cube-grid.css?raw' 17 | import fadingCircleCss from './components/css/fading-circle.css?raw' 18 | import foldingCubeCss from './components/css/folding-cube.css?raw' 19 | import wordpressCss from './components/css/wordpress.css?raw' 20 | import loadersCss from './components/css/loaders.css?raw' 21 | import loadersCssExtra from './components/css/loaders-css.css?raw' 22 | import circleSolidSpinCss from './components/css/circle-solid-spin.css?raw' 23 | import dualRingCss from './components/css/dual-ring.css?raw' 24 | import ellipsisCss from './components/css/ellipsis.css?raw' 25 | import facebookCss from './components/css/facebook.css?raw' 26 | import gridCss from './components/css/grid.css?raw' 27 | import heartCss from './components/css/heart.css?raw' 28 | import hourglassCss from './components/css/hourglass.css?raw' 29 | import ringCss from './components/css/ring.css?raw' 30 | import rippleCss from './components/css/ripple.css?raw' 31 | import rollerCss from './components/css/roller.css?raw' 32 | import clockCss from './components/css/clock.css?raw' 33 | import hydrogenCss from './components/css/hydrogen.css?raw' 34 | import loadbarCss from './components/css/loadbar.css?raw' 35 | import circleFadeCss from './components/css/circle-fade.css?raw' 36 | import moonCss from './components/css/moon.css?raw' 37 | 38 | const __injectedCss = [ 39 | baseCss, 40 | fadeInCss, 41 | rotatingPlaneCss, 42 | doubleBounceCss, 43 | waveCss, 44 | wanderingCubesCss, 45 | pulseCss, 46 | chasingDotsCss, 47 | threeBounceCss, 48 | circleCss, 49 | cubeGridCss, 50 | fadingCircleCss, 51 | foldingCubeCss, 52 | wordpressCss, 53 | loadersCss, 54 | loadersCssExtra, 55 | circleSolidSpinCss, 56 | dualRingCss, 57 | ellipsisCss, 58 | facebookCss, 59 | gridCss, 60 | heartCss, 61 | hourglassCss, 62 | ringCss, 63 | rippleCss, 64 | rollerCss, 65 | clockCss, 66 | hydrogenCss, 67 | loadbarCss, 68 | circleFadeCss, 69 | moonCss 70 | ].join('\n') 71 | 72 | if (typeof document !== 'undefined') { 73 | const style = document.createElement('style') 74 | style.setAttribute('data-vue-spinkit', '') 75 | style.appendChild(document.createTextNode(__injectedCss)) 76 | document.head.appendChild(style) 77 | } 78 | 79 | // For CommonJS build, export the component 80 | export { Spinner } 81 | export default Spinner 82 | -------------------------------------------------------------------------------- /src/components/css/circle.css: -------------------------------------------------------------------------------- 1 | .sk-circle { 2 | width: 40px; 3 | height: 40px; 4 | position: relative; 5 | } 6 | 7 | .sk-circle > div { 8 | background-color: initial; 9 | width: 100%; 10 | height: 100%; 11 | position: absolute; 12 | left: 0; 13 | top: 0; 14 | } 15 | 16 | .sk-circle > div::before { 17 | content: ''; 18 | display: block; 19 | margin: 0 auto; 20 | width: 20%; 21 | height: 20%; 22 | background-color: currentColor; 23 | border-radius: 100%; 24 | 25 | -webkit-animation: sk-bouncedelay 1.2s infinite ease-in-out; 26 | animation: sk-bouncedelay 1.2s infinite ease-in-out; 27 | /* Prevent first frame from flickering when animation starts */ 28 | -webkit-animation-fill-mode: both; 29 | animation-fill-mode: both; 30 | } 31 | 32 | .sk-circle > div:nth-child(2) { -webkit-transform: rotate(30deg); transform: rotate(30deg) } 33 | .sk-circle > div:nth-child(3) { -webkit-transform: rotate(60deg); transform: rotate(60deg) } 34 | .sk-circle > div:nth-child(4) { -webkit-transform: rotate(90deg); transform: rotate(90deg) } 35 | .sk-circle > div:nth-child(5) { -webkit-transform: rotate(120deg); transform: rotate(120deg) } 36 | .sk-circle > div:nth-child(6) { -webkit-transform: rotate(150deg); transform: rotate(150deg) } 37 | .sk-circle > div:nth-child(7) { -webkit-transform: rotate(180deg); transform: rotate(180deg) } 38 | .sk-circle > div:nth-child(8) { -webkit-transform: rotate(210deg); transform: rotate(210deg) } 39 | .sk-circle > div:nth-child(9) { -webkit-transform: rotate(240deg); transform: rotate(240deg) } 40 | .sk-circle > div:nth-child(10) { -webkit-transform: rotate(270deg); transform: rotate(270deg) } 41 | .sk-circle > div:nth-child(11) { -webkit-transform: rotate(300deg); transform: rotate(300deg) } 42 | .sk-circle > div:nth-child(12) { -webkit-transform: rotate(330deg); transform: rotate(330deg) } 43 | 44 | .sk-circle > div:nth-child(2)::before { -webkit-animation-delay: -1.1s; animation-delay: -1.1s } 45 | .sk-circle > div:nth-child(3)::before { -webkit-animation-delay: -1.0s; animation-delay: -1.0s } 46 | .sk-circle > div:nth-child(4)::before { -webkit-animation-delay: -0.9s; animation-delay: -0.9s } 47 | .sk-circle > div:nth-child(5)::before { -webkit-animation-delay: -0.8s; animation-delay: -0.8s } 48 | .sk-circle > div:nth-child(6)::before { -webkit-animation-delay: -0.7s; animation-delay: -0.7s } 49 | .sk-circle > div:nth-child(7)::before { -webkit-animation-delay: -0.6s; animation-delay: -0.6s } 50 | .sk-circle > div:nth-child(8)::before { -webkit-animation-delay: -0.5s; animation-delay: -0.5s } 51 | .sk-circle > div:nth-child(9)::before { -webkit-animation-delay: -0.4s; animation-delay: -0.4s } 52 | .sk-circle > div:nth-child(10)::before { -webkit-animation-delay: -0.3s; animation-delay: -0.3s } 53 | .sk-circle > div:nth-child(11)::before { -webkit-animation-delay: -0.2s; animation-delay: -0.2s } 54 | .sk-circle > div:nth-child(12)::before { -webkit-animation-delay: -0.1s; animation-delay: -0.1s } 55 | 56 | @-webkit-keyframes sk-bouncedelay { 57 | 0%, 80%, 100% { -webkit-transform: scale(0.0) } 58 | 40% { -webkit-transform: scale(1.0) } 59 | } 60 | 61 | @keyframes sk-bouncedelay { 62 | 0%, 80%, 100% { 63 | -webkit-transform: scale(0.0); 64 | transform: scale(0.0); 65 | } 40% { 66 | -webkit-transform: scale(1.0); 67 | transform: scale(1.0); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/components/css/fading-circle.css: -------------------------------------------------------------------------------- 1 | .sk-fading-circle { 2 | width: 40px; 3 | height: 40px; 4 | position: relative; 5 | } 6 | .sk-fading-circle > div { 7 | background-color: initial; 8 | width: 100%; 9 | height: 100%; 10 | position: absolute; 11 | left: 0; 12 | top: 0; 13 | } 14 | 15 | .sk-fading-circle > div::before { 16 | content: ''; 17 | display: block; 18 | margin: 0 auto; 19 | width: 15%; 20 | height: 15%; 21 | background-color: currentColor; 22 | border-radius: 100%; 23 | -webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out both; 24 | animation: sk-circleFadeDelay 1.2s infinite ease-in-out both; 25 | } 26 | .sk-fading-circle > div:nth-child(2) { 27 | -webkit-transform: rotate(30deg); 28 | -ms-transform: rotate(30deg); 29 | transform: rotate(30deg); } 30 | .sk-fading-circle > div:nth-child(3) { 31 | -webkit-transform: rotate(60deg); 32 | -ms-transform: rotate(60deg); 33 | transform: rotate(60deg); } 34 | .sk-fading-circle > div:nth-child(4) { 35 | -webkit-transform: rotate(90deg); 36 | -ms-transform: rotate(90deg); 37 | transform: rotate(90deg); } 38 | .sk-fading-circle > div:nth-child(5) { 39 | -webkit-transform: rotate(120deg); 40 | -ms-transform: rotate(120deg); 41 | transform: rotate(120deg); } 42 | .sk-fading-circle > div:nth-child(6) { 43 | -webkit-transform: rotate(150deg); 44 | -ms-transform: rotate(150deg); 45 | transform: rotate(150deg); } 46 | .sk-fading-circle > div:nth-child(7) { 47 | -webkit-transform: rotate(180deg); 48 | -ms-transform: rotate(180deg); 49 | transform: rotate(180deg); } 50 | .sk-fading-circle > div:nth-child(8) { 51 | -webkit-transform: rotate(210deg); 52 | -ms-transform: rotate(210deg); 53 | transform: rotate(210deg); } 54 | .sk-fading-circle > div:nth-child(9) { 55 | -webkit-transform: rotate(240deg); 56 | -ms-transform: rotate(240deg); 57 | transform: rotate(240deg); } 58 | .sk-fading-circle > div:nth-child(10) { 59 | -webkit-transform: rotate(270deg); 60 | -ms-transform: rotate(270deg); 61 | transform: rotate(270deg); } 62 | .sk-fading-circle > div:nth-child(11) { 63 | -webkit-transform: rotate(300deg); 64 | -ms-transform: rotate(300deg); 65 | transform: rotate(300deg); } 66 | .sk-fading-circle > div:nth-child(12) { 67 | -webkit-transform: rotate(330deg); 68 | -ms-transform: rotate(330deg); 69 | transform: rotate(330deg); } 70 | .sk-fading-circle > div:nth-child(2)::before { 71 | -webkit-animation-delay: -1.1s; 72 | animation-delay: -1.1s; } 73 | .sk-fading-circle > div:nth-child(3)::before { 74 | -webkit-animation-delay: -1s; 75 | animation-delay: -1s; } 76 | .sk-fading-circle > div:nth-child(4)::before { 77 | -webkit-animation-delay: -0.9s; 78 | animation-delay: -0.9s; } 79 | .sk-fading-circle > div:nth-child(5)::before { 80 | -webkit-animation-delay: -0.8s; 81 | animation-delay: -0.8s; } 82 | .sk-fading-circle > div:nth-child(6)::before { 83 | -webkit-animation-delay: -0.7s; 84 | animation-delay: -0.7s; } 85 | .sk-fading-circle > div:nth-child(7)::before { 86 | -webkit-animation-delay: -0.6s; 87 | animation-delay: -0.6s; } 88 | .sk-fading-circle > div:nth-child(8)::before { 89 | -webkit-animation-delay: -0.5s; 90 | animation-delay: -0.5s; } 91 | .sk-fading-circle > div:nth-child(9)::before { 92 | -webkit-animation-delay: -0.4s; 93 | animation-delay: -0.4s; } 94 | .sk-fading-circle > div:nth-child(10)::before { 95 | -webkit-animation-delay: -0.3s; 96 | animation-delay: -0.3s; } 97 | .sk-fading-circle > div:nth-child(11)::before { 98 | -webkit-animation-delay: -0.2s; 99 | animation-delay: -0.2s; } 100 | .sk-fading-circle > div:nth-child(12)::before { 101 | -webkit-animation-delay: -0.1s; 102 | animation-delay: -0.1s; } 103 | 104 | @-webkit-keyframes sk-circleFadeDelay { 105 | 0%, 39%, 100% { 106 | opacity: 0; } 107 | 40% { 108 | opacity: 1; } } 109 | 110 | @keyframes sk-circleFadeDelay { 111 | 0%, 39%, 100% { 112 | opacity: 0; } 113 | 40% { 114 | opacity: 1; } } -------------------------------------------------------------------------------- /src/Example.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 83 | 84 | 141 | -------------------------------------------------------------------------------- /postcss-plugins.js: -------------------------------------------------------------------------------- 1 | // PostCSS 8 compatible plugins to replace deprecated ones in @vue/component-compiler-utils 2 | 3 | // Replacement for the 'trim' plugin 4 | const trimPlugin = () => { 5 | return { 6 | postcssPlugin: 'trim', 7 | Once(css) { 8 | css.walk(({ type, raws }) => { 9 | if (type === 'rule' || type === 'atrule') { 10 | if (raws.before) raws.before = '\n'; 11 | if (raws.after) raws.after = '\n'; 12 | } 13 | }); 14 | } 15 | }; 16 | }; 17 | trimPlugin.postcss = true; 18 | 19 | // Replacement for the 'add-id' plugin 20 | const addIdPlugin = (options) => { 21 | return { 22 | postcssPlugin: 'add-id', 23 | Once(root) { 24 | const selectorParser = require('postcss-selector-parser'); 25 | const id = options; 26 | const keyframes = Object.create(null); 27 | 28 | root.each(function rewriteSelector(node) { 29 | if (!node.selector) { 30 | // handle media queries 31 | if (node.type === 'atrule') { 32 | if (node.name === 'media' || node.name === 'supports') { 33 | node.each(rewriteSelector); 34 | } else if (/-?keyframes$/.test(node.name)) { 35 | // register keyframes 36 | keyframes[node.params] = node.params = node.params + '-' + id; 37 | } 38 | } 39 | return; 40 | } 41 | 42 | node.selector = selectorParser((selectors) => { 43 | selectors.each((selector) => { 44 | let node = null; 45 | // find the last child node to insert attribute selector 46 | selector.each((n) => { 47 | // ">>>" combinator 48 | // and /deep/ alias for >>>, since >>> doesn't work in SASS 49 | if (n.type === 'combinator' && 50 | (n.value === '>>>' || n.value === '/deep/')) { 51 | n.value = ' '; 52 | n.spaces.before = n.spaces.after = ''; 53 | return false; 54 | } 55 | // in newer versions of sass, /deep/ support is also dropped, so add a ::v-deep alias 56 | if (n.type === 'pseudo' && n.value === '::v-deep') { 57 | n.value = n.spaces.before = n.spaces.after = ''; 58 | return false; 59 | } 60 | if (n.type !== 'pseudo' && n.type !== 'combinator') { 61 | node = n; 62 | } 63 | }); 64 | 65 | if (node) { 66 | node.spaces.after = ''; 67 | } else { 68 | // For deep selectors & standalone pseudo selectors, 69 | // the attribute selectors are prepended rather than appended. 70 | // So all leading spaces must be eliminated to avoid problems. 71 | selector.first.spaces.before = ''; 72 | } 73 | selector.insertAfter(node, selectorParser.attribute({ 74 | attribute: id 75 | })); 76 | }); 77 | }).processSync(node.selector); 78 | }); 79 | 80 | // If keyframes are found in this