quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
247 lines (205 loc) • 5.74 kB
JavaScript
import {
h,
ref,
computed,
watch,
onBeforeUnmount,
inject,
getCurrentInstance
} from 'vue'
import { isRuntimeSsrPreHydration } from '../../plugins/platform/Platform.js'
import QResizeObserver from '../resize-observer/QResizeObserver.js'
import { createComponent } from '../../utils/private.create/create.js'
import { hMergeSlot } from '../../utils/private.render/render.js'
import {
layoutKey,
emptyRenderFn
} from '../../utils/private.symbols/symbols.js'
export default createComponent({
name: 'QFooter',
props: {
modelValue: {
type: Boolean,
default: true
},
reveal: Boolean,
bordered: Boolean,
elevated: Boolean,
heightHint: {
type: [String, Number],
default: 50
}
},
emits: ['reveal', 'focusin'],
setup(props, { slots, emit }) {
const {
proxy: { $q }
} = getCurrentInstance()
const $layout = inject(layoutKey, emptyRenderFn)
if ($layout === emptyRenderFn) {
console.error('QFooter needs to be child of QLayout')
return emptyRenderFn
}
const size = ref(parseInt(props.heightHint, 10))
const revealed = ref(true)
const windowHeight = ref(
isRuntimeSsrPreHydration.value === true ||
$layout.isContainer.value === true
? 0
: window.innerHeight
)
const fixed = computed(
() =>
props.reveal === true ||
$layout.view.value.indexOf('F') !== -1 ||
($q.platform.is.ios && $layout.isContainer.value === true)
)
const containerHeight = computed(() =>
$layout.isContainer.value === true
? $layout.containerHeight.value
: windowHeight.value
)
const offset = computed(() => {
if (props.modelValue !== true) {
return 0
}
if (fixed.value === true) {
return revealed.value === true ? size.value : 0
}
const localOffset =
$layout.scroll.value.position +
containerHeight.value +
size.value -
$layout.height.value
return localOffset > 0 ? localOffset : 0
})
const hidden = computed(
() =>
props.modelValue !== true ||
(fixed.value === true && revealed.value !== true)
)
const revealOnFocus = computed(
() =>
props.modelValue === true &&
hidden.value === true &&
props.reveal === true
)
const classes = computed(
() =>
'q-footer q-layout__section--marginal ' +
(fixed.value === true ? 'fixed' : 'absolute') +
'-bottom' +
(props.bordered === true ? ' q-footer--bordered' : '') +
(hidden.value === true ? ' q-footer--hidden' : '') +
(props.modelValue !== true
? ' q-layout--prevent-focus' + (fixed.value !== true ? ' hidden' : '')
: '')
)
const style = computed(() => {
const view = $layout.rows.value.bottom,
css = {}
if (view[0] === 'l' && $layout.left.space === true) {
css[$q.lang.rtl === true ? 'right' : 'left'] = `${$layout.left.size}px`
}
if (view[2] === 'r' && $layout.right.space === true) {
css[$q.lang.rtl === true ? 'left' : 'right'] = `${$layout.right.size}px`
}
return css
})
function updateLayout(prop, val) {
$layout.update('footer', prop, val)
}
function updateLocal(prop, val) {
if (prop.value !== val) {
prop.value = val
}
}
function onResize({ height }) {
updateLocal(size, height)
updateLayout('size', height)
}
function updateRevealed() {
if (props.reveal !== true) return
const { direction, position, inflectionPoint } = $layout.scroll.value
updateLocal(
revealed,
direction === 'up' ||
position - inflectionPoint < 100 ||
$layout.height.value - containerHeight.value - position - size.value <
300
)
}
function onFocusin(evt) {
if (revealOnFocus.value === true) {
updateLocal(revealed, true)
}
emit('focusin', evt)
}
watch(
() => props.modelValue,
val => {
updateLayout('space', val)
updateLocal(revealed, true)
$layout.animate()
}
)
watch(offset, val => {
updateLayout('offset', val)
})
watch(
() => props.reveal,
val => {
if (val === false) updateLocal(revealed, props.modelValue)
}
)
watch(revealed, val => {
$layout.animate()
emit('reveal', val)
})
watch([size, $layout.scroll, $layout.height], updateRevealed)
watch(
() => $q.screen.height,
val => {
if ($layout.isContainer.value !== true) updateLocal(windowHeight, val)
}
)
const instance = {}
$layout.instances.footer = instance
if (props.modelValue === true) updateLayout('size', size.value)
updateLayout('space', props.modelValue)
updateLayout('offset', offset.value)
onBeforeUnmount(() => {
if ($layout.instances.footer === instance) {
$layout.instances.footer = void 0
updateLayout('size', 0)
updateLayout('offset', 0)
updateLayout('space', false)
}
})
return () => {
const child = hMergeSlot(slots.default, [
h(QResizeObserver, {
debounce: 0,
onResize
})
])
if (props.elevated === true) {
child.push(
h('div', {
class:
'q-layout__shadow absolute-full overflow-hidden no-pointer-events'
})
)
}
return h(
'footer',
{
class: classes.value,
style: style.value,
onFocusin
},
child
)
}
}
})