├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── deploy.sh ├── docs ├── .vuepress │ ├── components │ │ └── StackableModalDemo.vue │ ├── config.js │ └── style.styl └── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html └── src ├── assets ├── logo.png ├── modal.scss └── transitions │ └── translate-fade.scss ├── components └── StackModal.vue └── index.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | ie 11 -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.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 | 23 | # nikola 24 | /docs/.vuepress/dist 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Innologica Ltd 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 | # Stackable modal 2 | 3 | Stackable modal is a library for modal dialogs which can be stacked by using z-index position. 4 | The component uses bootstrap for styling the modal but DOES NOT include it by default - 5 | you need to import it yourself. 6 | 7 | When you open a second dialog the first one is scaled to 0.9 and position behind. You have always 3 visible modals. 8 | 9 | ## Installation 10 | 11 | ```shell 12 | npm i @innologica/vue-stackable-modal --save 13 | ``` 14 | 15 | or 16 | 17 | ```shell 18 | yarn add @innologica/vue-stackable-modal 19 | ``` 20 | 21 | import to use: 22 | 23 | ```JS 24 | import StackModal from '@innologica/vue-stackable-modal' 25 | ``` 26 | 27 | More info and demo https://innologica.github.io/vue-stackable-modal/ 28 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run docs:build 8 | 9 | # navigate into the build output directory 10 | cd docs/.vuepress/dist 11 | 12 | # if you are deploying to a custom domain 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # if you are deploying to https://.github.io 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # if you are deploying to https://.github.io/ 23 | git push -f git@github.com:Innologica/vue-stackable-modal.git master:gh-pages 24 | 25 | 26 | cd - -------------------------------------------------------------------------------- /docs/.vuepress/components/StackableModalDemo.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 80 | 81 | 84 | 85 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ga: 'UA-141652960-1', 3 | base: '/vue-stackable-modal/', 4 | title: 'Stackable modals library', 5 | description: 'Stackable modal by Innologica', 6 | themeConfig: { 7 | nav: [ 8 | { text: 'Github', link: 'https://github.com/Innologica/vue-stackable-modal' } 9 | ], 10 | sidebar: 'auto' 11 | }, 12 | } -------------------------------------------------------------------------------- /docs/.vuepress/style.styl: -------------------------------------------------------------------------------- 1 | // showing default values 2 | $accentColor = #3eaf7c 3 | $textColor = #2c3e50 4 | $borderColor = #eaecef 5 | $codeBgColor = #282c34 6 | 7 | .navbar { 8 | position: fixed !important; 9 | } -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Stackable modal 2 | 3 | Stackable modals is a library for modal dialogs which can be infinitely stacked. 4 | The component uses bootstrap for styling the modal but DOES NOT include it by default - 5 | you need to import it yourself. 6 | 7 | When you open a second dialog the first one is scaled to 0.9 and position behind 8 | 9 | ## Installation 10 | 11 | ```shell 12 | npm i @innologica/vue-stackable-modal --save 13 | ``` 14 | 15 | or 16 | 17 | ```shell 18 | yarn add @innologica/vue-stackable-modal 19 | ``` 20 | 21 | import to use: 22 | 23 | ```JS 24 | import StackModal from '@innologica/vue-stackable-modal' 25 | ``` 26 | 27 | ## Example 28 | 29 | 30 | 31 | ### Source code 32 | <<< @/docs/.vuepress/components/StackableModalDemo.vue 33 | 34 | ### Sample css 35 | <<< @/src/assets/modal.scss 36 | 37 | ## Props 38 | 39 | | Prop | Type | Default |Description | 40 | | ------------- |:-------------| -----|-----| 41 | | show | Boolean | false |Shows/hides the modal| 42 | | title | String | |The title of the modal shown in .modal-header div. If empty the div is not rendered| 43 | | modalClass | Object | {} |:class object which is attached to the modal dialog element | 44 | | hasBackdrop | Boolean | true |Whether to display backdrop element for this dialog. It is added to the body with calculated z-index. | 45 | | saveButton | Object | { title: 'Save', visible: true, btnClass: {'btn btn-primary': true}}| Save button config | 46 | | cancelButton | Object | { title: 'Cancel', visible: true, btnClass: {'btn btn-outline-secondary': true}}| Cancel button config | 47 | | transition | String | translate-fade* | Transition to use when showing the modal.You need to include scss with the transition | 48 | | closeOnEscape | Boolean | true | If enabled the component attaches event handler on document body which monitors for ESC and emits the 'close' event. | 49 | 50 | *for the default transition you need to @import "~@innologica/vue-stackable-modal/src/assets/transitions/translate-fade.scss"; 51 | 52 | ## Events 53 | 54 | | Event | Params | Description | 55 | |-------| --------|------------| 56 | | save | none| When the save button is pressed 57 | | close | none| When the cancel button is pressed, or the "x" in the title is clicked, or escape is pressed. Yoo need to close the modal via the show property| 58 | | show | show, index, total| Called when the modal show/hides. show - open/close, index - the index in the current stack, total - total modals open| 59 | 60 | ## Slots 61 | 62 | ### default 63 | This slot is the content of the modal. 64 | 65 | ### modal-header 66 | 67 | Default value: 68 | 69 | ```vue 70 | 71 | 77 | 78 | ``` 79 | 80 | The modal header is rendered above the content. If title is empty then it is not rendered 81 | 82 | ### modal-footer 83 | 84 | Default value: 85 | 86 | ```vue 87 | 88 | 104 | 105 | ``` 106 | This is the modal footer with the 2 buttons. If you just want to hide the footer you can provide empty footer slot e.g.: 107 | ```vue 108 |
109 | ``` 110 | 111 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@innologica/vue-stackable-modal", 3 | "version": "0.1.10", 4 | "scripts": { 5 | "lint": "vue-cli-service lint", 6 | "lib": "vue-cli-service build --target lib --name vue-stackable-modal ./src/index.js", 7 | "docs:dev": "vuepress dev docs", 8 | "docs:build": "vuepress build docs", 9 | "prepublishOnly": "npm run lib" 10 | }, 11 | "dependencies": { 12 | "core-js": "^2.6.5", 13 | "vue": "^2.6.10" 14 | }, 15 | "files": [ 16 | "dist", 17 | "src" 18 | ], 19 | "main": "dist/vue-stackable-modal.umd.min.js", 20 | "jsnext:main": "dist/vue-stackable-modal.umd.min.js", 21 | "devDependencies": { 22 | "@vue/cli-plugin-babel": "^3.8.0", 23 | "@vue/cli-plugin-eslint": "^3.8.0", 24 | "@vue/cli-service": "^3.8.0", 25 | "babel-eslint": "^10.0.1", 26 | "eslint": "^5.16.0", 27 | "eslint-plugin-vue": "^5.0.0", 28 | "node-sass": "^4.9.0", 29 | "sass-loader": "^7.1.0", 30 | "vue-template-compiler": "^2.6.10", 31 | "babel-preset-vue": "^2.0.2", 32 | "@babel/core": "^7.4.5", 33 | "babel-loader": "^8.0.6", 34 | "vuepress": "^0.14.11" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Innologica/vue-stackable-modal/23b381a1ff31a06e10cc4d132ec892d10e24a7e8/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-stackable-modal 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Innologica/vue-stackable-modal/23b381a1ff31a06e10cc4d132ec892d10e24a7e8/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/modal.scss: -------------------------------------------------------------------------------- 1 | $modal-xl: 900px; 2 | $modal-xxl: 1040px; 3 | $modal-xxxl: 1180px; 4 | $modal-90per: 90%; 5 | 6 | @media (min-width: 768px) { 7 | .modal-xl { 8 | max-width: $modal-xl; 9 | } 10 | .modal-xxl { 11 | max-width: $modal-xxl; 12 | } 13 | .modal-xxxl{ 14 | max-width: $modal-xxxl; 15 | } 16 | .modal-90per { 17 | max-width: $modal-90per; 18 | } 19 | } 20 | 21 | .modal-fullscreen { 22 | max-width: 100%; 23 | width: 100%; 24 | margin: 0; 25 | height: 100%; 26 | 27 | .modal-body { 28 | padding: 0; 29 | } 30 | 31 | .modal-content { 32 | height: 100%; 33 | } 34 | 35 | &.aside .modal-content { 36 | height: auto; 37 | } 38 | 39 | &.modal-dialog.aside.modal-stack1 .modal-content { 40 | transform: scale(1) translate(0, 0) !important; 41 | } 42 | } 43 | 44 | //modal without border 45 | .modal-dialog.modal-border-0 { 46 | .modal-content { 47 | border: none; 48 | } 49 | } 50 | 51 | @media screen and (min-width: 800px){ 52 | .modal-dialog { 53 | &.modal-xxl{ 54 | width: 98%; 55 | max-width: 1040px; 56 | } 57 | } 58 | } 59 | 60 | 61 | @media screen and (min-width: 640px){ 62 | .modal-dialog { 63 | &.modal-xxl{ 64 | width: 98%; 65 | max-width: 1040px; 66 | } 67 | } 68 | } 69 | 70 | @media screen and (max-width: 420px){ 71 | .modal-dialog, 72 | .modal-content{ 73 | overflow: auto; 74 | } 75 | } -------------------------------------------------------------------------------- /src/assets/transitions/translate-fade.scss: -------------------------------------------------------------------------------- 1 | $transition-duration: 250ms !default; 2 | $translate-offset: 50px !default; 3 | $timing-function: cubic-bezier(.53,2,.36,.85) !default; 4 | 5 | //translate fade (right to left) 6 | .translate-fade-enter-active, .translate-fade-leave-active { 7 | transition: all $transition-duration; 8 | transition-timing-function: $timing-function; 9 | } 10 | .translate-fade-enter, .translate-fade-leave-active { 11 | opacity: 0; 12 | } 13 | .translate-fade-enter { 14 | transform: translateX($translate-offset); 15 | } 16 | .translate-fade-leave-active { 17 | transform: translateX($translate-offset); 18 | } -------------------------------------------------------------------------------- /src/components/StackModal.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 217 | 218 | 258 | 259 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import StackModal from './components/StackModal' 2 | 3 | const install = (Vue) => { 4 | Vue.component('StackModal', StackModal) 5 | } 6 | 7 | // auto install if used in browser 8 | if (typeof window !== 'undefined' && window.Vue) { 9 | install(window.Vue) 10 | } 11 | 12 | export { StackModal as default } --------------------------------------------------------------------------------