This commit is contained in:
Yev Vlasenko
2018-02-17 19:23:40 +00:00
17 changed files with 472 additions and 225 deletions

View File

@@ -133,6 +133,50 @@ this.$modal.show('dialog', {
<img src="https://user-images.githubusercontent.com/1577802/29165216-ec62552c-7db9-11e7-807e-ef341edcc94d.png"> <img src="https://user-images.githubusercontent.com/1577802/29165216-ec62552c-7db9-11e7-807e-ef341edcc94d.png">
</p> </p>
### Dynamic Modals
In order to instantiate modals at runtime (for lazy-loading or decluttering templates), it is possible to create modals dynamically.
To start using this feature you must set `dynamic: true` in plugin configuration:
```js
Vue.use(VModal, { dynamic: true })
```
And include the `<modals-container/>` component it in your project:
```vue
<modals-container/>
```
Call it (the first argument is the component definition, the second are component properties, and the third modal parameters):
```javascript
this.$modal.show({
template: `
<div>
<h1>This is created inline</h1>
<p>{{ text }}</p>
</div>
`,
props: ['text']
}, {
text: 'This text is passed as a property'
})
```
It can also be used with `.vue` files:
```javascript
import MyComponent from './MyComponent.vue'
this.$modal.show(MyComponent, {
text: 'This text is passed as a property'
}, {
draggable: true
})
```
For more examples please take a look at [vue-js-modal.yev.io](http://vue-js-modal.yev.io). For more examples please take a look at [vue-js-modal.yev.io](http://vue-js-modal.yev.io).
### SSR ### SSR
@@ -156,6 +200,10 @@ Vue.use(VModal)
For full demo please look at `demo/server_side_rendering` For full demo please look at `demo/server_side_rendering`
### Extracted CSS
There is also a ssr build with css file extracted. Take a look in /dist folder.
### Properties ### Properties
| Name | Required | Type | Default | Description | | Name | Required | Type | Default | Description |
@@ -172,8 +220,10 @@ For full demo please look at `demo/server_side_rendering`
| classes | false | [String, Array] | 'v--modal'| Classes that will be applied to the actual modal box, if not specified, the default 'vue--modal' class will be applied | | classes | false | [String, Array] | 'v--modal'| Classes that will be applied to the actual modal box, if not specified, the default 'vue--modal' class will be applied |
| width | false | [String, Number] | 600 | Width in pixels or percents (e.g. 50 or "50px", "50%") | | width | false | [String, Number] | 600 | Width in pixels or percents (e.g. 50 or "50px", "50%") |
| height | false | [String, Number] | 300 | Height in pixels or percents (e.g. 50 or "50px", "50%") or `"auto"` | | height | false | [String, Number] | 300 | Height in pixels or percents (e.g. 50 or "50px", "50%") or `"auto"` |
| minWidth | false | Number | 0 | The minimum width to which modal can be resized | | minWidth | false | Number (px) | 0 | The minimum width to which modal can be resized |
| minHeight | false | Number | 0 | The minimum height to which modal can be resized | | minHeight | false | Number (px) | 0 | The minimum height to which modal can be resized |
| maxWidth | false | Number (px) | Infinity | The maximum width of the modal (if the value is greater than window width, window width will be used instead |
| maxHeight | false | Number (px) | Infinity | The maximum height of the modal (if the value is greater than window height, window height will be used instead |
| pivotX | false | Number (0 - 1.0) | 0.5 | Horizontal position in %, default is 0.5 (meaning that modal box will be in the middle (50% from left) of the window | | pivotX | false | Number (0 - 1.0) | 0.5 | Horizontal position in %, default is 0.5 (meaning that modal box will be in the middle (50% from left) of the window |
| pivotY | false | Number (0 - 1.0) | 0.5 | Vertical position in %, default is 0.5 (meaning that modal box will be in the middle (50% from top) of the window | | pivotY | false | Number (0 - 1.0) | 0.5 | Vertical position in %, default is 0.5 (meaning that modal box will be in the middle (50% from top) of the window |
@@ -319,6 +369,15 @@ Dont forget about close button :)
</modal> </modal>
``` ```
### Check out
Check out my other projects:
* https://github.com/euvl/vue-notification
* https://github.com/euvl/vue-js-toggle-button
* https://github.com/euvl/vue-js-popover
* https://github.com/euvl/v-clipboard
### Developers ### Developers
To run an example: To run an example:

View File

@@ -7,6 +7,8 @@
<demo-focus-modal/> <demo-focus-modal/>
<demo-size-modal/> <demo-size-modal/>
<modals-container />
<v-dialog <v-dialog
@before-opened="dialogEvent('before-open')" @before-opened="dialogEvent('before-open')"
@before-closed="dialogEvent('before-close')" @before-closed="dialogEvent('before-close')"
@@ -106,6 +108,22 @@
@click="showButtonsDialog"> @click="showButtonsDialog">
Dialog: buttons Dialog: buttons
</button> </button>
<br>
<button
class="btn"
@click="showDynamicRuntimeModal">
Dynamic: Runtime Modal
</button>
<button
class="btn"
@click="showDynamicComponentModal">
Dynamic: Component Modal
</button>
<button
class="btn"
@click="showDynamicComponentModalWithModalParams">
Dynamic: Component Modal with modal params
</button>
</div> </div>
</div> </div>
</template> </template>
@@ -118,6 +136,7 @@ import DemoLoginModal from './components/DemoLoginModal.vue'
import DemoDogProfileModal from './components/DogProfileModal.vue' import DemoDogProfileModal from './components/DogProfileModal.vue'
import DemoConditionalModal from './components/ConditionalModal.vue' import DemoConditionalModal from './components/ConditionalModal.vue'
import DemoSizeModal from './components/SizeModal.vue' import DemoSizeModal from './components/SizeModal.vue'
import CustomComponentModal from './components/CustomComponentModal.vue'
export default { export default {
name: 'app', name: 'app',
@@ -203,6 +222,36 @@ export default {
}) })
}, },
showDynamicRuntimeModal () {
this.$modal.show({
template: `
<div>
<h1>This is created inline</h1>
<p>{{ text }}</p>
</div>
`,
props: ['text']
}, {
text: 'This text is passed as a property'
})
},
showDynamicComponentModal () {
this.$modal.show(CustomComponentModal, {
text: 'This text is passed as a property'
})
},
showDynamicComponentModalWithModalParams () {
this.$modal.show(CustomComponentModal, {
text: 'This text is passed as a property'
}, {
resizable: true,
adaptive: true,
draggable: true,
})
},
dialogEvent (eventName) { dialogEvent (eventName) {
console.log('Dialog event: ' + eventName) console.log('Dialog event: ' + eventName)
} }

View File

@@ -1,6 +1,10 @@
<template> <template>
<modal name="conditional-modal" <modal name="conditional-modal"
:adaptive="true" :adaptive="true"
:max-width="1000"
:max-height="400"
width="80%"
height="50%"
@before-open="beforeOpen"> @before-open="beforeOpen">
<div style="padding:30px; text-align: center"> <div style="padding:30px; text-align: center">
Hello! Hello!
@@ -11,14 +15,14 @@
export default { export default {
name: 'ConditionalModal', name: 'ConditionalModal',
methods: { methods: {
beforeOpen (event) { beforeOpen(event) {
console.log('Event:', event) console.log('Event:', event)
console.log('Params:', event.params) console.log('Params:', event.params)
if (event.params.show === false) { if (event.params.show === false) {
event.stop() event.stop()
} }
}, }
} }
} }
</script> </script>

View File

@@ -0,0 +1,12 @@
<template>
<div>
<h1>This is a custom component</h1>
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
props: ['text']
}
</script>

View File

@@ -3,7 +3,8 @@ import App from './App.vue'
import VueJsModal from 'plugin' import VueJsModal from 'plugin'
Vue.use(VueJsModal, { Vue.use(VueJsModal, {
dialog: true dialog: true,
dynamic: true,
}) })
new Vue({ new Vue({

40
dist/index.js vendored
View File

@@ -207,16 +207,14 @@
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(18); __webpack_require__(18);
var Component = __webpack_require__(1)(__webpack_require__(7), __webpack_require__(15), null, null); var Component = __webpack_require__(1)(__webpack_require__(7), __webpack_require__(15), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Dialog.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Dialog.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(19); __webpack_require__(19);
var Component = __webpack_require__(1)(__webpack_require__(8), __webpack_require__(16), null, null); var Component = __webpack_require__(1)(__webpack_require__(8), __webpack_require__(16), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Modal.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Modal.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
@@ -349,6 +347,14 @@
return value >= 0; return value >= 0;
} }
}, },
maxWidth: {
type: Number,
default: 1 / 0
},
maxHeight: {
type: Number,
default: 1 / 0
},
width: { width: {
type: [ Number, String ], type: [ Number, String ],
default: 600, default: 600,
@@ -467,12 +473,14 @@
}; };
}, },
trueModalWidth: function() { trueModalWidth: function() {
var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width; var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, maxWidth = this.maxWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width, max = Math.min(window.width, maxWidth);
return adaptive ? (0, _util.inRange)(minWidth, window.width, value) : value; return adaptive ? (0, _util.inRange)(minWidth, max, value) : value;
}, },
trueModalHeight: function() { trueModalHeight: function() {
var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height; var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, maxHeight = this.maxHeight, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height;
return isAutoHeight ? this.modal.renderedHeight : adaptive ? (0, _util.inRange)(this.minHeight, this.window.height, value) : value; if (isAutoHeight) return this.modal.renderedHeight;
var max = Math.min(window.height, maxHeight);
return adaptive ? (0, _util.inRange)(this.minHeight, max, value) : value;
}, },
overlayClass: function() { overlayClass: function() {
return { return {
@@ -523,7 +531,9 @@
this.$emit("resize", resizeEvent); this.$emit("resize", resizeEvent);
}, },
toggle: function(state, params) { toggle: function(state, params) {
var reset = this.reset, scrollable = this.scrollable, visible = this.visible, beforeEventName = visible ? "before-close" : "before-open"; var reset = this.reset, scrollable = this.scrollable, visible = this.visible;
if (visible !== state) {
var beforeEventName = visible ? "before-close" : "before-open";
"before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(), "before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(),
reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll"); reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll");
var stopEventExecution = !1, stop = function() { var stopEventExecution = !1, stop = function() {
@@ -534,6 +544,7 @@
params: params params: params
}); });
this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state); this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state);
}
}, },
getDraggableElement: function() { getDraggableElement: function() {
var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable; var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable;
@@ -716,15 +727,15 @@
}; };
exports.default = parse; exports.default = parse;
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-dialog div {\n box-sizing: border-box;\n}\n.vue-dialog .dialog-flex {\n width: 100%;\n height: 100%;\n}\n.vue-dialog .dialog-content {\n flex: 1 0 auto;\n width: 100%;\n padding: 15px;\n font-size: 14px;\n}\n.vue-dialog .dialog-c-title {\n font-weight: 600;\n padding-bottom: 15px;\n}\n.vue-dialog .dialog-c-text {\n}\n.vue-dialog .vue-dialog-buttons {\n display: flex;\n flex: 0 1 auto;\n width: 100%;\n border-top: 1px solid #eee;\n}\n.vue-dialog .vue-dialog-buttons-none {\n width: 100%;\n padding-bottom: 15px;\n}\n.vue-dialog-button {\n font-size: 12px !important;\n background: transparent;\n padding: 0;\n margin: 0;\n border: 0;\n cursor: pointer;\n box-sizing: border-box;\n line-height: 40px;\n height: 40px;\n color: inherit;\n font: inherit;\n outline: none;\n}\n.vue-dialog-button:hover {\n background: rgba(0, 0, 0, 0.01);\n}\n.vue-dialog-button:active {\n background: rgba(0, 0, 0, 0.025);\n}\n.vue-dialog-button:not(:first-of-type) {\n border-left: 1px solid #eee;\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-dialog div {\r\n box-sizing: border-box;\n}\n.vue-dialog .dialog-flex {\r\n width: 100%;\r\n height: 100%;\n}\n.vue-dialog .dialog-content {\r\n flex: 1 0 auto;\r\n width: 100%;\r\n padding: 15px;\r\n font-size: 14px;\n}\n.vue-dialog .dialog-c-title {\r\n font-weight: 600;\r\n padding-bottom: 15px;\n}\n.vue-dialog .dialog-c-text {\n}\n.vue-dialog .vue-dialog-buttons {\r\n display: flex;\r\n flex: 0 1 auto;\r\n width: 100%;\r\n border-top: 1px solid #eee;\n}\n.vue-dialog .vue-dialog-buttons-none {\r\n width: 100%;\r\n padding-bottom: 15px;\n}\n.vue-dialog-button {\r\n font-size: 12px !important;\r\n background: transparent;\r\n padding: 0;\r\n margin: 0;\r\n border: 0;\r\n cursor: pointer;\r\n box-sizing: border-box;\r\n line-height: 40px;\r\n height: 40px;\r\n color: inherit;\r\n font: inherit;\r\n outline: none;\n}\n.vue-dialog-button:hover {\r\n background: rgba(0, 0, 0, 0.01);\n}\n.vue-dialog-button:active {\r\n background: rgba(0, 0, 0, 0.025);\n}\n.vue-dialog-button:not(:first-of-type) {\r\n border-left: 1px solid #eee;\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.v--modal-block-scroll {\n overflow: hidden;\n position: fixed;\n width: 100vw;\n}\n.v--modal-overlay {\n position: fixed;\n box-sizing: border-box;\n left: 0;\n top: 0;\n width: 100%;\n height: 100vh;\n background: rgba(0, 0, 0, 0.2);\n z-index: 999;\n opacity: 1;\n}\n.v--modal-overlay.scrollable {\n height: 100%;\n min-height: 100vh;\n overflow-y: auto;\n padding-bottom: 10px;\n -webkit-overflow-scrolling: touch;\n}\n.v--modal-overlay .v--modal-box {\n position: relative;\n overflow: hidden;\n box-sizing: border-box;\n}\n.v--modal-overlay.scrollable .v--modal-box {\n margin-bottom: 2px;\n /* transition: top 0.2s ease; */\n}\n.v--modal {\n background-color: white;\n text-align: left;\n border-radius: 3px;\n box-shadow: 0 20px 60px -2px rgba(27, 33, 58, 0.4);\n padding: 0;\n}\n.v--modal.v--modal-fullscreen {\n width: 100vw;\n height: 100vh;\n margin: 0;\n left: 0;\n top: 0;\n}\n.v--modal-top-right {\n display: block;\n position: absolute;\n right: 0;\n top: 0;\n}\n.overlay-fade-enter-active,\n.overlay-fade-leave-active {\n transition: all 0.2s;\n}\n.overlay-fade-enter,\n.overlay-fade-leave-active {\n opacity: 0;\n}\n.nice-modal-fade-enter-active,\n.nice-modal-fade-leave-active {\n transition: all 0.4s;\n}\n.nice-modal-fade-enter,\n.nice-modal-fade-leave-active {\n opacity: 0;\n transform: translateY(-20px);\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.v--modal-block-scroll {\r\n position: absolute;\r\n overflow: hidden;\r\n width: 100vw;\n}\n.v--modal-overlay {\r\n position: fixed;\r\n box-sizing: border-box;\r\n left: 0;\r\n top: 0;\r\n width: 100%;\r\n height: 100vh;\r\n background: rgba(0, 0, 0, 0.2);\r\n z-index: 999;\r\n opacity: 1;\n}\n.v--modal-overlay.scrollable {\r\n height: 100%;\r\n min-height: 100vh;\r\n overflow-y: auto;\r\n padding-bottom: 10px;\r\n -webkit-overflow-scrolling: touch;\n}\n.v--modal-overlay .v--modal-box {\r\n position: relative;\r\n overflow: hidden;\r\n box-sizing: border-box;\n}\n.v--modal-overlay.scrollable .v--modal-box {\r\n margin-bottom: 2px;\r\n /* transition: top 0.2s ease; */\n}\n.v--modal {\r\n background-color: white;\r\n text-align: left;\r\n border-radius: 3px;\r\n box-shadow: 0 20px 60px -2px rgba(27, 33, 58, 0.4);\r\n padding: 0;\n}\n.v--modal.v--modal-fullscreen {\r\n width: 100vw;\r\n height: 100vh;\r\n margin: 0;\r\n left: 0;\r\n top: 0;\n}\n.v--modal-top-right {\r\n display: block;\r\n position: absolute;\r\n right: 0;\r\n top: 0;\n}\n.overlay-fade-enter-active,\r\n.overlay-fade-leave-active {\r\n transition: all 0.2s;\n}\n.overlay-fade-enter,\r\n.overlay-fade-leave-active {\r\n opacity: 0;\n}\n.nice-modal-fade-enter-active,\r\n.nice-modal-fade-leave-active {\r\n transition: all 0.4s;\n}\n.nice-modal-fade-enter,\r\n.nice-modal-fade-leave-active {\r\n opacity: 0;\r\n transform: translateY(-20px);\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-modal-resizer {\n display: block;\n overflow: hidden;\n position: absolute;\n width: 12px;\n height: 12px;\n right: 0;\n bottom: 0;\n z-index: 9999999;\n background: transparent;\n cursor: se-resize;\n}\n.vue-modal-resizer::after {\n display: block;\n position: absolute;\n content: '';\n background: transparent;\n left: 0;\n top: 0;\n width: 0;\n height: 0;\n border-bottom: 10px solid #ddd;\n border-left: 10px solid transparent;\n}\n.vue-modal-resizer.clicked::after {\n border-bottom: 10px solid #369be9;\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-modal-resizer {\r\n display: block;\r\n overflow: hidden;\r\n position: absolute;\r\n width: 12px;\r\n height: 12px;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 9999999;\r\n background: transparent;\r\n cursor: se-resize;\n}\n.vue-modal-resizer::after {\r\n display: block;\r\n position: absolute;\r\n content: '';\r\n background: transparent;\r\n left: 0;\r\n top: 0;\r\n width: 0;\r\n height: 0;\r\n border-bottom: 10px solid #ddd;\r\n border-left: 10px solid transparent;\n}\n.vue-modal-resizer.clicked::after {\r\n border-bottom: 10px solid #369be9;\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(20); __webpack_require__(20);
var Component = __webpack_require__(1)(__webpack_require__(9), __webpack_require__(17), null, null); var Component = __webpack_require__(1)(__webpack_require__(9), __webpack_require__(17), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Resizer.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Resizer.vue",
Component.esModule && Object.keys(Component.esModule).some(function(key) { Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."),
@@ -773,6 +784,9 @@
key: i, key: i,
class: button.class || "vue-dialog-button", class: button.class || "vue-dialog-button",
style: _vm.buttonStyle, style: _vm.buttonStyle,
attrs: {
type: "button"
},
domProps: { domProps: {
innerHTML: _vm._s(button.title) innerHTML: _vm._s(button.title)
}, },

40
dist/ssr.index.js vendored
View File

@@ -161,16 +161,14 @@
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(18); __webpack_require__(18);
var Component = __webpack_require__(1)(__webpack_require__(7), __webpack_require__(15), null, null); var Component = __webpack_require__(1)(__webpack_require__(7), __webpack_require__(15), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Dialog.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Dialog.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(19); __webpack_require__(19);
var Component = __webpack_require__(1)(__webpack_require__(8), __webpack_require__(16), null, null); var Component = __webpack_require__(1)(__webpack_require__(8), __webpack_require__(16), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Modal.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Modal.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
@@ -303,6 +301,14 @@
return value >= 0; return value >= 0;
} }
}, },
maxWidth: {
type: Number,
default: 1 / 0
},
maxHeight: {
type: Number,
default: 1 / 0
},
width: { width: {
type: [ Number, String ], type: [ Number, String ],
default: 600, default: 600,
@@ -421,12 +427,14 @@
}; };
}, },
trueModalWidth: function() { trueModalWidth: function() {
var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width; var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, maxWidth = this.maxWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width, max = Math.min(window.width, maxWidth);
return adaptive ? (0, _util.inRange)(minWidth, window.width, value) : value; return adaptive ? (0, _util.inRange)(minWidth, max, value) : value;
}, },
trueModalHeight: function() { trueModalHeight: function() {
var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height; var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, maxHeight = this.maxHeight, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height;
return isAutoHeight ? this.modal.renderedHeight : adaptive ? (0, _util.inRange)(this.minHeight, this.window.height, value) : value; if (isAutoHeight) return this.modal.renderedHeight;
var max = Math.min(window.height, maxHeight);
return adaptive ? (0, _util.inRange)(this.minHeight, max, value) : value;
}, },
overlayClass: function() { overlayClass: function() {
return { return {
@@ -477,7 +485,9 @@
this.$emit("resize", resizeEvent); this.$emit("resize", resizeEvent);
}, },
toggle: function(state, params) { toggle: function(state, params) {
var reset = this.reset, scrollable = this.scrollable, visible = this.visible, beforeEventName = visible ? "before-close" : "before-open"; var reset = this.reset, scrollable = this.scrollable, visible = this.visible;
if (visible !== state) {
var beforeEventName = visible ? "before-close" : "before-open";
"before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(), "before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(),
reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll"); reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll");
var stopEventExecution = !1, stop = function() { var stopEventExecution = !1, stop = function() {
@@ -488,6 +498,7 @@
params: params params: params
}); });
this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state); this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state);
}
}, },
getDraggableElement: function() { getDraggableElement: function() {
var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable; var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable;
@@ -670,15 +681,15 @@
}; };
exports.default = parse; exports.default = parse;
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-dialog div {\n box-sizing: border-box;\n}\n.vue-dialog .dialog-flex {\n width: 100%;\n height: 100%;\n}\n.vue-dialog .dialog-content {\n flex: 1 0 auto;\n width: 100%;\n padding: 15px;\n font-size: 14px;\n}\n.vue-dialog .dialog-c-title {\n font-weight: 600;\n padding-bottom: 15px;\n}\n.vue-dialog .dialog-c-text {\n}\n.vue-dialog .vue-dialog-buttons {\n display: flex;\n flex: 0 1 auto;\n width: 100%;\n border-top: 1px solid #eee;\n}\n.vue-dialog .vue-dialog-buttons-none {\n width: 100%;\n padding-bottom: 15px;\n}\n.vue-dialog-button {\n font-size: 12px !important;\n background: transparent;\n padding: 0;\n margin: 0;\n border: 0;\n cursor: pointer;\n box-sizing: border-box;\n line-height: 40px;\n height: 40px;\n color: inherit;\n font: inherit;\n outline: none;\n}\n.vue-dialog-button:hover {\n background: rgba(0, 0, 0, 0.01);\n}\n.vue-dialog-button:active {\n background: rgba(0, 0, 0, 0.025);\n}\n.vue-dialog-button:not(:first-of-type) {\n border-left: 1px solid #eee;\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-dialog div {\r\n box-sizing: border-box;\n}\n.vue-dialog .dialog-flex {\r\n width: 100%;\r\n height: 100%;\n}\n.vue-dialog .dialog-content {\r\n flex: 1 0 auto;\r\n width: 100%;\r\n padding: 15px;\r\n font-size: 14px;\n}\n.vue-dialog .dialog-c-title {\r\n font-weight: 600;\r\n padding-bottom: 15px;\n}\n.vue-dialog .dialog-c-text {\n}\n.vue-dialog .vue-dialog-buttons {\r\n display: flex;\r\n flex: 0 1 auto;\r\n width: 100%;\r\n border-top: 1px solid #eee;\n}\n.vue-dialog .vue-dialog-buttons-none {\r\n width: 100%;\r\n padding-bottom: 15px;\n}\n.vue-dialog-button {\r\n font-size: 12px !important;\r\n background: transparent;\r\n padding: 0;\r\n margin: 0;\r\n border: 0;\r\n cursor: pointer;\r\n box-sizing: border-box;\r\n line-height: 40px;\r\n height: 40px;\r\n color: inherit;\r\n font: inherit;\r\n outline: none;\n}\n.vue-dialog-button:hover {\r\n background: rgba(0, 0, 0, 0.01);\n}\n.vue-dialog-button:active {\r\n background: rgba(0, 0, 0, 0.025);\n}\n.vue-dialog-button:not(:first-of-type) {\r\n border-left: 1px solid #eee;\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.v--modal-block-scroll {\n overflow: hidden;\n position: fixed;\n width: 100vw;\n}\n.v--modal-overlay {\n position: fixed;\n box-sizing: border-box;\n left: 0;\n top: 0;\n width: 100%;\n height: 100vh;\n background: rgba(0, 0, 0, 0.2);\n z-index: 999;\n opacity: 1;\n}\n.v--modal-overlay.scrollable {\n height: 100%;\n min-height: 100vh;\n overflow-y: auto;\n padding-bottom: 10px;\n -webkit-overflow-scrolling: touch;\n}\n.v--modal-overlay .v--modal-box {\n position: relative;\n overflow: hidden;\n box-sizing: border-box;\n}\n.v--modal-overlay.scrollable .v--modal-box {\n margin-bottom: 2px;\n /* transition: top 0.2s ease; */\n}\n.v--modal {\n background-color: white;\n text-align: left;\n border-radius: 3px;\n box-shadow: 0 20px 60px -2px rgba(27, 33, 58, 0.4);\n padding: 0;\n}\n.v--modal.v--modal-fullscreen {\n width: 100vw;\n height: 100vh;\n margin: 0;\n left: 0;\n top: 0;\n}\n.v--modal-top-right {\n display: block;\n position: absolute;\n right: 0;\n top: 0;\n}\n.overlay-fade-enter-active,\n.overlay-fade-leave-active {\n transition: all 0.2s;\n}\n.overlay-fade-enter,\n.overlay-fade-leave-active {\n opacity: 0;\n}\n.nice-modal-fade-enter-active,\n.nice-modal-fade-leave-active {\n transition: all 0.4s;\n}\n.nice-modal-fade-enter,\n.nice-modal-fade-leave-active {\n opacity: 0;\n transform: translateY(-20px);\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.v--modal-block-scroll {\r\n position: absolute;\r\n overflow: hidden;\r\n width: 100vw;\n}\n.v--modal-overlay {\r\n position: fixed;\r\n box-sizing: border-box;\r\n left: 0;\r\n top: 0;\r\n width: 100%;\r\n height: 100vh;\r\n background: rgba(0, 0, 0, 0.2);\r\n z-index: 999;\r\n opacity: 1;\n}\n.v--modal-overlay.scrollable {\r\n height: 100%;\r\n min-height: 100vh;\r\n overflow-y: auto;\r\n padding-bottom: 10px;\r\n -webkit-overflow-scrolling: touch;\n}\n.v--modal-overlay .v--modal-box {\r\n position: relative;\r\n overflow: hidden;\r\n box-sizing: border-box;\n}\n.v--modal-overlay.scrollable .v--modal-box {\r\n margin-bottom: 2px;\r\n /* transition: top 0.2s ease; */\n}\n.v--modal {\r\n background-color: white;\r\n text-align: left;\r\n border-radius: 3px;\r\n box-shadow: 0 20px 60px -2px rgba(27, 33, 58, 0.4);\r\n padding: 0;\n}\n.v--modal.v--modal-fullscreen {\r\n width: 100vw;\r\n height: 100vh;\r\n margin: 0;\r\n left: 0;\r\n top: 0;\n}\n.v--modal-top-right {\r\n display: block;\r\n position: absolute;\r\n right: 0;\r\n top: 0;\n}\n.overlay-fade-enter-active,\r\n.overlay-fade-leave-active {\r\n transition: all 0.2s;\n}\n.overlay-fade-enter,\r\n.overlay-fade-leave-active {\r\n opacity: 0;\n}\n.nice-modal-fade-enter-active,\r\n.nice-modal-fade-leave-active {\r\n transition: all 0.4s;\n}\n.nice-modal-fade-enter,\r\n.nice-modal-fade-leave-active {\r\n opacity: 0;\r\n transform: translateY(-20px);\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-modal-resizer {\n display: block;\n overflow: hidden;\n position: absolute;\n width: 12px;\n height: 12px;\n right: 0;\n bottom: 0;\n z-index: 9999999;\n background: transparent;\n cursor: se-resize;\n}\n.vue-modal-resizer::after {\n display: block;\n position: absolute;\n content: '';\n background: transparent;\n left: 0;\n top: 0;\n width: 0;\n height: 0;\n border-bottom: 10px solid #ddd;\n border-left: 10px solid transparent;\n}\n.vue-modal-resizer.clicked::after {\n border-bottom: 10px solid #369be9;\n}\n", "" ]); exports = module.exports = __webpack_require__(0)(), exports.push([ module.i, "\n.vue-modal-resizer {\r\n display: block;\r\n overflow: hidden;\r\n position: absolute;\r\n width: 12px;\r\n height: 12px;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 9999999;\r\n background: transparent;\r\n cursor: se-resize;\n}\n.vue-modal-resizer::after {\r\n display: block;\r\n position: absolute;\r\n content: '';\r\n background: transparent;\r\n left: 0;\r\n top: 0;\r\n width: 0;\r\n height: 0;\r\n border-bottom: 10px solid #ddd;\r\n border-left: 10px solid transparent;\n}\n.vue-modal-resizer.clicked::after {\r\n border-bottom: 10px solid #369be9;\n}\r\n", "" ]);
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(20); __webpack_require__(20);
var Component = __webpack_require__(1)(__webpack_require__(9), __webpack_require__(17), null, null); var Component = __webpack_require__(1)(__webpack_require__(9), __webpack_require__(17), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Resizer.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Resizer.vue",
Component.esModule && Object.keys(Component.esModule).some(function(key) { Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."),
@@ -727,6 +738,9 @@
key: i, key: i,
class: button.class || "vue-dialog-button", class: button.class || "vue-dialog-button",
style: _vm.buttonStyle, style: _vm.buttonStyle,
attrs: {
type: "button"
},
domProps: { domProps: {
innerHTML: _vm._s(button.title) innerHTML: _vm._s(button.title)
}, },

34
dist/ssr.nocss.js vendored
View File

@@ -98,16 +98,14 @@
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(9); __webpack_require__(9);
var Component = __webpack_require__(0)(__webpack_require__(5), __webpack_require__(13), null, null); var Component = __webpack_require__(0)(__webpack_require__(5), __webpack_require__(13), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Dialog.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Dialog.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Dialog.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
}, function(module, exports, __webpack_require__) { }, function(module, exports, __webpack_require__) {
__webpack_require__(10); __webpack_require__(10);
var Component = __webpack_require__(0)(__webpack_require__(6), __webpack_require__(14), null, null); var Component = __webpack_require__(0)(__webpack_require__(6), __webpack_require__(14), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Modal.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Modal.vue", Component.esModule && Object.keys(Component.esModule).some(function(key) {
Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Modal.vue: functional components are not supported with templates, they should use render functions."),
module.exports = Component.exports; module.exports = Component.exports;
@@ -240,6 +238,14 @@
return value >= 0; return value >= 0;
} }
}, },
maxWidth: {
type: Number,
default: 1 / 0
},
maxHeight: {
type: Number,
default: 1 / 0
},
width: { width: {
type: [ Number, String ], type: [ Number, String ],
default: 600, default: 600,
@@ -358,12 +364,14 @@
}; };
}, },
trueModalWidth: function() { trueModalWidth: function() {
var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width; var window = this.window, modal = this.modal, adaptive = this.adaptive, minWidth = this.minWidth, maxWidth = this.maxWidth, value = "%" === modal.widthType ? window.width / 100 * modal.width : modal.width, max = Math.min(window.width, maxWidth);
return adaptive ? (0, _util.inRange)(minWidth, window.width, value) : value; return adaptive ? (0, _util.inRange)(minWidth, max, value) : value;
}, },
trueModalHeight: function() { trueModalHeight: function() {
var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height; var window = this.window, modal = this.modal, isAutoHeight = this.isAutoHeight, adaptive = this.adaptive, maxHeight = this.maxHeight, value = "%" === modal.heightType ? window.height / 100 * modal.height : modal.height;
return isAutoHeight ? this.modal.renderedHeight : adaptive ? (0, _util.inRange)(this.minHeight, this.window.height, value) : value; if (isAutoHeight) return this.modal.renderedHeight;
var max = Math.min(window.height, maxHeight);
return adaptive ? (0, _util.inRange)(this.minHeight, max, value) : value;
}, },
overlayClass: function() { overlayClass: function() {
return { return {
@@ -414,7 +422,9 @@
this.$emit("resize", resizeEvent); this.$emit("resize", resizeEvent);
}, },
toggle: function(state, params) { toggle: function(state, params) {
var reset = this.reset, scrollable = this.scrollable, visible = this.visible, beforeEventName = visible ? "before-close" : "before-open"; var reset = this.reset, scrollable = this.scrollable, visible = this.visible;
if (visible !== state) {
var beforeEventName = visible ? "before-close" : "before-open";
"before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(), "before-open" === beforeEventName ? (document.activeElement && document.activeElement.blur(),
reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll"); reset && (this.setInitialSize(), this.shift.left = 0, this.shift.top = 0), scrollable && document.body.classList.add("v--modal-block-scroll")) : scrollable && document.body.classList.remove("v--modal-block-scroll");
var stopEventExecution = !1, stop = function() { var stopEventExecution = !1, stop = function() {
@@ -425,6 +435,7 @@
params: params params: params
}); });
this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state); this.$emit(beforeEventName, beforeEvent), stopEventExecution || (this.visible = state);
}
}, },
getDraggableElement: function() { getDraggableElement: function() {
var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable; var selector = "string" != typeof this.draggable ? ".v--modal-box" : this.draggable;
@@ -609,7 +620,7 @@
}, function(module, exports) {}, function(module, exports) {}, function(module, exports) {}, function(module, exports, __webpack_require__) { }, function(module, exports) {}, function(module, exports) {}, function(module, exports) {}, function(module, exports, __webpack_require__) {
__webpack_require__(11); __webpack_require__(11);
var Component = __webpack_require__(0)(__webpack_require__(7), __webpack_require__(15), null, null); var Component = __webpack_require__(0)(__webpack_require__(7), __webpack_require__(15), null, null);
Component.options.__file = "/Users/yev.vlasenko2/Projects/vue/vue-js-modal/src/Resizer.vue", Component.options.__file = "D:\\Projects\\vue\\vue-js-modal\\src\\Resizer.vue",
Component.esModule && Object.keys(Component.esModule).some(function(key) { Component.esModule && Object.keys(Component.esModule).some(function(key) {
return "default" !== key && "__esModule" !== key; return "default" !== key && "__esModule" !== key;
}) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."), }) && console.error("named exports are not supported in *.vue files."), Component.options.functional && console.error("[vue-loader] Resizer.vue: functional components are not supported with templates, they should use render functions."),
@@ -658,6 +669,9 @@
key: i, key: i,
class: button.class || "vue-dialog-button", class: button.class || "vue-dialog-button",
style: _vm.buttonStyle, style: _vm.buttonStyle,
attrs: {
type: "button"
},
domProps: { domProps: {
innerHTML: _vm._s(button.title) innerHTML: _vm._s(button.title)
}, },

2
dist/styles.css vendored
View File

@@ -1,7 +1,7 @@
.v--modal-block-scroll { .v--modal-block-scroll {
position: absolute;
overflow: hidden; overflow: hidden;
position: fixed;
width: 100vw; width: 100vw;
} }
.v--modal-overlay { .v--modal-overlay {

View File

@@ -1,7 +1,7 @@
{ {
"name": "vue-js-modal", "name": "vue-js-modal",
"description": "Modal Component for Vue.js", "description": "Modal Component for Vue.js",
"version": "1.3.7", "version": "1.3.10",
"author": "euvl <yev.vlasenko@gmail.com>", "author": "euvl <yev.vlasenko@gmail.com>",
"main": "dist/index.js", "main": "dist/index.js",
"repository": { "repository": {
@@ -19,16 +19,14 @@
"url": "https://github.com/euvl/vue-js-modal/issues" "url": "https://github.com/euvl/vue-js-modal/issues"
}, },
"scripts": { "scripts": {
"build:client": "build:client": "webpack --config ./build/webpack.client.config.js --progress --hide-modules",
"webpack --config ./build/webpack.client.config.js --progress --hide-modules", "build:ssr": "webpack --config ./build/webpack.ssr.config.js --progress --hide-modules",
"build:ssr": "build:ssr-no-css": "webpack --config ./build/webpack.ssr-no-css.config.js --progress --hide-modules",
"webpack --config ./build/webpack.ssr.config.js --progress --hide-modules",
"build:ssr-no-css":
"webpack --config ./build/webpack.ssr-no-css.config.js --progress --hide-modules",
"lint": "eslint --ext .js,.vue src test/unit/specs", "lint": "eslint --ext .js,.vue src test/unit/specs",
"unit": "./node_modules/karma/bin/karma start test/unit/karma.conf.js", "unit": "./node_modules/karma/bin/karma start test/unit/karma.conf.js",
"build": "build":
"npm run unit && npm run build:client && npm run build:ssr && npm run build:ssr-no-css", "npm run unit && npm run build:client && npm run build:ssr && npm run build:ssr-no-css",
"watch": "webpack --config ./build/webpack.client.config.js --progress --hide-modules --watch",
"test:types": "tsc -p types/test" "test:types": "tsc -p types/test"
}, },
"license": "MIT", "license": "MIT",

View File

@@ -27,6 +27,7 @@
<button <button
v-for="(button, i) in buttons" v-for="(button, i) in buttons"
:class="button.class || 'vue-dialog-button'" :class="button.class || 'vue-dialog-button'"
type="button"
:style="buttonStyle" :style="buttonStyle"
:key="i" :key="i"
v-html="button.title" v-html="button.title"
@@ -54,40 +55,40 @@ export default {
default: 'fade' default: 'fade'
} }
}, },
data() { data () {
return { return {
params: {}, params: {},
defaultButtons: [{ title: 'CLOSE' }] defaultButtons: [{ title: 'CLOSE' }]
} }
}, },
computed: { computed: {
buttons() { buttons () {
return this.params.buttons || this.defaultButtons return this.params.buttons || this.defaultButtons
}, },
/** /**
* Returns FLEX style with correct width for arbitrary number of * Returns FLEX style with correct width for arbitrary number of
* buttons. * buttons.
*/ */
buttonStyle() { buttonStyle () {
return { return {
flex: `1 1 ${100 / this.buttons.length}%` flex: `1 1 ${100 / this.buttons.length}%`
} }
} }
}, },
methods: { methods: {
beforeOpened(event) { beforeOpened (event) {
window.addEventListener('keyup', this.onKeyUp) window.addEventListener('keyup', this.onKeyUp)
this.params = event.params || {} this.params = event.params || {}
this.$emit('before-opened', event) this.$emit('before-opened', event)
}, },
beforeClosed(event) { beforeClosed (event) {
window.removeEventListener('keyup', this.onKeyUp) window.removeEventListener('keyup', this.onKeyUp)
this.params = {} this.params = {}
this.$emit('before-closed', event) this.$emit('before-closed', event)
}, },
click(i, event, source = 'click') { click (i, event, source = 'click') {
const button = this.buttons[i] const button = this.buttons[i]
if (button && typeof button.handler === 'function') { if (button && typeof button.handler === 'function') {
@@ -96,7 +97,7 @@ export default {
this.$modal.hide('dialog') this.$modal.hide('dialog')
} }
}, },
onKeyUp(event) { onKeyUp (event) {
if (event.which === 13 && this.buttons.length > 0) { if (event.which === 13 && this.buttons.length > 0) {
const buttonIndex = const buttonIndex =
this.buttons.length === 1 this.buttons.length === 1

View File

@@ -78,21 +78,29 @@ export default {
minWidth: { minWidth: {
type: Number, type: Number,
default: 0, default: 0,
validator(value) { validator (value) {
return value >= 0 return value >= 0
} }
}, },
minHeight: { minHeight: {
type: Number, type: Number,
default: 0, default: 0,
validator(value) { validator (value) {
return value >= 0 return value >= 0
} }
}, },
maxWidth: {
type: Number,
default: Infinity
},
maxHeight: {
type: Number,
default: Infinity
},
width: { width: {
type: [Number, String], type: [Number, String],
default: 600, default: 600,
validator(value) { validator (value) {
if (typeof value === 'string') { if (typeof value === 'string') {
let width = parseNumber(value) let width = parseNumber(value)
return (width.type === '%' || width.type === 'px') && width.value > 0 return (width.type === '%' || width.type === 'px') && width.value > 0
@@ -104,7 +112,7 @@ export default {
height: { height: {
type: [Number, String], type: [Number, String],
default: 300, default: 300,
validator(value) { validator (value) {
if (typeof value === 'string') { if (typeof value === 'string') {
if (value === 'auto') { if (value === 'auto') {
return true return true
@@ -122,14 +130,14 @@ export default {
pivotX: { pivotX: {
type: Number, type: Number,
default: 0.5, default: 0.5,
validator(value) { validator (value) {
return value >= 0 && value <= 1 return value >= 0 && value <= 1
} }
}, },
pivotY: { pivotY: {
type: Number, type: Number,
default: 0.5, default: 0.5,
validator(value) { validator (value) {
return value >= 0 && value <= 1 return value >= 0 && value <= 1
} }
} }
@@ -137,7 +145,7 @@ export default {
components: { components: {
Resizer Resizer
}, },
data() { data () {
return { return {
visible: false, visible: false,
@@ -174,7 +182,7 @@ export default {
* inside `setTimeout` and `$nextTick`, after the DOM changes. * inside `setTimeout` and `$nextTick`, after the DOM changes.
* This fixes `$refs.modal` `undefined` bug (fixes #15) * This fixes `$refs.modal` `undefined` bug (fixes #15)
*/ */
visible(value) { visible (value) {
if (value) { if (value) {
this.visibility.overlay = true this.visibility.overlay = true
@@ -198,13 +206,13 @@ export default {
} }
} }
}, },
created() { created () {
this.setInitialSize() this.setInitialSize()
}, },
/** /**
* Sets global listeners * Sets global listeners
*/ */
beforeMount() { beforeMount () {
Modal.event.$on('toggle', (name, state, params) => { Modal.event.$on('toggle', (name, state, params) => {
if (name === this.name) { if (name === this.name) {
if (typeof state === 'undefined') { if (typeof state === 'undefined') {
@@ -239,7 +247,7 @@ export default {
* simply stay at its initial height (won't crash). * simply stay at its initial height (won't crash).
* (Provide polyfill to support IE < 11) * (Provide polyfill to support IE < 11)
*/ */
const MutationObserver = (function() { const MutationObserver = (function () {
const prefixes = ['', 'WebKit', 'Moz', 'O', 'Ms'] const prefixes = ['', 'WebKit', 'Moz', 'O', 'Ms']
for (let i = 0; i < prefixes.length; i++) { for (let i = 0; i < prefixes.length; i++) {
@@ -266,7 +274,7 @@ export default {
/** /**
* Removes "resize" window listener * Removes "resize" window listener
*/ */
beforeDestroy() { beforeDestroy () {
window.removeEventListener('resize', this.onWindowResize) window.removeEventListener('resize', this.onWindowResize)
if (this.clickToClose) { if (this.clickToClose) {
@@ -277,14 +285,14 @@ export default {
/** /**
* Returns true if height is set to "auto" * Returns true if height is set to "auto"
*/ */
isAutoHeight() { isAutoHeight () {
return this.modal.heightType === 'auto' return this.modal.heightType === 'auto'
}, },
/** /**
* Calculates and returns modal position based on the * Calculates and returns modal position based on the
* pivots, window size and modal size * pivots, window size and modal size
*/ */
position() { position () {
const { const {
window, window,
shift, shift,
@@ -309,13 +317,15 @@ export default {
* Returns pixel width (if set with %) and makes sure that modal size * Returns pixel width (if set with %) and makes sure that modal size
* fits the window * fits the window
*/ */
trueModalWidth() { trueModalWidth () {
const { window, modal, adaptive, minWidth } = this const { window, modal, adaptive, minWidth, maxWidth } = this
const value = const value =
modal.widthType === '%' ? window.width / 100 * modal.width : modal.width modal.widthType === '%' ? window.width / 100 * modal.width : modal.width
return adaptive ? inRange(minWidth, window.width, value) : value const max = Math.min(window.width, maxWidth)
return adaptive ? inRange(minWidth, max, value) : value
}, },
/** /**
* Returns pixel height (if set with %) and makes sure that modal size * Returns pixel height (if set with %) and makes sure that modal size
@@ -323,8 +333,8 @@ export default {
* *
* Returns modal.renderedHeight if height set as "auto" * Returns modal.renderedHeight if height set as "auto"
*/ */
trueModalHeight() { trueModalHeight () {
const { window, modal, isAutoHeight, adaptive } = this const { window, modal, isAutoHeight, adaptive, maxHeight } = this
const value = const value =
modal.heightType === '%' modal.heightType === '%'
@@ -336,14 +346,14 @@ export default {
return this.modal.renderedHeight return this.modal.renderedHeight
} }
return adaptive const max = Math.min(window.height, maxHeight)
? inRange(this.minHeight, this.window.height, value)
: value return adaptive ? inRange(this.minHeight, max, value) : value
}, },
/** /**
* Returns class list for screen overlay (modal background) * Returns class list for screen overlay (modal background)
*/ */
overlayClass() { overlayClass () {
return { return {
'v--modal-overlay': true, 'v--modal-overlay': true,
scrollable: this.scrollable && this.isAutoHeight scrollable: this.scrollable && this.isAutoHeight
@@ -352,13 +362,13 @@ export default {
/** /**
* Returns class list for modal itself * Returns class list for modal itself
*/ */
modalClass() { modalClass () {
return ['v--modal-box', this.classes] return ['v--modal-box', this.classes]
}, },
/** /**
* CSS styles for position and size of the modal * CSS styles for position and size of the modal
*/ */
modalStyle() { modalStyle () {
return { return {
top: this.position.top + 'px', top: this.position.top + 'px',
left: this.position.left + 'px', left: this.position.left + 'px',
@@ -373,10 +383,10 @@ export default {
* if "reset" flag is set to true - this function will be called * if "reset" flag is set to true - this function will be called
* every time "beforeOpen" is triggered * every time "beforeOpen" is triggered
*/ */
setInitialSize() { setInitialSize () {
let { modal } = this const { modal } = this
let width = parseNumber(this.width) const width = parseNumber(this.width)
let height = parseNumber(this.height) const height = parseNumber(this.height)
modal.width = width.value modal.width = width.value
modal.widthType = width.type modal.widthType = width.type
@@ -384,13 +394,13 @@ export default {
modal.heightType = height.type modal.heightType = height.type
}, },
onEscapeKeyUp(event) { onEscapeKeyUp (event) {
if (event.which === 27 && this.visible) { if (event.which === 27 && this.visible) {
this.$modal.hide(this.name) this.$modal.hide(this.name)
} }
}, },
onWindowResize() { onWindowResize () {
this.window.width = window.innerWidth this.window.width = window.innerWidth
this.window.height = window.innerHeight this.window.height = window.innerHeight
}, },
@@ -398,8 +408,8 @@ export default {
/** /**
* Generates event object * Generates event object
*/ */
genEventObject(params) { genEventObject (params) {
var eventData = { const eventData = {
name: this.name, name: this.name,
timestamp: Date.now(), timestamp: Date.now(),
canceled: false, canceled: false,
@@ -411,7 +421,7 @@ export default {
/** /**
* Event handler which is triggered on modal resize * Event handler which is triggered on modal resize
*/ */
onModalResize(event) { onModalResize (event) {
this.modal.widthType = 'px' this.modal.widthType = 'px'
this.modal.width = event.size.width this.modal.width = event.size.width
@@ -424,13 +434,13 @@ export default {
this.$emit('resize', resizeEvent) this.$emit('resize', resizeEvent)
}, },
/** /**
* Event handler which is triggered on $modal.show and $modal.hight * Event handler which is triggered on $modal.show and $modal.hide
* BeforeEvents: ('before-close' and 'before-open') are `$emit`ed here, * BeforeEvents: ('before-close' and 'before-open') are `$emit`ed here,
* but AfterEvents ('opened' and 'closed') are moved to `watch.visible`. * but AfterEvents ('opened' and 'closed') are moved to `watch.visible`.
*/ */
toggle(state, params) { toggle (state, params) {
const { reset, scrollable, visible } = this const { reset, scrollable, visible } = this
if (visible === state) return
const beforeEventName = visible ? 'before-close' : 'before-open' const beforeEventName = visible ? 'before-close' : 'before-open'
if (beforeEventName === 'before-open') { if (beforeEventName === 'before-open') {
@@ -474,12 +484,13 @@ export default {
} }
}, },
getDraggableElement() { getDraggableElement () {
var selector = var selector =
typeof this.draggable !== 'string' ? '.v--modal-box' : this.draggable typeof this.draggable !== 'string' ? '.v--modal-box' : this.draggable
if (selector) { if (selector) {
var handler = this.$refs.overlay.querySelector(selector) const handler = this.$refs.overlay.querySelector(selector)
if (handler) { if (handler) {
return handler return handler
} }
@@ -488,13 +499,13 @@ export default {
/** /**
* Event handler that is triggered when background overlay is clicked * Event handler that is triggered when background overlay is clicked
*/ */
onBackgroundClick() { onBackgroundClick () {
if (this.clickToClose) { if (this.clickToClose) {
this.toggle(false) this.toggle(false)
} }
}, },
addDraggableListeners() { addDraggableListeners () {
if (!this.draggable) { if (!this.draggable) {
return return
} }
@@ -559,7 +570,7 @@ export default {
} }
}, },
removeDraggableListeners() { removeDraggableListeners () {
// console.log('removing draggable handlers') // console.log('removing draggable handlers')
}, },
@@ -570,7 +581,7 @@ export default {
* wrapping afterEvents in `$nextTick` fixes `$refs.modal` undefined bug. * wrapping afterEvents in `$nextTick` fixes `$refs.modal` undefined bug.
* (fixes #15) * (fixes #15)
*/ */
callAfterEvent(state) { callAfterEvent (state) {
if (state) { if (state) {
this.connectObserver() this.connectObserver()
} else { } else {
@@ -589,7 +600,7 @@ export default {
* 1. modal opened * 1. modal opened
* 2. MutationObserver's observe callback * 2. MutationObserver's observe callback
*/ */
updateRenderedHeight() { updateRenderedHeight () {
if (this.$refs.modal) { if (this.$refs.modal) {
this.modal.renderedHeight = this.$refs.modal.getBoundingClientRect().height this.modal.renderedHeight = this.$refs.modal.getBoundingClientRect().height
} }
@@ -599,7 +610,7 @@ export default {
* Start observing modal's DOM, if childList or subtree changes, * Start observing modal's DOM, if childList or subtree changes,
* the callback (registered in beforeMount) will be called. * the callback (registered in beforeMount) will be called.
*/ */
connectObserver() { connectObserver () {
if (this.mutationObserver) { if (this.mutationObserver) {
this.mutationObserver.observe(this.$refs.modal, { this.mutationObserver.observe(this.$refs.modal, {
childList: true, childList: true,
@@ -612,7 +623,7 @@ export default {
/** /**
* Disconnects MutationObserver * Disconnects MutationObserver
*/ */
disconnectObserver() { disconnectObserver () {
if (this.mutationObserver) { if (this.mutationObserver) {
this.mutationObserver.disconnect() this.mutationObserver.disconnect()
} }
@@ -622,8 +633,8 @@ export default {
</script> </script>
<style> <style>
.v--modal-block-scroll { .v--modal-block-scroll {
position: absolute;
overflow: hidden; overflow: hidden;
position: fixed;
width: 100vw; width: 100vw;
} }

50
src/ModalsContainer.vue Normal file
View File

@@ -0,0 +1,50 @@
<template>
<div id="#modals-container">
<modal
v-for="modal in modals"
:key="modal.id"
:name="modal.name"
v-bind="modal.config"
@closed="remove(modal.id)"
>
<component :is="modal.component" v-bind="modal.params"></component>
</modal>
</div>
</template>
<script>
export default {
data () {
return {
uid: 0,
modals: []
}
},
created () {
this.$modal._setDynamicContainer(this)
},
methods: {
add (modal, params, config) {
let id = this.uid++
let name = '_dynamic-modal-' + id
this.modals.push({
id: id,
name: name,
component: modal,
params: params || {},
config: config || {}
})
this.$nextTick(() => {
this.$modal.show(name)
})
},
remove (id) {
for (let i in this.modals) {
if (this.modals[i].id === id) {
this.modals.splice(i, 1)
return
}
}
}
}
}
</script>

View File

@@ -16,22 +16,22 @@ export default {
default: 0 default: 0
} }
}, },
data() { data () {
return { return {
clicked: false, clicked: false,
size: {} size: {}
} }
}, },
mounted() { mounted () {
this.$el.addEventListener('mousedown', this.start, false) this.$el.addEventListener('mousedown', this.start, false)
}, },
computed: { computed: {
className() { className () {
return { 'vue-modal-resizer': true, clicked: this.clicked } return { 'vue-modal-resizer': true, clicked: this.clicked }
} }
}, },
methods: { methods: {
start(event) { start (event) {
this.clicked = true this.clicked = true
window.addEventListener('mousemove', this.mousemove, false) window.addEventListener('mousemove', this.mousemove, false)
@@ -40,7 +40,7 @@ export default {
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
}, },
stop() { stop () {
this.clicked = false this.clicked = false
window.removeEventListener('mousemove', this.mousemove, false) window.removeEventListener('mousemove', this.mousemove, false)
@@ -51,10 +51,10 @@ export default {
size: this.size size: this.size
}) })
}, },
mousemove(event) { mousemove (event) {
this.resize(event) this.resize(event)
}, },
resize(event) { resize (event) {
var el = this.$el.parentElement var el = this.$el.parentElement
if (el) { if (el) {

View File

@@ -1,10 +1,11 @@
import Modal from './Modal.vue' import Modal from './Modal.vue'
import Dialog from './Dialog.vue' import Dialog from './Dialog.vue'
import ModalsContainer from './ModalsContainer.vue'
const defaultComponentName = 'modal' const defaultComponentName = 'modal'
const Plugin = { const Plugin = {
install(Vue, options = {}) { install (Vue, options = {}) {
/** /**
* Makes sure that plugin can be insstalled only once * Makes sure that plugin can be insstalled only once
*/ */
@@ -14,19 +15,31 @@ const Plugin = {
this.installed = true this.installed = true
this.event = new Vue() this.event = new Vue()
this.dynamicContainer = null
/** /**
* Plugin API * Plugin API
*/ */
Vue.prototype.$modal = { Vue.prototype.$modal = {
show(name, params) { _setDynamicContainer (dynamicContainer) {
Plugin.event.$emit('toggle', name, true, params) Plugin.dynamicContainer = dynamicContainer
}, },
show (modal, paramsOrProps, params) {
hide(name, params) { if (typeof modal === 'string') {
Plugin.event.$emit('toggle', modal, true, paramsOrProps)
} else {
if (Plugin.dynamicContainer === null) {
console.warn('[vue-js-modal] In order to render dynamic modals, a <modals-container> component must be present on the page')
} else {
Plugin.dynamicContainer.add(modal, paramsOrProps, params)
}
}
},
hide (name, params) {
Plugin.event.$emit('toggle', name, false, params) Plugin.event.$emit('toggle', name, false, params)
}, },
toggle(name, params) { toggle (name, params) {
Plugin.event.$emit('toggle', name, undefined, params) Plugin.event.$emit('toggle', name, undefined, params)
} }
} }
@@ -41,6 +54,12 @@ const Plugin = {
if (options.dialog) { if (options.dialog) {
Vue.component('v-dialog', Dialog) Vue.component('v-dialog', Dialog)
} }
/**
* Registration of <ModalsContainer/> component
*/
if (options.dynamic) {
Vue.component('modals-container', ModalsContainer)
}
} }
} }

View File

@@ -28,7 +28,8 @@ var getType = value => {
} }
for (var i = 0; i < types.length; i++) { for (var i = 0; i < types.length; i++) {
let type = types[i] const type = types[i]
if (type.regexp.test(value)) { if (type.regexp.test(value)) {
return { return {
type: type.name, type: type.name,

4
types/index.d.ts vendored
View File

@@ -1,4 +1,4 @@
import Vue, { PluginObject } from "vue"; import Vue, { PluginObject, ComponentOptions } from "vue";
declare const VueJSModal: PluginObject<VueJSModalOptions>; declare const VueJSModal: PluginObject<VueJSModalOptions>;
export default VueJSModal; export default VueJSModal;
@@ -9,7 +9,7 @@ export declare interface VueJSModalOptions {
} }
declare interface VModal { declare interface VModal {
show(name: string, params?: object): void; show(modal: string | typeof Vue | ComponentOptions<Vue>, paramsOrProps?: object, params?: object): void;
hide(name: string, params?: object): void; hide(name: string, params?: object): void;
toggle(name: string, params?: object): void; toggle(name: string, params?: object): void;
} }