mirror of
				https://github.com/KevinMidboe/vue-js-modal.git
				synced 2025-10-29 18:00:20 +00:00 
			
		
		
		
	Refactored, added es5 build
This commit is contained in:
		
							
								
								
									
										257
									
								
								src/Modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/Modal.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| <template> | ||||
|   <transition name="overlay-fade"> | ||||
|     <div v-if="visibility.overlay" | ||||
|          class="nice-modal-overlay" | ||||
|          @mousedown.stop="toggle(false)"> | ||||
|       <transition :name="transition"> | ||||
|         <div v-if="visibility.modal" | ||||
|              ref="modal" | ||||
|              :class="modalClass" | ||||
|              :style="modalStyle" | ||||
|              @mousedown.stop> | ||||
|           <slot></slot> | ||||
|           <resizer v-if="resizable" | ||||
|                    :min-width="minWidth" | ||||
|                    :min-height="minHeight" | ||||
|                    @resize="resize"/> | ||||
|         </div> | ||||
|       </transition> | ||||
|     </div> | ||||
|   </transition> | ||||
| </template> | ||||
| <script> | ||||
|   import Vue      from 'vue' | ||||
|   import Modal    from './index' | ||||
|   import Resizer  from './Resizer.vue' | ||||
|  | ||||
|   export default { | ||||
|     name: 'Modal', | ||||
|     props: { | ||||
|       name: { | ||||
|         required: true, | ||||
|         type: [String, Number], | ||||
|       }, | ||||
|       delay: { | ||||
|         type: Number, | ||||
|         default: 0, | ||||
|       }, | ||||
|       resizable: { | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       }, | ||||
|       adaptive: { | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       }, | ||||
|       transition: { | ||||
|         type: String, | ||||
|       }, | ||||
|       classes: { | ||||
|         type: [String, Array], | ||||
|         default: 'nice-modal', | ||||
|       }, | ||||
|       width: { | ||||
|         type: Number, | ||||
|         default: 600 | ||||
|       }, | ||||
|       height: { | ||||
|         type: Number, | ||||
|         default: 300 | ||||
|       }, | ||||
|       minWidth: { | ||||
|         type: Number, | ||||
|         default: 0 | ||||
|       }, | ||||
|       minHeight: { | ||||
|         type: Number, | ||||
|         default: 0 | ||||
|       } | ||||
|     }, | ||||
|     components: { | ||||
|       Resizer | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         visible: false, | ||||
|  | ||||
|         visibility: { | ||||
|           modal: false, | ||||
|           overlay: false | ||||
|         }, | ||||
|  | ||||
|         modal: { | ||||
|           width: this.width, | ||||
|           height: this.height | ||||
|         }, | ||||
|  | ||||
|         window: { | ||||
|           width: window.innerWidth, | ||||
|           height: window.innerWidth | ||||
|         } | ||||
|       }; | ||||
|     }, | ||||
|     watch: { | ||||
|       visible(value) { | ||||
|         if (this.delay > 0) { | ||||
|           if (value) { | ||||
|             this.visibility.overlay = true | ||||
|             setTimeout(() => this.visibility.modal = true, this.delay) | ||||
|           } else { | ||||
|             this.visibility.modal = false | ||||
|             setTimeout(() => this.visibility.overlay = false, this.delay) | ||||
|           } | ||||
|         } else { | ||||
|           this.visibility.overlay = value | ||||
|           Vue.nextTick(() => this.visibility.modal = value) | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     created() { | ||||
|       Modal.event.$on('toggle', (name, state, params) => { | ||||
|         if (name === this.name) { | ||||
|           this.toggle(!this.visible, params) | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|       window.addEventListener('resize', this.onWindowResize) | ||||
|     }, | ||||
|     beforeMount() { | ||||
|       this.onWindowResize(); | ||||
|     }, | ||||
|     computed: { | ||||
|       position() { | ||||
|         return { | ||||
|           left: Math.max(0.5 * (this.window.width - this.modal.width), 0), | ||||
|           top: Math.max(0.5 * (this.window.height - this.modal.height), 0) | ||||
|         } | ||||
|       }, | ||||
|       modalClass() { | ||||
|         return ['modal', this.classes] | ||||
|       }, | ||||
|       modalStyle() { | ||||
|         return { | ||||
|           top: this.position.top + 'px', | ||||
|           left: this.position.left + 'px', | ||||
|           width: this.modal.width + 'px', | ||||
|           height: this.modal.height + 'px' | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       onWindowResize() { | ||||
|         this.window.width = window.innerWidth | ||||
|         this.window.height = window.innerHeight | ||||
|  | ||||
|         if (this.adaptive) { | ||||
|           var width = this.window.width > this.modal.width | ||||
|             ? this.modal.width | ||||
|             : this.window.width | ||||
|  | ||||
|           var height = this.window.height > this.modal.height | ||||
|             ? this.modal.height | ||||
|             : this.window.height | ||||
|  | ||||
|           this.modal.width = width // Math.max(width, this.minWidth); | ||||
|           this.modal.height = height // Math.max(height, this.minHeight); | ||||
|         } | ||||
|       }, | ||||
|       genEventObject(params) { | ||||
|         return Vue.util.extend( | ||||
|           { | ||||
|             name: this.name, | ||||
|             ref: this.$refs.modal, | ||||
|             timestamp: Date.now() | ||||
|           }, | ||||
|           params || {}); | ||||
|       }, | ||||
|       resize(event) { | ||||
|         this.modal.width = event.size.width | ||||
|         this.modal.height = event.size.height | ||||
|  | ||||
|         let resizeEvent = this.genEventObject({ | ||||
|           size: this.modal | ||||
|         }); | ||||
|  | ||||
|         this.$emit('resize', resizeEvent) | ||||
|       }, | ||||
|       toggle(state, params) { | ||||
|         const beforeEventName = this.visible ? 'before-close' : 'before-open' | ||||
|         const afterEventName = this.visible ? 'closed' : 'opened' | ||||
|  | ||||
|         let stopEventExecution = false | ||||
|  | ||||
|         const beforeEvent = this.genEventObject({ | ||||
|           stop: () => stopEventExecution = false, | ||||
|           state, | ||||
|           params | ||||
|         }) | ||||
|  | ||||
|         this.$emit(beforeEventName, beforeEvent) | ||||
|  | ||||
|         if (!stopEventExecution) { | ||||
|           this.visible = !!state | ||||
|  | ||||
|           const afterEvent = this.genEventObject({ | ||||
|             state, | ||||
|             params | ||||
|           }) | ||||
|  | ||||
|           this.$emit(afterEventName, afterEvent) | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   }; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
|   .nice-modal-overlay { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     width: 100vw; | ||||
|     height: 100vh; | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
|     z-index: 999; | ||||
|     opacity: 1; | ||||
|  | ||||
|     .modal { | ||||
|       position: relative; | ||||
|       overflow: hidden; | ||||
|       box-sizing: border-box; | ||||
|  | ||||
|       background-color: white; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .overlay-fade-enter-active, .overlay-fade-leave-active { | ||||
|     transition: all 0.2s; | ||||
|   } | ||||
|  | ||||
|   .overlay-fade-enter, .overlay-fade-leave-active { | ||||
|     opacity: 0; | ||||
|   } | ||||
|  | ||||
|   .nice-modal-fade-enter-active, .nice-modal-fade-leave-active { | ||||
|     transition: all 0.4s; | ||||
|   } | ||||
|  | ||||
|   .nice-modal-fade-enter, .nice-modal-fade-leave-active { | ||||
|     opacity: 0; | ||||
|     transform: translateY(-20px); | ||||
|   } | ||||
|  | ||||
|   .nice-modal { | ||||
|     background: white; | ||||
|     text-align: left; | ||||
|     border-radius: 3px; | ||||
|     box-shadow: 0 20px 60px -2px rgba(27, 33, 58, .4); | ||||
|     padding: 0; | ||||
|  | ||||
|     &.nice-modal-fullscreen { | ||||
|       width: 100vw; | ||||
|       height: 100vh; | ||||
|       margin: 0; | ||||
|       left: 0; | ||||
|       top: 0; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										120
									
								
								src/Resizer.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/Resizer.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| <template> | ||||
|   <div :class="className"></div> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   name: 'Resizer', | ||||
|   props: { | ||||
|     minHeight: { | ||||
|       type: Number, | ||||
|       default: 0 | ||||
|     }, | ||||
|     minWidth: { | ||||
|       type: Number, | ||||
|       default: 0 | ||||
|     }}, | ||||
|   data() { | ||||
|     return { | ||||
|       clicked: false, | ||||
|       size: {} | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.$el.addEventListener('mousedown', this.start, false) | ||||
|   }, | ||||
|   computed: { | ||||
|     className () { | ||||
|       return {'vue-modal-resizer': true, 'clicked': this.clicked} | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     start(event) { | ||||
|       this.clicked = true | ||||
|  | ||||
|       window.addEventListener('mousemove', this.mousemove, false) | ||||
|       window.addEventListener('mouseup', this.stop, false) | ||||
|  | ||||
|       event.stopPropagation() | ||||
|       event.preventDefault() | ||||
|     }, | ||||
|     stop() { | ||||
|       this.clicked = false | ||||
|  | ||||
|       window.removeEventListener('mousemove', this.mousemove, false) | ||||
|       window.removeEventListener('mouseup', this.stop, false) | ||||
|  | ||||
|       this.$emit('resize-stop', { | ||||
|         element: this.$el.parentElement, | ||||
|         size: this.size | ||||
|       }); | ||||
|     }, | ||||
|     mousemove(event) { | ||||
|       this.resize(event) | ||||
|     }, | ||||
|     resize(event) { | ||||
|       var el = this.$el.parentElement | ||||
|  | ||||
|       if (el) { | ||||
|         var width = event.clientX - el.offsetLeft | ||||
|         var height = event.clientY - el.offsetTop | ||||
|  | ||||
|         if (width < this.minWidth) { | ||||
|           width = this.minWidth | ||||
|         } | ||||
|  | ||||
|         if (width > window.innerWidth) { | ||||
|           width = window.innerWidth | ||||
|         } | ||||
|  | ||||
|         if (height < this.minHeight) { | ||||
|           height = this.minHeight | ||||
|         } | ||||
|  | ||||
|         if (height > window.innerHeight) { | ||||
|           height = window.innerHeight | ||||
|         } | ||||
|  | ||||
|         this.size = {width, height} | ||||
|         el.style.width = width + 'px' | ||||
|         el.style.height = height + 'px' | ||||
|  | ||||
|         this.$emit('resize', { | ||||
|           element: el, | ||||
|           size: this.size | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| .vue-modal-resizer { | ||||
|     display: block; | ||||
|     overflow: hidden; | ||||
|     position: absolute; | ||||
|     width: 12px; | ||||
|     height: 12px; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 9999999; | ||||
|     background: transparent; | ||||
|     cursor: se-resize; | ||||
|  | ||||
|     &:after { | ||||
|       display: block; | ||||
|       position: absolute; | ||||
|       content: ''; | ||||
|       background: transparent; | ||||
|       left: 0; | ||||
|       top: 0; | ||||
|     	width: 0; | ||||
|     	height: 0; | ||||
|     	border-bottom: 10px solid #ddd; | ||||
|     	border-left: 10px solid transparent; | ||||
|     } | ||||
|  | ||||
|     &.clicked:after { | ||||
|       border-bottom: 10px solid #369BE9; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										28
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import Vue    from 'vue' | ||||
| import Modal  from './Modal.vue' | ||||
|  | ||||
| const ModalPlugin = { | ||||
|   install(Vue, options = {}) { | ||||
|     if (!this.hasOwnProperty("event")) { | ||||
|       this.event = new Vue() | ||||
|     } | ||||
|  | ||||
|     const $modal = { | ||||
|       show(name, params) { | ||||
|         ModalPlugin.event.$emit('toggle', name, true, params) | ||||
|       }, | ||||
|       hide(name, params) { | ||||
|         ModalPlugin.event.$emit('toggle', name, false, params) | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     Object.defineProperty(Vue.prototype, '$modal', { | ||||
|       get: () => $modal | ||||
|     }) | ||||
|  | ||||
|     Vue.component('modal', Modal) | ||||
|     return null | ||||
|   }, | ||||
| } | ||||
|  | ||||
| export default ModalPlugin | ||||
		Reference in New Issue
	
	Block a user