├── .browserslistrc ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── build └── rollup.config.js ├── dev ├── serve.ts └── serve.vue ├── package-lock.json ├── package.json ├── shims-vue.d.ts ├── src ├── ConfettiExplosion.vue ├── entry.esm.ts └── entry.ts └── tsconfig.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | current node 2 | last 2 versions and > 2% 3 | ie > 10 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Valgeir Björnsson 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-confetti-explosion 2 | 3 | > This library is the Vue 3 port of [svelte-confetti-explosion](https://www.npmjs.com/package/svelte-confetti-explosion) which in turn is ported from the [@reonomy/react-confetti-explosion](https://www.npmjs.com/package/@reonomy/react-confetti-explosion) package. 4 | 5 | ![confetti-large-edit](https://user-images.githubusercontent.com/5460067/111782964-0c6bed80-8890-11eb-8a8b-0a4fdbc30cbd.gif) 6 | 7 | ## Installing 8 | 9 | ```bash 10 | # pnpm 11 | pnpm add vue-confetti-explosion 12 | 13 | # npm 14 | npm install vue-confetti-explosion 15 | 16 | # yarn 17 | yarn add vue-confetti-explosion 18 | ``` 19 | 20 | ## Usage 21 | 22 | Basic usage: 23 | 24 | ```html 25 | 28 | 29 | 32 | ``` 33 | 34 | Customizing behavior with options: 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | ## Props 41 | 42 | There's tons of options available for this package. All of them are already documented within the code itself, so you'll never have to leave the code editor. 43 | 44 | ### particleCount 45 | 46 | Number of confetti particles to create. 47 | 48 | **type:** `number` 49 | 50 | **Default value:** 150 51 | 52 | **Example:** 53 | 54 | ```html 55 | 56 | ``` 57 | 58 | ### particleSize 59 | 60 | Size of the confetti particles in pixels 61 | 62 | **type:** `number` 63 | 64 | **Default value:** 12 65 | 66 | **Example:** 67 | 68 | ```html 69 | 70 | ``` 71 | 72 | ### duration 73 | 74 | Duration of the animation in milliseconds 75 | 76 | **type:** `number` 77 | 78 | **Default value:** 3500 79 | 80 | **Example:** 81 | 82 | ```html 83 | 84 | ``` 85 | 86 | ### colors 87 | 88 | Colors to use for the confetti particles. Pass string array of colors. Can use hex colors, named colors, CSS Variables, literally anything valid in plain CSS. 89 | 90 | **type:** `Array` 91 | 92 | **Default value:** `['#FFC700', '#FF0000', '#2E3191', '#41BBC7']` 93 | 94 | **Example:** 95 | 96 | ```html 97 | 99 | ``` 100 | 101 | ### force 102 | 103 | Force of the confetti particles. Between 0 and 1. 0 is no force, 1 is maximum force. Will error out if you pass a value outside of this range. 104 | 105 | **type:** `number` 106 | 107 | **Default value:** 0.5 108 | 109 | **Example:** 110 | 111 | ```html 112 | 113 | ``` 114 | 115 | ### stageHeight 116 | 117 | Height of the stage in pixels. Confetti will only fall within this height. 118 | 119 | **type:** `number` 120 | 121 | **Default value:** 800 122 | 123 | **Example:** 124 | 125 | ```html 126 | 127 | ``` 128 | 129 | ### stageWidth 130 | 131 | Width of the stage in pixels. Confetti will only fall within this width. 132 | 133 | **type:** `number` 134 | 135 | **Default value:** 1600 136 | 137 | **Example:** 138 | 139 | ```html 140 | 141 | ``` 142 | 143 | ### shouldDestroyAfterDone 144 | 145 | Whether or not destroy all confetti nodes after the `duration` period has passed. By default it destroys all nodes, to free up memory. 146 | 147 | **type:** `boolean` 148 | 149 | **Default value:** `true` 150 | 151 | **Example:** 152 | 153 | ```html 154 | 155 | ``` 156 | 157 | ~~## Style Props~~ 158 | 159 | > This is Svelte specific, still not implemented for this Vue 3 component 160 | 161 | ~~You can specify two style props on the component: `--x` and `--y`. These will shift the confetti particles on the x and y axis. by how much you specify, These can be in `px`, `em`, `rem`, `vh`, `vw`, literally any valid CSS unit.~~ 162 | 163 | ~~**USAGE:**~~ 164 | 165 | ```html 166 | 167 | ``` 168 | 169 | ## Examples 170 | 171 | ```html 172 | 184 | 185 | 191 | ``` 192 | 193 | ## Potential gotchas 194 | 195 | - Your container must be `overflow: visible` in order to allow elements to fully spread across area. 196 | - If your `floorHeight` is too small, particles may visibly land on the floor instead of disappearing off-screen. 197 | 198 | ## Performance 199 | 200 | This library functions by creating 2 DOM nodes for every single confetti. By default, if the `particlesCount` is set to 150, it will create 300 nodes. This is a lot of nodes. For most devices, these many nodes are not a big issue, but I recommend checking your target devices' performance if you choose to go with a higher number, like 400 or 500. 201 | 202 | Also, after the specified `duration`, all the confetti DOM nodes will be destroyed. This is to free up memory. If you wish to keep them around, set `shouldDestroyAfterDone` to `false`. 203 | 204 | ## License 205 | 206 | MIT License 207 | © [Valgeir Björnsson](https://valgeir.dev/) 208 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const devPresets = ['@vue/babel-preset-app']; 2 | const buildPresets = [ 3 | [ 4 | '@babel/preset-env', 5 | // Config for @babel/preset-env 6 | { 7 | // Example: Always transpile optional chaining/nullish coalescing 8 | // include: [ 9 | // /(optional-chaining|nullish-coalescing)/ 10 | // ], 11 | }, 12 | ], 13 | '@babel/preset-typescript', 14 | ]; 15 | module.exports = { 16 | presets: (process.env.NODE_ENV === 'development' ? devPresets : buildPresets), 17 | }; 18 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | // rollup.config.js 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | import vue from 'rollup-plugin-vue'; 5 | import alias from '@rollup/plugin-alias'; 6 | import commonjs from '@rollup/plugin-commonjs'; 7 | import resolve from '@rollup/plugin-node-resolve'; 8 | import replace from '@rollup/plugin-replace'; 9 | import babel from '@rollup/plugin-babel'; 10 | import PostCSS from 'rollup-plugin-postcss'; 11 | import { terser } from 'rollup-plugin-terser'; 12 | import ttypescript from 'ttypescript'; 13 | import typescript from 'rollup-plugin-typescript2'; 14 | import minimist from 'minimist'; 15 | 16 | // Get browserslist config and remove ie from es build targets 17 | const esbrowserslist = fs.readFileSync('./.browserslistrc') 18 | .toString() 19 | .split('\n') 20 | .filter((entry) => entry && entry.substring(0, 2) !== 'ie'); 21 | 22 | // Extract babel preset-env config, to combine with esbrowserslist 23 | const babelPresetEnvConfig = require('../babel.config') 24 | .presets.filter((entry) => entry[0] === '@babel/preset-env')[0][1]; 25 | 26 | const argv = minimist(process.argv.slice(2)); 27 | 28 | const projectRoot = path.resolve(__dirname, '..'); 29 | 30 | const baseConfig = { 31 | input: 'src/entry.ts', 32 | plugins: { 33 | preVue: [ 34 | alias({ 35 | entries: [ 36 | { 37 | find: '@', 38 | replacement: `${path.resolve(projectRoot, 'src')}`, 39 | }, 40 | ], 41 | }), 42 | ], 43 | replace: { 44 | 'process.env.NODE_ENV': JSON.stringify('production'), 45 | }, 46 | vue: { 47 | }, 48 | postVue: [ 49 | resolve({ 50 | extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'], 51 | }), 52 | // Process only ` 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-confetti-explosion", 3 | "version": "1.0.2", 4 | "description": "Confetti explosion in Vue 3 🎉🎊", 5 | "author": { 6 | "name": "Valgeir Björnsson", 7 | "email": "valgeir@hey.com", 8 | "url": "https://github.com/valgeirb" 9 | }, 10 | "repository": "github:valgeirb/vue-confetti-explosion", 11 | "keywords": [ 12 | "confetti", 13 | "party", 14 | "fun", 15 | "badass", 16 | "badassery", 17 | "vue", 18 | "vue3", 19 | "small", 20 | "tiny", 21 | "performant" 22 | ], 23 | "main": "dist/confetti-explosion.ssr.js", 24 | "browser": "dist/confetti-explosion.esm.js", 25 | "module": "dist/confetti-explosion.esm.js", 26 | "unpkg": "dist/confetti-explosion.min.js", 27 | "types": "dist/types/src/entry.esm.d.ts", 28 | "files": [ 29 | "dist/*", 30 | "src/**/*.vue" 31 | ], 32 | "sideEffects": false, 33 | "scripts": { 34 | "serve": "vue-cli-service serve dev/serve.ts", 35 | "prebuild": "rimraf ./dist", 36 | "build": "cross-env NODE_ENV=production rollup --config build/rollup.config.js", 37 | "build:ssr": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format cjs", 38 | "build:es": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format es", 39 | "build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife", 40 | "postbuild": "rimraf ./dist/types/dev ./dist/types/src/entry.d.ts" 41 | }, 42 | "dependencies": {}, 43 | "devDependencies": { 44 | "@babel/core": "^7.14.6", 45 | "@babel/preset-env": "^7.14.7", 46 | "@babel/preset-typescript": "^7.14.5", 47 | "@rollup/plugin-alias": "^3.1.2", 48 | "@rollup/plugin-babel": "^5.3.0", 49 | "@rollup/plugin-commonjs": "^14.0.0", 50 | "@rollup/plugin-node-resolve": "^9.0.0", 51 | "@rollup/plugin-replace": "^2.4.2", 52 | "@vue/cli-plugin-babel": "^4.5.13", 53 | "@vue/cli-plugin-typescript": "^4.5.13", 54 | "@vue/cli-service": "^4.5.13", 55 | "@vue/compiler-sfc": "^3.0.11", 56 | "@zerollup/ts-transform-paths": "^1.7.18", 57 | "cross-env": "^7.0.3", 58 | "minimist": "^1.2.5", 59 | "postcss": "^8.2.10", 60 | "rimraf": "^3.0.2", 61 | "rollup": "^2.52.8", 62 | "rollup-plugin-postcss": "^4.0.0", 63 | "rollup-plugin-terser": "^7.0.2", 64 | "rollup-plugin-vue": "^6.0.0", 65 | "rollup-plugin-typescript2": "^0.30.0", 66 | "ttypescript": "^1.5.12", 67 | "typescript": "^4.0.3", 68 | "vue": "^3.2.22" 69 | }, 70 | "peerDependencies": { 71 | "vue": "^3.0.5" 72 | }, 73 | "engines": { 74 | "node": ">=12" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | 4 | const Component: DefineComponent<{}, {}, any>; 5 | export default Component; 6 | } 7 | -------------------------------------------------------------------------------- /src/ConfettiExplosion.vue: -------------------------------------------------------------------------------- 1 | 334 | 335 | 351 | 352 | 399 | -------------------------------------------------------------------------------- /src/entry.esm.ts: -------------------------------------------------------------------------------- 1 | import { App, Plugin } from "vue"; 2 | 3 | // Import vue component 4 | import component from "@/ConfettiExplosion.vue"; 5 | 6 | // Define typescript interfaces for installable component 7 | type InstallableComponent = typeof component & { 8 | install: Exclude; 9 | }; 10 | 11 | // Default export is installable instance of component. 12 | // IIFE injects install function into component, allowing component 13 | // to be registered via Vue.use() as well as Vue.component(), 14 | export default /*#__PURE__*/ ((): InstallableComponent => { 15 | // Assign InstallableComponent type 16 | const installable = component as unknown as InstallableComponent; 17 | 18 | // Attach install function executed by Vue.use() 19 | installable.install = (app: App) => { 20 | app.component("ConfettiExplosion", installable); 21 | }; 22 | return installable; 23 | })(); 24 | 25 | // It's possible to expose named exports when writing components that can 26 | // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; 27 | // export const RollupDemoDirective = directive; 28 | -------------------------------------------------------------------------------- /src/entry.ts: -------------------------------------------------------------------------------- 1 | // iife/cjs usage extends esm default export - so import it all 2 | import component, * as namedExports from '@/entry.esm'; 3 | 4 | // Attach named exports directly to component. IIFE/CJS will 5 | // only expose one global var, with named exports exposed as properties of 6 | // that global var (eg. plugin.namedExport) 7 | Object.entries(namedExports).forEach(([exportName, exported]) => { 8 | if (exportName !== 'default') component[exportName] = exported; 9 | }); 10 | 11 | export default component as typeof component & Exclude; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "declaration": true, 7 | "declarationDir": "dist/types", 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "importHelpers": true, 11 | "moduleResolution": "node", 12 | "experimentalDecorators": true, 13 | "esModuleInterop": true, 14 | "allowSyntheticDefaultImports": true, 15 | "sourceMap": true, 16 | "baseUrl": ".", 17 | "newLine": "lf", 18 | "types": [ 19 | "node", 20 | "vue" 21 | ], 22 | "paths": { 23 | "@/*": [ 24 | "src/*" 25 | ] 26 | }, 27 | "plugins": [ 28 | { 29 | "transform":"@zerollup/ts-transform-paths", 30 | "exclude": ["*"] 31 | } 32 | ], 33 | "lib": [ 34 | "esnext", 35 | "dom", 36 | "dom.iterable", 37 | "scripthost" 38 | ] 39 | }, 40 | "exclude": [ 41 | "node_modules", 42 | "dist" 43 | ] 44 | } 45 | --------------------------------------------------------------------------------