UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

246 lines (208 loc) 6.11 kB
import { h, ref, computed, watch, nextTick, getCurrentInstance } from 'vue' import TouchPan from '../../directives/touch-pan/TouchPan.js' import useDark, { useDarkProps } from '../../composables/private.use-dark/use-dark.js' import { createComponent } from '../../utils/private.create/create.js' import { hSlot, hMergeSlot, hDir } from '../../utils/private.render/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(() => [ [ 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) ) } } })