quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
207 lines (169 loc) • 5.78 kB
JavaScript
import { h, ref, computed, watch, nextTick, getCurrentInstance } from 'vue'
import TouchPan from '../../directives/TouchPan.js'
import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
import { createComponent } from '../../utils/private/create.js'
import { hSlot, hMergeSlot, hDir } from '../../utils/private/render.js'
export default createComponent({
name: 'QSplitter',
props: {
...useDarkProps,
modelValue: {
type: Number,
required: true
},
reverse: Boolean,
unit: {
type: String,
default: '%',
validator: v => [ '%', 'px' ].includes(v)
},
limits: {
type: Array,
validator: v => {
if (v.length !== 2) return false
if (typeof v[ 0 ] !== 'number' || typeof v[ 1 ] !== 'number') return false
return v[ 0 ] >= 0 && v[ 0 ] <= v[ 1 ]
}
},
emitImmediately: Boolean,
horizontal: Boolean,
disable: Boolean,
beforeClass: [ Array, String, Object ],
afterClass: [ Array, String, Object ],
separatorClass: [ Array, String, Object ],
separatorStyle: [ Array, String, Object ]
},
emits: [ 'update:modelValue' ],
setup (props, { slots, emit }) {
const { proxy: { $q } } = getCurrentInstance()
const isDark = useDark(props, $q)
const rootRef = ref(null)
const sideRefs = {
before: ref(null),
after: ref(null)
}
const classes = computed(() =>
'q-splitter no-wrap '
+ `${ props.horizontal === true ? 'q-splitter--horizontal column' : 'q-splitter--vertical row' }`
+ ` q-splitter--${ props.disable === true ? 'disabled' : 'workable' }`
+ (isDark.value === true ? ' q-splitter--dark' : '')
)
const propName = computed(() => (props.horizontal === true ? 'height' : 'width'))
const side = computed(() => (props.reverse !== true ? 'before' : 'after'))
const computedLimits = computed(() => (
props.limits !== void 0
? props.limits
: (props.unit === '%' ? [ 10, 90 ] : [ 50, Infinity ])
))
function getCSSValue (value) {
return (props.unit === '%' ? value : Math.round(value)) + props.unit
}
const styles = computed(() => ({
[ side.value ]: {
[ propName.value ]: getCSSValue(props.modelValue)
}
}))
let __dir, __maxValue, __value, __multiplier, __normalized
function pan (evt) {
if (evt.isFirst === true) {
const size = rootRef.value.getBoundingClientRect()[ propName.value ]
__dir = props.horizontal === true ? 'up' : 'left'
__maxValue = props.unit === '%' ? 100 : size
__value = Math.min(__maxValue, computedLimits.value[ 1 ], Math.max(computedLimits.value[ 0 ], props.modelValue))
__multiplier = (props.reverse !== true ? 1 : -1)
* (props.horizontal === true ? 1 : ($q.lang.rtl === true ? -1 : 1))
* (props.unit === '%' ? (size === 0 ? 0 : 100 / size) : 1)
rootRef.value.classList.add('q-splitter--active')
return
}
if (evt.isFinal === true) {
if (__normalized !== props.modelValue) {
emit('update:modelValue', __normalized)
}
rootRef.value.classList.remove('q-splitter--active')
return
}
const val = __value
+ __multiplier
* (evt.direction === __dir ? -1 : 1)
* evt.distance[ props.horizontal === true ? 'y' : 'x' ]
__normalized = Math.min(__maxValue, computedLimits.value[ 1 ], Math.max(computedLimits.value[ 0 ], val))
sideRefs[ side.value ].value.style[ propName.value ] = getCSSValue(__normalized)
if (props.emitImmediately === true && props.modelValue !== __normalized) {
emit('update:modelValue', __normalized)
}
}
const sepDirective = computed(() => {
// if props.disable !== true
return [ [
TouchPan,
pan,
void 0,
{
[ props.horizontal === true ? 'vertical' : 'horizontal' ]: true,
prevent: true,
stop: true,
mouse: true,
mouseAllDir: true
}
] ]
})
function normalize (val, limits) {
if (val < limits[ 0 ]) {
emit('update:modelValue', limits[ 0 ])
}
else if (val > limits[ 1 ]) {
emit('update:modelValue', limits[ 1 ])
}
}
watch(() => props.modelValue, v => {
normalize(v, computedLimits.value)
})
watch(() => props.limits, () => {
nextTick(() => {
normalize(props.modelValue, computedLimits.value)
})
})
return () => {
const child = [
h('div', {
ref: sideRefs.before,
class: [
'q-splitter__panel q-splitter__before' + (props.reverse === true ? ' col' : ''),
props.beforeClass
],
style: styles.value.before
}, hSlot(slots.before)),
h('div', {
class: [
'q-splitter__separator',
props.separatorClass
],
style: props.separatorStyle,
'aria-disabled': props.disable === true ? 'true' : void 0
}, [
hDir(
'div',
{ class: 'q-splitter__separator-area absolute-full' },
hSlot(slots.separator),
'sep',
props.disable !== true,
() => sepDirective.value
)
]),
h('div', {
ref: sideRefs.after,
class: [
'q-splitter__panel q-splitter__after' + (props.reverse === true ? '' : ' col'),
props.afterClass
],
style: styles.value.after
}, hSlot(slots.after))
]
return h('div', {
class: classes.value,
ref: rootRef
}, hMergeSlot(slots.default, child))
}
}
})