positioning mention popovers works now
This commit is contained in:
parent
cebf4989e7
commit
4545f20f86
5 changed files with 34 additions and 14 deletions
|
@ -18,8 +18,8 @@ const Popover = {
|
||||||
// Takes a x/y object and tells how many pixels to offset from
|
// Takes a x/y object and tells how many pixels to offset from
|
||||||
// anchor point on either axis
|
// anchor point on either axis
|
||||||
offset: Object,
|
offset: Object,
|
||||||
// Takes an element to use for positioning over this.$el
|
// Takes a x/y/h object and tells how much to offset the anchor point
|
||||||
offsetElement: null,
|
anchorOffset: Object,
|
||||||
// Additional styles you may want for the popover container
|
// Additional styles you may want for the popover container
|
||||||
popoverClass: String,
|
popoverClass: String,
|
||||||
// Time in milliseconds until the popup appears, default is 100ms
|
// Time in milliseconds until the popup appears, default is 100ms
|
||||||
|
@ -49,11 +49,17 @@ const Popover = {
|
||||||
// Popover will be anchored around this element, trigger ref is the container, so
|
// Popover will be anchored around this element, trigger ref is the container, so
|
||||||
// its children are what are inside the slot. Expect only one slot="trigger".
|
// its children are what are inside the slot. Expect only one slot="trigger".
|
||||||
const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
|
const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
|
||||||
const positionElement = this.offsetElement ? this.offsetElement : anchorEl
|
const screenBox = anchorEl.getBoundingClientRect()
|
||||||
const screenBox = positionElement.getBoundingClientRect()
|
|
||||||
console.log(positionElement, screenBox)
|
|
||||||
// Screen position of the origin point for popover
|
// Screen position of the origin point for popover
|
||||||
const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top }
|
const anchorOffset = {
|
||||||
|
x: (this.anchorOffset && this.anchorOffset.x) || 0,
|
||||||
|
y: (this.anchorOffset && this.anchorOffset.y) || 0,
|
||||||
|
h: (this.anchorOffset && this.anchorOffset.h) || 0
|
||||||
|
}
|
||||||
|
const origin = {
|
||||||
|
x: screenBox.left + screenBox.width * 0.5 + anchorOffset.x,
|
||||||
|
y: screenBox.top + anchorOffset.y
|
||||||
|
}
|
||||||
const content = this.$refs.content
|
const content = this.$refs.content
|
||||||
// Minor optimization, don't call a slow reflow call if we don't have to
|
// Minor optimization, don't call a slow reflow call if we don't have to
|
||||||
const parentBounds = this.boundTo &&
|
const parentBounds = this.boundTo &&
|
||||||
|
@ -102,21 +108,23 @@ const Popover = {
|
||||||
if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
|
if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
|
||||||
|
|
||||||
const yOffset = (this.offset && this.offset.y) || 0
|
const yOffset = (this.offset && this.offset.y) || 0
|
||||||
|
const anchorHeight = anchorOffset.h || anchorEl.offsetHeight
|
||||||
const translateY = usingTop
|
const translateY = usingTop
|
||||||
? -positionElement.offsetHeight - yOffset - content.offsetHeight
|
? -anchorEl.offsetHeight - yOffset - content.offsetHeight + anchorOffset.y
|
||||||
: yOffset
|
: -anchorEl.offsetHeight + anchorHeight + yOffset + anchorOffset.y
|
||||||
|
|
||||||
const xOffset = (this.offset && this.offset.x) || 0
|
const xOffset = (this.offset && this.offset.x) || 0
|
||||||
const translateX = (positionElement.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset
|
const translateX = (anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset + anchorOffset.x
|
||||||
|
|
||||||
// Note, separate translateX and translateY avoids blurry text on chromium,
|
// Note, separate translateX and translateY avoids blurry text on chromium,
|
||||||
// single translate or translate3d resulted in blurry text.
|
// single translate or translate3d resulted in blurry text.
|
||||||
this.styles = {
|
this.styles = {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: `translateX(${Math.floor(translateX)}px) translateY(${Math.floor(translateY)}px)`
|
transform: `translateX(${Math.round(translateX)}px) translateY(${Math.round(translateY)}px)`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showPopover () {
|
showPopover () {
|
||||||
|
if (!this.$el) return
|
||||||
if (this.trigger === 'hover' && !this.hovered) return
|
if (this.trigger === 'hover' && !this.hovered) return
|
||||||
if (this.hidden) this.$emit('show')
|
if (this.hidden) this.$emit('show')
|
||||||
this.hidden = false
|
this.hidden = false
|
||||||
|
|
|
@ -32,7 +32,7 @@ const StatusContent = {
|
||||||
// not as computed because it sets the initial state which will be changed later
|
// not as computed because it sets the initial state which will be changed later
|
||||||
expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject,
|
expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject,
|
||||||
focusedUserId: null,
|
focusedUserId: null,
|
||||||
focusedUserElement: null
|
userPopoverOffset: { x: 0, y: 0 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -190,7 +190,12 @@ const StatusContent = {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.focusedUserId = attn.id
|
this.focusedUserId = attn.id
|
||||||
this.focusedUserElement = target
|
// Give the popover an offset to place it over the hovered element
|
||||||
|
const containerWidth = this.$refs.userPopover.$el.offsetWidth
|
||||||
|
const elementWidth = target.offsetWidth
|
||||||
|
const x = -containerWidth / 2 + target.offsetLeft + elementWidth / 2
|
||||||
|
const y = target.offsetTop
|
||||||
|
this.userPopoverOffset = { x, y, h: target.offsetHeight }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,10 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<UserPopover
|
<UserPopover
|
||||||
|
ref="userPopover"
|
||||||
|
class="status-user-popover"
|
||||||
:user-id="focusedUserId"
|
:user-id="focusedUserId"
|
||||||
|
:anchor-offset="userPopoverOffset"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:class="{'tall-status': hideTallStatus}"
|
:class="{'tall-status': hideTallStatus}"
|
||||||
|
@ -142,6 +145,10 @@ $status-margin: 0.75em;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
|
.status-user-popover {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.status-content-wrapper {
|
.status-content-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -3,7 +3,7 @@ const UserPopover = {
|
||||||
name: 'UserPopover',
|
name: 'UserPopover',
|
||||||
props: [
|
props: [
|
||||||
'userId',
|
'userId',
|
||||||
'focusedElement'
|
'anchorOffset'
|
||||||
],
|
],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
popover-class="user-popover"
|
popover-class="user-popover"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
:delay="200"
|
:delay="200"
|
||||||
:offset-element="focusedElement"
|
:anchor-offset="anchorOffset"
|
||||||
@show="enter"
|
@show="enter"
|
||||||
>
|
>
|
||||||
<template slot="trigger">
|
<template slot="trigger">
|
||||||
|
|
Loading…
Add table
Reference in a new issue