1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-28 22:42:26 +00:00
bramw_baserow/web-frontend/modules/core/components/Highlight.vue
2025-04-01 20:52:11 +00:00

127 lines
3.1 KiB
Vue

<template>
<div
v-if="selector !== null"
class="highlight"
:style="{
left: `${position.left || '0px'}`,
top: `${position.top || '0px'}`,
width: `${position.width || '0px'}`,
height: `${position.height || '0px'}`,
}"
>
<slot></slot>
</div>
</template>
<script>
import {
findScrollableParent,
getCombinedBoundingClientRect,
} from '@baserow/modules/core/utils/dom'
export default {
name: 'Highlight',
props: {
getParent: {
type: Function,
required: false,
default: null,
},
},
data() {
return {
scrollableParents: new Set(),
selector: null,
position: {
top: 0,
right: 0,
width: 0,
height: 0,
},
}
},
mounted() {
const parent = this._getParent()
this.resizeObserver = new ResizeObserver(() => {
this.update()
})
this.resizeObserver.observe(parent)
this.update()
},
beforeDestroy() {
const parent = this._getParent()
this.resizeObserver.unobserve(parent)
this.clearScrollEvents()
},
methods: {
_getParent() {
return this.getParent !== null ? this.getParent() : this.$el.parentElement
},
clearScrollEvents() {
this.scrollableParents.forEach((element) => {
element.removeEventListener('scroll', this.update)
})
this.scrollableParents = new Set()
},
getElements(selector) {
const parent = this._getParent()
const selectors = Array.isArray(selector)
? this.selector
: [this.selector]
const elements = selectors
.map((selector) => parent.querySelector(selector))
.filter((element) => !!element)
return elements
},
show(selector) {
this.selector = selector
this.update()
this.clearScrollEvents()
this.getElements(selector).forEach((element) => {
const scrollableParent = findScrollableParent(element)
if (scrollableParent) {
this.scrollableParents.add(scrollableParent)
scrollableParent.addEventListener('scroll', this.update)
}
element.scrollIntoView({
behavior: 'smooth',
inline: 'center',
block: 'center',
})
})
},
update() {
const position = {
left: '0px',
top: '0px',
width: '0px',
height: '0px',
}
if (this.selector === null) {
return
}
if (this.selector.length > 0) {
const elements = this.getElements(this.selector)
const parentRect = this._getParent().getBoundingClientRect()
const elementRect = getCombinedBoundingClientRect(elements)
const padding = 2
position.top = elementRect.top - parentRect.top - padding + 'px'
position.left = elementRect.left - parentRect.left - padding + 'px'
position.width = elementRect.width + padding * 2 + 'px'
position.height = elementRect.height + padding * 2 + 'px'
} else {
position.top = '50%'
position.left = '50%'
}
this.position = position
},
hide() {
this.selector = null
this.clearScrollEvents()
},
},
}
</script>