[UI] Improvements to the Dropdown element.

- Added `style` property to pass static style rules to the dropdown
  body.

- Better positioning of the dropdown when the resulting body is too long
  and may overflow the top of the screen - in that case, the dropdown
  position needs to be maximized at zero.
This commit is contained in:
Fabio Manganiello 2024-08-25 00:13:25 +02:00
parent 8f2e68f0db
commit db34a607e4
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 47 additions and 27 deletions

View file

@ -6,7 +6,11 @@
</button>
<div class="body-container hidden" ref="dropdownContainer">
<DropdownBody :id="id" :keepOpenOnItemClick="keepOpenOnItemClick" ref="dropdown" @click="onClick">
<DropdownBody :id="id"
:keepOpenOnItemClick="keepOpenOnItemClick"
:style="style"
ref="dropdown"
@click="onClick">
<slot />
</DropdownBody>
</div>
@ -41,6 +45,11 @@ export default {
type: Boolean,
default: false,
},
style: {
type: Object,
default: () => ({}),
},
},
data() {
@ -127,36 +136,42 @@ export default {
this.visible = true
this.$refs.dropdownContainer.classList.remove('hidden')
this.$nextTick(() => {
const buttonRect = this.$refs.button.getBoundingClientRect()
const buttonPos = {
left: buttonRect.left + window.scrollX,
top: buttonRect.top + window.scrollY,
}
this.$nextTick(this.adjustDropdownPos)
},
const pos = {
left: buttonPos.left,
top: buttonPos.top + this.buttonHeight,
}
adjustDropdownPos() {
const buttonRect = this.$refs.button.getBoundingClientRect()
const buttonPos = {
left: buttonRect.left + window.scrollX,
top: buttonRect.top + window.scrollY,
}
const dropdownWidth = this.getDropdownWidth()
const dropdownHeight = this.getDropdownHeight()
const pos = {
left: buttonPos.left,
top: buttonPos.top + this.buttonHeight,
}
if ((pos.left + dropdownWidth) > (window.innerWidth + window.scrollX) / 2) {
pos.left -= (dropdownWidth - this.buttonWidth)
}
const dropdownWidth = this.getDropdownWidth()
const dropdownHeight = this.getDropdownHeight()
if ((pos.top + dropdownHeight) > (window.innerHeight + window.scrollY) / 2) {
pos.top -= (dropdownHeight + this.buttonHeight - 10)
}
if ((pos.left + dropdownWidth) > (window.innerWidth + window.scrollX) / 2) {
pos.left -= (dropdownWidth - this.buttonWidth)
}
const element = this.$refs.dropdown.$el
element.classList.add('fade-in')
element.style.top = `${pos.top}px`
element.style.left = `${pos.left}px`
bus.emit('dropdown-open', this.$refs.dropdown)
this.$refs.dropdownContainer.classList.add('hidden')
})
if ((pos.top + dropdownHeight) > (window.innerHeight + window.scrollY) / 2) {
let newPosTop = pos.top - (dropdownHeight + this.buttonHeight - 10)
if (newPosTop < 0)
newPosTop = 0
pos.top = newPosTop
}
const element = this.$refs.dropdown.$el
element.classList.add('fade-in')
element.style.top = `${pos.top}px`
element.style.left = `${pos.left}px`
bus.emit('dropdown-open', this.$refs.dropdown)
this.$refs.dropdownContainer.classList.add('hidden')
},
toggle(event) {

View file

@ -1,5 +1,5 @@
<template>
<div class="dropdown" :id="id" @click="$emit('click', $event)">
<div class="dropdown" :id="id" :style="style" @click="$emit('click', $event)">
<slot />
</div>
</template>
@ -16,6 +16,11 @@ export default {
type: Boolean,
default: false,
},
style: {
type: Object,
default: () => ({}),
},
},
}
</script>