From e817174f4a900b6a3b212f1053912cce02e26d32 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Mon, 15 Jul 2024 15:15:36 +0200 Subject: [PATCH 1/2] fix(NcActions): Use full window height Calculate the space on the window based on the trigger location. Signed-off-by: Ferdinand Thiessen --- src/components/NcActions/NcActions.vue | 49 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/components/NcActions/NcActions.vue b/src/components/NcActions/NcActions.vue index 08f6f3f8c1..db4caa0fca 100644 --- a/src/components/NcActions/NcActions.vue +++ b/src/components/NcActions/NcActions.vue @@ -952,11 +952,13 @@ export default { import NcButton from '../NcButton/index.js' import NcPopover from '../NcPopover/index.js' import GenRandomId from '../../utils/GenRandomId.js' -import { getTrapStack } from '../../utils/focusTrap.js' + import { t } from '../../l10n.js' +import { getTrapStack } from '../../utils/focusTrap.js' +import { useElementBounding, useWindowSize } from '@vueuse/core' +import Vue, { ref, computed } from 'vue' -import Vue, { computed } from 'vue' -import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue' +import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue' const focusableSelector = '.focusable' @@ -973,7 +975,6 @@ export default { components: { NcButton, - DotsHorizontal, NcPopover, }, @@ -1170,9 +1171,25 @@ export default { setup() { const randomId = `menu-${GenRandomId()}` + const triggerRandomId = `trigger-${randomId}` + + const triggerButton = ref() + + const { top, bottom } = useElementBounding(triggerButton) + const { height } = useWindowSize() + const maxMenuHeight = computed(() => Math.max( + // Either expand to the top, so the max height is the top position of the trigger minus the header height minus the wedge and the padding + top.value - 84, + // or expand to the bottom, so the max height is the window height minus current position of the trigger minus the wedge and padding + height.value - bottom.value - 34, + )) + return { + triggerButton, + maxMenuHeight, + randomId, - triggerRandomId: `trigger-${randomId}`, + triggerRandomId, } }, @@ -1416,8 +1433,8 @@ export default { this.focusIndex = 0 if (returnFocus) { - // Focus back the menu button - this.$refs.menuButton?.$el.focus() + // Focus back the trigger button + this.$refs.triggerButton?.$el.focus() } }, @@ -1432,15 +1449,15 @@ export default { }, /** - * Hanle resizing the popover to make sure users can discover there is more to scroll + * Handle resizing the popover to make sure users can discover there is more to scroll */ resizePopover() { // Get the inner v-popper element that defines the popover height (from floating-vue) const inner = this.$refs.menu.closest('.v-popper__inner') - const maxHeight = Number.parseFloat(window.getComputedStyle(inner).maxHeight) const height = this.$refs.menu.clientHeight + // If the popover height is limited by the max-height (scrollbars shown) limit the height to half of the last element - if (height > maxHeight) { + if (height > this.maxMenuHeight) { // sum of action heights let currentHeight = 0 // last action height @@ -1448,7 +1465,7 @@ export default { for (const action of this.$refs.menuList.children) { // If the max height would be overflown by half of the current element, // then we limit the height to the half of the previous element - if ((currentHeight + action.clientHeight / 2) > maxHeight) { + if ((currentHeight + action.clientHeight / 2) > this.maxMenuHeight) { inner.style.height = `${currentHeight - actionHeight / 2}px` break } @@ -1836,7 +1853,7 @@ export default { const triggerIcon = this.$slots.icon?.[0] || ( this.defaultIcon ? h('span', { class: ['icon', this.defaultIcon] }) - : h('DotsHorizontal', { + : h(IconDotsHorizontal, { props: { size: 20, }, @@ -1854,7 +1871,7 @@ export default { container: this.container, popoverBaseClass: 'action-item__popper', popupRole: this.config.popupRole, - setReturnFocus: this.config.withFocusTrap ? this.$refs.menuButton?.$el : null, + setReturnFocus: this.config.withFocusTrap ? this.$refs.triggerButton?.$el : null, focusTrap: this.config.withFocusTrap, }, // For some reason the popover component @@ -1883,7 +1900,7 @@ export default { disabled: this.disabled, }, slot: 'trigger', - ref: 'menuButton', + ref: 'triggerButton', attrs: { id: this.triggerRandomId, 'aria-label': this.menuName ? null : this.ariaLabel, @@ -2059,12 +2076,12 @@ export default { // the popover__inner for actions only. .v-popper--theme-dropdown.v-popper__popper.action-item__popper .v-popper__wrapper { border-radius: var(--border-radius-large); - overflow:hidden; + overflow: hidden; .v-popper__inner { border-radius: var(--border-radius-large); padding: 4px; - max-height: calc(50vh - 16px); + max-height: calc(100vh - var(--header-height)); overflow: auto; } } From 5575680382a475277deeefd3100d21f3c13c4e5b Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Mon, 15 Jul 2024 22:30:17 +0200 Subject: [PATCH 2/2] fix(NcActions): Respect boundaries element for popover height Signed-off-by: Ferdinand Thiessen --- src/components/NcActions/NcActions.vue | 29 +++++++++++++++++++------- styleguide.config.js | 1 + styleguide/assets/styleguide.css | 13 ++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 styleguide/assets/styleguide.css diff --git a/src/components/NcActions/NcActions.vue b/src/components/NcActions/NcActions.vue index db4caa0fca..a305be50e2 100644 --- a/src/components/NcActions/NcActions.vue +++ b/src/components/NcActions/NcActions.vue @@ -956,7 +956,7 @@ import GenRandomId from '../../utils/GenRandomId.js' import { t } from '../../l10n.js' import { getTrapStack } from '../../utils/focusTrap.js' import { useElementBounding, useWindowSize } from '@vueuse/core' -import Vue, { ref, computed } from 'vue' +import Vue, { ref, computed, toRef } from 'vue' import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue' @@ -1131,7 +1131,7 @@ export default { */ boundariesElement: { type: Element, - default: () => document.querySelector('body'), + default: () => document.querySelector('#app-content-vue') ?? document.querySelector('body'), }, /** @@ -1169,19 +1169,30 @@ export default { 'click', ], - setup() { + setup(props) { const randomId = `menu-${GenRandomId()}` const triggerRandomId = `trigger-${randomId}` const triggerButton = ref() const { top, bottom } = useElementBounding(triggerButton) - const { height } = useWindowSize() + const { top: boundaryTop, bottom: boundaryBottom } = useElementBounding(toRef(props, 'boundariesElement')) + const { height: windowHeight } = useWindowSize() const maxMenuHeight = computed(() => Math.max( - // Either expand to the top, so the max height is the top position of the trigger minus the header height minus the wedge and the padding - top.value - 84, - // or expand to the bottom, so the max height is the window height minus current position of the trigger minus the wedge and padding - height.value - bottom.value - 34, + // Either expand to the top + Math.min( + // max height is the top position of the trigger minus the header height minus the wedge and the padding + top.value - 84, + // and also limited to the space in the boundary + top.value - boundaryTop.value, + ), + // or expand to the bottom + Math.min( + // the max height is the window height minus current position of the trigger minus the wedge and padding + windowHeight.value - bottom.value - 34, + // and limit to the available space in the boundary + boundaryBottom.value - bottom.value, + ), )) return { @@ -1473,6 +1484,8 @@ export default { actionHeight = action.clientHeight currentHeight += actionHeight } + } else { + inner.style.height = 'fit-content' } }, diff --git a/styleguide.config.js b/styleguide.config.js index 4afb8f0594..8113ead5cf 100644 --- a/styleguide.config.js +++ b/styleguide.config.js @@ -30,6 +30,7 @@ module.exports = async () => { path.join(__dirname, 'styleguide/global.requires.js'), path.join(__dirname, 'styleguide/assets/icons.css'), path.join(__dirname, 'styleguide/assets/additional.css'), + path.join(__dirname, 'styleguide/assets/styleguide.css'), ], pagePerSection: true, minimize: true, diff --git a/styleguide/assets/styleguide.css b/styleguide/assets/styleguide.css new file mode 100644 index 0000000000..c1d94f5c34 --- /dev/null +++ b/styleguide/assets/styleguide.css @@ -0,0 +1,13 @@ +/*! + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#rsg-root { + height: 100%; +} + +#rsg-root .rsg--root-1 { + height: 100%; + overflow: scroll; +}