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

View file

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