Merge pull request #46 from onekiloparsec/master

Allow to use window width and height percentages in modal size.
This commit is contained in:
Yev Vlasenko
2017-07-16 11:24:40 +01:00
committed by GitHub
8 changed files with 454 additions and 179 deletions

View File

@@ -5,6 +5,7 @@
<demo-dog-profile-modal /> <demo-dog-profile-modal />
<demo-conditional-modal/> <demo-conditional-modal/>
<demo-focus-modal/> <demo-focus-modal/>
<demo-size-modal/>
<modal name="example-modal" <modal name="example-modal"
transition="nice-modal-fade" transition="nice-modal-fade"
@@ -55,6 +56,10 @@
@click="$modal.show('demo-login')"> @click="$modal.show('demo-login')">
Demo: Login Demo: Login
</button> </button>
<button class="blue"
@click="$modal.show('size-modal')">
Demo: Size = 60%
</button>
<!-- <!--
<button class="green" <button class="green"
@click="$modal.show('input-focus-modal')"> @click="$modal.show('input-focus-modal')">
@@ -79,6 +84,7 @@ import DemoFocusModal from './components/InputFocusModal.vue'
import DemoLoginModal from './components/DemoLoginModal.vue' 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'
export default { export default {
name: 'app', name: 'app',
@@ -89,7 +95,8 @@ export default {
DemoFocusModal, DemoFocusModal,
DemoLoginModal, DemoLoginModal,
DemoDogProfileModal, DemoDogProfileModal,
DemoConditionalModal DemoConditionalModal,
DemoSizeModal
}, },
data() { data() {
return { return {

View File

@@ -0,0 +1,15 @@
<template>
<modal name="size-modal"
transition="nice-modal-fade"
:min-width="200"
:min-height="200"
:adaptive="true"
width="60%"
height="60%">
<div style="height: 100%; box-sizing: border-box; padding: 10px; font-size: 13px; overflow: auto">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dictum purus egestas libero ornare venenatis. Maecenas pharetra tortor eu tortor imperdiet, a faucibus quam finibus. Nulla id lacinia quam. Praesent imperdiet sed magna non finibus. Aenean blandit, mauris vitae lacinia rutrum, nunc mi scelerisque sem, in laoreet sem lectus ut orci. Ut egestas nulla in vehicula feugiat. Vivamus tincidunt nisi vel risus dictum suscipit. Nulla id blandit mi, vulputate aliquam enim.
Praesent sodales diam a tellus imperdiet condimentum. Mauris malesuada libero elit, sed tincidunt velit consectetur sit amet. Praesent consequat lobortis pellentesque. Donec pellentesque eros sit amet arcu bibendum, vel pharetra purus sodales. Morbi aliquam ac augue eu aliquam. Cras id justo sit amet tortor luctus lobortis. Vestibulum risus urna, cursus vitae feugiat non, tincidunt non massa.
</div>
</modal>
</template>

193
dist/index.js vendored

File diff suppressed because one or more lines are too long

211
dist/ssr.index.js vendored

File diff suppressed because one or more lines are too long

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.2.3", "version": "1.2.4",
"author": "euvl <yev.vlasenko@gmail.com>", "author": "euvl <yev.vlasenko@gmail.com>",
"main": "dist/index.js", "main": "dist/index.js",
"repository": { "repository": {

View File

@@ -19,7 +19,7 @@
<resizer v-if="resizable" <resizer v-if="resizable"
:min-width="minWidth" :min-width="minWidth"
:min-height="minHeight" :min-height="minHeight"
@resize="resize"/> @resize="onModalResize"/>
</div> </div>
</transition> </transition>
</div> </div>
@@ -30,6 +30,7 @@
import Modal from './index' import Modal from './index'
import Resizer from './Resizer.vue' import Resizer from './Resizer.vue'
import { inRange } from './util' import { inRange } from './util'
import parseNumber from './parser'
export default { export default {
name: 'VueJsModal', name: 'VueJsModal',
@@ -75,26 +76,16 @@
return value >= 0 return value >= 0
} }
}, },
maxAdaptiveWidth: {
type: Number,
default: 1
// ,
// validator (value) {
// return value > 0 && value <= 1
// }
},
maxAdaptiveHeight: {
type: Number,
default: 1
// ,
// validator (value) {
// return value > 0 && value <= 1
// }
},
width: { width: {
type: Number, type: [Number, String],
default: 600, default: 600,
validator (value) { validator (value) {
if (typeof value === 'string') {
let width = parseNumber(value)
return (width.type === '%' || width.type === 'px')
&& width.value > 0
}
return value >= 0 return value >= 0
} }
}, },
@@ -103,13 +94,13 @@
default: 300, default: 300,
validator (value) { validator (value) {
if (typeof value === 'string') { if (typeof value === 'string') {
return value === 'auto' let height = parseNumber(value)
return (height.type === '%' || height.type === 'px')
&& height.value > 0
} }
if (typeof value === 'number') {
return value >= 0 return value >= 0
} }
}
}, },
pivotX: { pivotX: {
type: Number, type: Number,
@@ -130,6 +121,9 @@
Resizer Resizer
}, },
data () { data () {
let width = parseNumber(this.width)
let height = parseNumber(this.height)
return { return {
visible: false, visible: false,
@@ -144,23 +138,26 @@
}, },
modal: { modal: {
width: this.width, widthInit: 0,
height: this.height width: width.value,
widthType: width.type,
heightInit: 0,
height: height.value,
heightType: height.type
}, },
window: { window: {
width: 0, width: 0,
height: 0 height: 0
}, }
}
draggableElement: false
};
}, },
watch: { watch: {
visible (value) { visible (value) {
if (value) { if (value) {
this.visibility.overlay = true this.visibility.overlay = true
this.adaptSize() // this.adaptSize()
setTimeout(() => { setTimeout(() => {
this.visibility.modal = true this.visibility.modal = true
@@ -200,11 +197,14 @@
computed: { computed: {
position () { position () {
const { window, modal, shift } = this const { window, modal, shift } = this
const maxLeft = window.width - modal.width
const maxTop = window.height - modal.height
const left = shift.left + this.pivotX * (window.width - modal.width) const maxLeft = window.width - this.trueModalWidth
const top = shift.top + this.pivotY * (window.height - modal.height) const maxTop = window.height - this.trueModalHeight
const left = shift.left +
this.pivotX * (window.width - this.trueModalWidth)
const top = shift.top +
this.pivotY * (window.height - this.trueModalHeight)
return { return {
left: inRange(0, maxLeft, left), left: inRange(0, maxLeft, left),
@@ -212,6 +212,28 @@
} }
}, },
trueModalWidth () {
const { window, modal } = this
const value = modal.widthType === '%'
? window.width / 100 * modal.width
: modal.width
return this.adaptive
? inRange(this.minWidth, this.window.width, value)
: value
},
trueModalHeight () {
const { window, modal } = this
const value = (modal.heightType === '%')
? window.height / 100 * modal.height
: modal.height
return this.adaptive
? inRange(this.minHeight, this.window.height, value)
: value
},
modalClass () { modalClass () {
return ['v--modal-box', this.classes] return ['v--modal-box', this.classes]
}, },
@@ -220,8 +242,8 @@
return { return {
top: this.position.top + 'px', top: this.position.top + 'px',
left: this.position.left + 'px', left: this.position.left + 'px',
width: this.modal.width + 'px', width: this.trueModalWidth + 'px',
height: this.modal.height + 'px' height: this.trueModalHeight + 'px'
} }
} }
}, },
@@ -229,7 +251,6 @@
onWindowResize () { onWindowResize () {
this.window.width = window.innerWidth this.window.width = window.innerWidth
this.window.height = window.innerHeight this.window.height = window.innerHeight
this.adaptSize()
}, },
genEventObject (params) { genEventObject (params) {
@@ -246,27 +267,28 @@
return Vue.util.extend(data, params || {}); return Vue.util.extend(data, params || {});
}, },
/*
adaptSize () { adaptSize () {
if (this.adaptive) { if (this.adaptive) {
this.modal.width = inRange( this.modal.width = inRange(this.minWidth, this.window.width,
0, this.trueModalWidth)
this.window.width * this.maxAdaptiveWidth, this.modal.height = inRange(this.minHeight, this.window.height,
this.modal.width) this.trueModalHeight)
this.modal.height = inRange(
0,
this.window.height * this.maxAdaptiveHeight,
this.modal.height)
} }
}, },
*/
resize (event) { onModalResize (event) {
this.modal.widthType = 'px'
this.modal.width = event.size.width this.modal.width = event.size.width
this.modal.heightType = 'px'
this.modal.height = event.size.height this.modal.height = event.size.height
const { size } = this.modal const { size } = this.modal
const resizeEvent = this.genEventObject({ size }); const resizeEvent = this.genEventObject({ size });
console.log(resizeEvent)
this.$emit('resize', resizeEvent) this.$emit('resize', resizeEvent)
}, },

77
src/parser.js Normal file
View File

@@ -0,0 +1,77 @@
// Parses string with float number and suffix:
// "0.001" => { type: "px", value: 0.001 }
// "0.001px" => { type: "px", value: 0.001 }
// "0.1%" => { type: "px", value: 0.1 }
// "foo" => { type: "", value: "foo" }
var floatRegexp = '[-+]?[0-9]*\.?[0-9]+'
var types = [
// {
// name: 'rem',
// regexp: new RegExp(`^${floatRegexp}rem\$`)
// },
{
name: 'px',
regexp: new RegExp(`^${floatRegexp}px\$`)
},
{
name: '%',
regexp: new RegExp(`^${floatRegexp}%\$`)
},
// Fallback option:
// If no suffix specified, assign to px
{
name: 'px',
regexp: new RegExp(`^${floatRegexp}\$`)
}
]
var getType = (value) => {
for (var i = 0; i < types.length; i++) {
let type = types[i]
if (type.regexp.test(value)) {
return {
type: type.name,
value: parseFloat(value)
}
}
}
return {
type: '',
value: value
}
}
var parse = (value) => {
switch (typeof value) {
case 'number':
return { type: 'px', value }
case 'string':
return getType(value)
default:
return { type: '', value }
}
}
export default parse
/// tests
/*
console.log(parse(10))
console.log(parse(10.10))
console.log(parse(-10))
console.log(parse('5%'))
console.log(parse('-5%'))
console.log(parse('5.123%'))
console.log(parse('5px'))
console.log(parse('-5px'))
console.log(parse('5.123px'))
console.log(parse("adasd%"))
console.log(parse(""))
console.log(parse("+2-3px")) // fails
*/