mirror of
https://github.com/KevinMidboe/vue-js-modal.git
synced 2025-10-29 18:00:20 +00:00
Replaced with the newer version
This commit is contained in:
6
.babelrc
6
.babelrc
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"presets": ["es2015", "stage-2"],
|
||||
"plugins": ["transform-runtime"],
|
||||
"comments": false
|
||||
"presets": [
|
||||
["es2015", { "modules": false }]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -1,2 +0,0 @@
|
||||
build/*.js
|
||||
config/*.js
|
||||
30
.eslintrc.js
30
.eslintrc.js
@@ -1,30 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: 'babel-eslint',
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
},
|
||||
extends: 'airbnb-base',
|
||||
plugins: [
|
||||
'html'
|
||||
],
|
||||
'settings': {
|
||||
'import/resolver': {
|
||||
'webpack': {
|
||||
'config': './webpack.base.config.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
'rules': {
|
||||
// don't require .vue extension when importing
|
||||
'no-new': 0,
|
||||
'prefer-template': 0,
|
||||
'no-unused-vars': 0,
|
||||
'no-console': 0,
|
||||
'import/extensions': ['error', 'always', {
|
||||
'js': 'never',
|
||||
'vue': 'never'
|
||||
}],
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
|
||||
}
|
||||
}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log
|
||||
|
||||
201
LICENSE.md
Normal file
201
LICENSE.md
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
250
Modal/Modal.vue
Normal file
250
Modal/Modal.vue
Normal file
@@ -0,0 +1,250 @@
|
||||
<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"
|
||||
v-bind:class="modalClass"
|
||||
v-bind:style="modalStyle"
|
||||
v-on:mousedown.stop
|
||||
ref="modal">
|
||||
<slot></slot>
|
||||
<resizer v-if="resizable" @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: (this.window.width - this.modal.width) / 2,
|
||||
top: (this.window.height - this.modal.height) / 2
|
||||
}
|
||||
},
|
||||
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) {
|
||||
this.modal.width = this.window.width > this.width
|
||||
? this.width
|
||||
: this.window.width
|
||||
|
||||
this.modal.height = this.window.height > this.height
|
||||
? this.height
|
||||
: this.window.height;
|
||||
}
|
||||
},
|
||||
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;
|
||||
|
||||
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.5s;
|
||||
}
|
||||
|
||||
.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>
|
||||
103
Modal/Resizer.vue
Normal file
103
Modal/Resizer.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div :class="{'vue-modal-resizer': true, 'clicked': clicked}">
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import util from '../util';
|
||||
export default {
|
||||
name: 'Resizer',
|
||||
data() {
|
||||
return {
|
||||
clicked: false,
|
||||
min: {
|
||||
height: 50,
|
||||
width: 0
|
||||
},
|
||||
size: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$el.addEventListener('mousedown', this.start, false);
|
||||
},
|
||||
methods: {
|
||||
start(event) {
|
||||
this.clicked = true;
|
||||
|
||||
window.addEventListener('mousemove', this.mousemove, false);
|
||||
window.addEventListener('mouseup', this.stop, false);
|
||||
|
||||
util.stopEvent(event);
|
||||
},
|
||||
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 (event.clientX < window.innerWidth / 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (el) {
|
||||
var width = event.clientX - el.offsetLeft;
|
||||
var height = event.clientY - el.offsetTop;
|
||||
|
||||
if (height < this.min.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
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>
|
||||
30
Modal/index.js
Normal file
30
Modal/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import Vue from 'vue';
|
||||
import Modal from './Modal.vue';
|
||||
|
||||
const VueModal = {
|
||||
install(Vue, options = {}) {
|
||||
if (!this.hasOwnProperty("event")) {
|
||||
this.event = new Vue();
|
||||
}
|
||||
|
||||
const $modal = {
|
||||
show(name, params) {
|
||||
VueModal.event.$emit('toggle', name, true, params);
|
||||
},
|
||||
hide(name, params) {
|
||||
VueModal.event.$emit('toggle', name, false, params);
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$modal', {
|
||||
get: () => $modal
|
||||
});
|
||||
|
||||
Vue.component('nice-modal', Modal);
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
Vue.use(VueModal);
|
||||
|
||||
export default VueModal;
|
||||
48
README.md
48
README.md
@@ -1,45 +1,7 @@
|
||||
# vue-modal
|
||||
##nice-vue-components
|
||||
|
||||
A simple modal component for Vue.js
|
||||
A collection of vue components
|
||||
|
||||
##Install
|
||||
|
||||
##Usage
|
||||
Example:
|
||||
|
||||
main.js:
|
||||
```js
|
||||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
import VueModal from 'vue-modal';
|
||||
|
||||
Vue.use(VueModal);
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
template: '<App/>',
|
||||
components: { App },
|
||||
});
|
||||
|
||||
```
|
||||
App.vue:
|
||||
```html
|
||||
<template>
|
||||
<div id="app">
|
||||
<h1>Test page</h1>
|
||||
<button @click="modal('basic')">Show modal</button>
|
||||
<modal name="basic">Hello! Im a modal!</modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app',
|
||||
methods: {
|
||||
modal(name) => this.$modal.show(name),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
||||
##License
|
||||
MIT
|
||||
* Beeper
|
||||
* Notification
|
||||
* Modal
|
||||
|
||||
3
dist/vue-modal.js
vendored
3
dist/vue-modal.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<h1>Test page</h1>
|
||||
<button @click="showModal('basic')">Show basic modal</button>
|
||||
<transition name="fade">
|
||||
<modal name="basic">Hello! Im basic modal!</modal>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app',
|
||||
methods: {
|
||||
showModal(name) => this.$modal.show(name),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>vue-modal</title>
|
||||
<title>Examples</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="/dist/build.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
import VueModal from '../src/index';
|
||||
|
||||
Vue.use(VueModal);
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
template: '<App/>',
|
||||
components: { App },
|
||||
});
|
||||
104
examples/src/App.vue
Normal file
104
examples/src/App.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<h2>
|
||||
Beeper
|
||||
<nice-beep class="inline-beep" color="#23d813" :frequency="1200"/>
|
||||
</h2>
|
||||
<div>
|
||||
tl;dr
|
||||
</div>
|
||||
|
||||
<h2>Notifications</h2>
|
||||
<nice-notifications name="example-1" animation="fade"/>
|
||||
<nice-notifications position="bottom left"/>
|
||||
<button @click="notifyExample0">Example 1</button>
|
||||
<button @click="notifyExample1">Example 2</button>
|
||||
|
||||
<h2>Modals</h2>
|
||||
<nice-modal name="example-modal"
|
||||
transition="nice-modal-fade"
|
||||
:delay="200"
|
||||
:adaptive="true"
|
||||
:resizable="true">
|
||||
<div style="height: 100%; box-sizing: border-box; padding: 10px; font-size: 13px; overflow: auto">
|
||||
Appropriately exploit professional infrastructures rather than unique
|
||||
growth strategies. Assertively build leveraged growth strategies
|
||||
vis-a-vis multimedia based vortals. Progressively simplify
|
||||
cross-platform value through interactive imperatives. Objectively
|
||||
implement enabled web services after plug-and-play ROI. Distinctively
|
||||
impact inexpensive schemas before installed base imperatives.
|
||||
Holisticly benchmark pandemic process improvements without wireless
|
||||
experiences.
|
||||
Efficiently create worldwide partnerships after tactical vortals.
|
||||
Uniquely productize enabled platforms vis-a-vis timely processes.
|
||||
Conveniently unleash standards compliant niches through highly
|
||||
efficient testing procedures. Rapidiously enable pandemic niche
|
||||
markets whereas viral markets.
|
||||
Assertively simplify alternative partnerships and error-free
|
||||
e-commerce. Professionally formulate 24/365 internal or "organic"
|
||||
sources through equity invested mindshare. Globally redefine unique
|
||||
best practices for.
|
||||
</div>
|
||||
</nice-modal>
|
||||
<button @click="modalExample0">Example 1</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const ID = ((i) => () => i++)(0);
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
methods: {
|
||||
notifyExample0() {
|
||||
this.$notify({
|
||||
type: 'error',
|
||||
group: 'example-1',
|
||||
title: 'Error message',
|
||||
text: 'This is error message #' + ID()
|
||||
});
|
||||
},
|
||||
notifyExample1() {
|
||||
this.$notify({
|
||||
type: 'warn',
|
||||
duration: 10000,
|
||||
title: 'Warning message',
|
||||
text:
|
||||
`
|
||||
Warning #${ID()} <br>
|
||||
Notification will dissapear in 10 sec<br>
|
||||
Rendering <b>HTML</b>
|
||||
`
|
||||
});
|
||||
},
|
||||
modalExample0() {
|
||||
this.$modal.show('example-modal');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 50px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.inline-beep {
|
||||
display: inline-block;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
8
examples/src/main.js
Normal file
8
examples/src/main.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import Modal from '../../Modal';
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render: h => h(App)
|
||||
});
|
||||
67
package.json
67
package.json
@@ -1,60 +1,31 @@
|
||||
{
|
||||
"name": "vue-modal",
|
||||
"version": "0.0.1",
|
||||
"description": "A Vue.js simple modal dialog component",
|
||||
"name": "examples",
|
||||
"description": "Examples of using components",
|
||||
"version": "1.0.0",
|
||||
"author": "euvl <yev.vlasenko@gmail.com>",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"main": "./dist/vue-modal.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/euvl/vue-modal.git"
|
||||
"private": false,
|
||||
"main": "./components/index.js",
|
||||
"scripts": {
|
||||
"examples": "cross-env NODE_ENV=development webpack-dev-server --open --hot"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-runtime": "^6.18.0",
|
||||
"autoprefixer": "^6.4.0",
|
||||
"vue": "^2.1.10",
|
||||
"babel-core": "^6.0.0",
|
||||
"babel-eslint": "^7.0.0",
|
||||
"babel-loader": "^6.0.0",
|
||||
"babel-plugin-transform-runtime": "^6.0.0",
|
||||
"babel-loader": "^6.2.10",
|
||||
"babel-preset-es2015": "^6.0.0",
|
||||
"babel-preset-stage-2": "^6.0.0",
|
||||
"babel-register": "^6.0.0",
|
||||
"chalk": "^1.1.3",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"cross-env": "^3.0.0",
|
||||
"css-loader": "^0.25.0",
|
||||
"eslint": "^3.7.1",
|
||||
"eslint-friendly-formatter": "^2.0.5",
|
||||
"eslint-loader": "^1.5.0",
|
||||
"eslint-plugin-html": "^1.3.0",
|
||||
"eslint-config-airbnb-base": "^8.0.0",
|
||||
"eslint-import-resolver-webpack": "^0.6.0",
|
||||
"eslint-plugin-import": "^1.16.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"express": "^4.13.3",
|
||||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"file-loader": "^0.9.0",
|
||||
"function-bind": "^1.0.2",
|
||||
"html-webpack-plugin": "^2.8.1",
|
||||
"http-proxy-middleware": "^0.17.2",
|
||||
"json-loader": "^0.5.4",
|
||||
"semver": "^5.3.0",
|
||||
"opn": "^4.0.2",
|
||||
"ora": "^0.3.0",
|
||||
"shelljs": "^0.7.4",
|
||||
"url-loader": "^0.5.7",
|
||||
"vue-loader": "^9.4.0",
|
||||
"vue-style-loader": "^1.0.0",
|
||||
"webpack": "^1.13.2",
|
||||
"webpack-dev-middleware": "^1.8.3",
|
||||
"webpack-hot-middleware": "^2.12.2",
|
||||
"webpack-merge": "^0.14.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
"node-sass": "^4.5.0",
|
||||
"sass-loader": "^5.0.1",
|
||||
"vue-hot-reload-api": "^2.0.8",
|
||||
"vue-loader": "^10.0.0",
|
||||
"vue-style-loader": "^2.0.0",
|
||||
"vue-template-compiler": "^2.1.0",
|
||||
"webpack": "^2.2.0",
|
||||
"webpack-dev-server": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.0.5"
|
||||
"velocity-animate": "^1.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
146
src/Modal.vue
146
src/Modal.vue
@@ -1,146 +0,0 @@
|
||||
<template>
|
||||
<div class="vue-modal-overlay" v-if="visibleOverlay" @click.stop="toggle(false)">
|
||||
<transition :name="transition">
|
||||
<div :class="modalclass" ref="modal" :style="styles" v-show="visibleModal" @click.stop>
|
||||
<template v-if="withTitle">
|
||||
<div class="modal-title">
|
||||
<slot name="title-left"/>
|
||||
<slot name="title-right"/>
|
||||
</div>
|
||||
</template>
|
||||
<slot/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import VueModal from './modal';
|
||||
|
||||
const props = {
|
||||
name: {
|
||||
required: true,
|
||||
type: [String, Number],
|
||||
},
|
||||
withTitle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
position: {
|
||||
type: Array,
|
||||
},
|
||||
transition: {
|
||||
type: String,
|
||||
},
|
||||
classes: {
|
||||
type: [String, Array],
|
||||
default: 'vue-modal',
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 600,
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'Modal',
|
||||
props,
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
visibleModal: false,
|
||||
visibleOverlay: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(value) {
|
||||
if (this.delay > 0) {
|
||||
if (value) {
|
||||
this.visibleOverlay = true;
|
||||
setTimeout(() => { this.visibleModal = true; },
|
||||
this.delay);
|
||||
} else {
|
||||
this.visibleModal = false;
|
||||
setTimeout(() => { this.visibleOverlay = false; },
|
||||
this.delay);
|
||||
}
|
||||
} else {
|
||||
this.visibleOverlay = value;
|
||||
|
||||
Vue.nextTick(() => {
|
||||
this.visibleModal = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
VueModal.event.$on('toggle', (name, state) => {
|
||||
if (name === this.name) {
|
||||
this.toggle(!this.visible);
|
||||
}
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
modalclass() {
|
||||
return ['modal', this.classes];
|
||||
},
|
||||
styles() {
|
||||
return {
|
||||
'margin-left': (-this.width / 2) + 'px',
|
||||
width: this.width + 'px',
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle(state) {
|
||||
const before = this.visible ? 'before-close' : 'before-open';
|
||||
const after = this.visible ? 'opened' : 'closed';
|
||||
|
||||
this.$emit(before, this.name);
|
||||
this.visible = !!state;
|
||||
this.$emit(after, this.name);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vue-modal-overlay {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.vue-modal-fade-enter-active, .vue-modal-fade-leave-active {
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.vue-modal-fade-enter, .vue-modal-fade-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
|
||||
.vue-modal {
|
||||
position: absolute;
|
||||
background: white;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
|
||||
left: 50%;
|
||||
top: 20%;
|
||||
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 20px 60px -2px rgba(27, 33, 58, .4);
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +0,0 @@
|
||||
import VueModal from './modal';
|
||||
|
||||
export default VueModal;
|
||||
43
src/modal.js
43
src/modal.js
@@ -1,43 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import Modal from './Modal.vue';
|
||||
|
||||
const VueModal = {
|
||||
event: new Vue(),
|
||||
install(self, options = {}) {
|
||||
if (this.installed) {
|
||||
return console.log('Modal component is already installed.');
|
||||
}
|
||||
|
||||
this.installed = true;
|
||||
|
||||
const modal = {
|
||||
toggle(name, state, params) {
|
||||
const opts = typeof state === 'object' && typeof params === 'undefined'
|
||||
? state
|
||||
: params;
|
||||
|
||||
VueModal.event
|
||||
.$emit('toggle', name, state);
|
||||
},
|
||||
show(name, params = {}) {
|
||||
VueModal.event
|
||||
.$emit('toggle', name, true);
|
||||
},
|
||||
hide(name, params = {}) {
|
||||
VueModal.event
|
||||
.$emit('toggle', name, false);
|
||||
},
|
||||
};
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$modal', {
|
||||
get() {
|
||||
return modal;
|
||||
},
|
||||
});
|
||||
|
||||
Vue.component('modal', Modal);
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
export default VueModal;
|
||||
@@ -1,26 +0,0 @@
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
path: './dist',
|
||||
publicPath: 'dist/',
|
||||
filename: 'vue-modal.js'
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue'
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel!eslint',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
vue: {
|
||||
loaders: {
|
||||
js: 'babel!eslint'
|
||||
}
|
||||
}
|
||||
};
|
||||
75
webpack.config.js
Normal file
75
webpack.config.js
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
var path = require('path')
|
||||
var webpack = require('webpack')
|
||||
|
||||
module.exports = {
|
||||
entry: './examples/src/main.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
publicPath: '/dist/',
|
||||
filename: 'build.js'
|
||||
},
|
||||
externals: [
|
||||
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
loaders: {
|
||||
'scss': 'vue-style-loader!css-loader!sass-loader',
|
||||
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|svg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]?[hash]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'vue': 'vue/dist/vue.js',
|
||||
'nice-vue-components$': path.resolve(__dirname, './components/index.js')
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
historyApiFallback: true
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
devtool: '#eval-source-map'
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports.devtool = '#source-map'
|
||||
// http://vue-loader.vuejs.org/en/workflow/production.html
|
||||
module.exports.plugins = (module.exports.plugins || []).concat([
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: true,
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
})
|
||||
])
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
var config = require('./webpack.base.config');
|
||||
|
||||
config.devtool = 'eval-source-map';
|
||||
config.devServer = {
|
||||
noInfo: true
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,18 +0,0 @@
|
||||
var webpack = require('webpack');
|
||||
var config = require('./webpack.base.config');
|
||||
|
||||
config.plugins = (config.plugins || []).concat([
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
}),
|
||||
new webpack.optimize.OccurenceOrderPlugin()
|
||||
]);
|
||||
|
||||
module.exports = config;
|
||||
Reference in New Issue
Block a user