You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2026/09/15 07:28:47 UTC
(myfaces-tobago) branch main updated: fix(dropdown): menu size
This is an automated email from the ASF dual-hosted git repository.
henningn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/main by this push:
new 682602e755 fix(dropdown): menu size
682602e755 is described below
commit 682602e7552b0199b89b8c8e1158d59312b27752
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Mon Sep 14 12:25:33 2026 +0200
fix(dropdown): menu size
add test
Set display: inline-block; so the padding is respected. By default, the padding is part of the scroll area.
Calculate the max-height first, instead of setting it to "initial". The value "initial" means that the whole browser window is used. But if later a max-height is set, a vertical scrollbar may appear. The vertical scrollbar must have some space, so it might cause a horizontal scrollbar.
Issue: TOBAGO-2542
---
.../content/900-test/button/dropdown/Dropdown.css | 30 +++++++++++++
.../content/900-test/button/dropdown/Dropdown.js | 28 ++++++++++++
.../900-test/button/dropdown/Dropdown.xhtml | 26 +++++++++++
.../src/test/typescript/button.test.ts | 23 ++++++++++
tobago-theme/src/main/scss/_tobago.scss | 1 +
.../src/main/ts/tobago-dropdown-menu.ts | 52 ++++++++++------------
6 files changed, 132 insertions(+), 28 deletions(-)
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.css b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.css
new file mode 100644
index 0000000000..583eaad929
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.css
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.tobago2542-a-content {
+ background-color: #f2f542;
+ width: 380px;
+ height: 400px;
+}
+
+.tobago2542-b-content {
+ background-color: #f2f542;
+ width: 371px;
+ height: 700px;
+}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.js b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.js
new file mode 100644
index 0000000000..3c93f74d12
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.js
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+document.addEventListener("tobago.init", function () {
+ window.addEventListener("load", updateResolutionDisplay);
+ window.addEventListener("resize", updateResolutionDisplay);
+});
+
+function updateResolutionDisplay() {
+ const docRect = document.documentElement.getBoundingClientRect();
+ document.getElementById("resolution").textContent = docRect.width + "x" + window.innerHeight;
+}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.xhtml
index eb02e9eb8d..522dad168b 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/button/dropdown/Dropdown.xhtml
@@ -21,6 +21,10 @@
xmlns:tc="http://myfaces.apache.org/tobago/component"
xmlns:ui="jakarta.faces.facelets">
+ <tc:style file="Dropdown.css"/>
+ <tc:script file="Dropdown.js"/>
+ <div id="resolution"></div>
+
<tc:in id="beforeComp" label="Component before"/>
<tc:button id="dropdownForm" label="Form" omit="true">
@@ -171,4 +175,26 @@
<tc:link id="fixedRight0Entry" label="Link" omit="true"/>
</tc:button>
+ <p>TOBAGO-2542 dropdown content has scrollbars</p>
+ <tc:flowLayout textAlign="right">
+ <tc:button id="dropdownFormTobago2542a" label="TOBAGO-2542_a" omit="true">
+ <f:facet name="panel">
+ <tc:panel>
+ <tc:style customClass="tobago2542-a-content"/>
+ <p>Content</p>
+ </tc:panel>
+ </f:facet>
+ </tc:button>
+ </tc:flowLayout>
+ <tc:flowLayout textAlign="right">
+ <tc:button id="dropdownFormTobago2542b" label="TOBAGO-2542_b" omit="true">
+ <f:facet name="panel">
+ <tc:panel>
+ <tc:style customClass="tobago2542-b-content"/>
+ <p>Content</p>
+ </tc:panel>
+ </f:facet>
+ </tc:button>
+ </tc:flowLayout>
+
</ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/test/typescript/button.test.ts b/tobago-example/tobago-example-demo/src/test/typescript/button.test.ts
index abe215d0b3..4e6e8b900a 100644
--- a/tobago-example/tobago-example-demo/src/test/typescript/button.test.ts
+++ b/tobago-example/tobago-example-demo/src/test/typescript/button.test.ts
@@ -486,4 +486,27 @@ test.describe("900-test/button/dropdown/Dropdown.xhtml", () => {
await expect(fixedRight0Entry).not.toBeVisible();
await expect(fixedRight0ToggleButton).toBeFocused();
});
+
+ test("TOBAGO-2542_a: dropdown must open to the left", async ({page, browserName}) => {
+ const toggleButton = page.locator("[id='page:mainForm:dropdownFormTobago2542a::command']");
+ const dropdownMenu = page.locator(".tobago-dropdown-menu[data-tobago-for='page:mainForm:dropdownFormTobago2542a']");
+
+ await expect(dropdownMenu).not.toBeVisible();
+ await toggleButton.scrollIntoViewIfNeeded();
+ await toggleButton.click();
+ await expect(dropdownMenu).toBeVisible();
+ await expect(dropdownMenu).toHaveCSS("right", "236px");
+ });
+
+ test("TOBAGO-2542_b: dropdown must open to the left", async ({page, browserName}) => {
+ const toggleButton = page.locator("[id='page:mainForm:dropdownFormTobago2542b::command']");
+ const dropdownMenu = page.locator(".tobago-dropdown-menu[data-tobago-for='page:mainForm:dropdownFormTobago2542b']");
+
+ await expect(dropdownMenu).not.toBeVisible();
+ await expect(dropdownMenu).not.toBeVisible();
+ await toggleButton.scrollIntoViewIfNeeded();
+ await toggleButton.click();
+ await expect(dropdownMenu).toBeVisible();
+ await expect(dropdownMenu).toHaveCSS("right", "236px");
+ });
});
diff --git a/tobago-theme/src/main/scss/_tobago.scss b/tobago-theme/src/main/scss/_tobago.scss
index 5b9fd1a8cb..bf22da47b7 100644
--- a/tobago-theme/src/main/scss/_tobago.scss
+++ b/tobago-theme/src/main/scss/_tobago.scss
@@ -90,6 +90,7 @@ @mixin buttonDropdownMenu() {
@include tobagoDropdownMenuValues();
.tobago-panel-facet {
+ display: inline-block;
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
}
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-dropdown-menu.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-dropdown-menu.ts
index cd4f788acb..5853a04aef 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-dropdown-menu.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-dropdown-menu.ts
@@ -154,9 +154,30 @@ export class DropdownMenu {
private updatePosition(): void {
const refElementRect = this.referenceElement.getBoundingClientRect();
- /* After updating the position, max-height is set as an inline-style. Make sure no CSS class set max-height for this
- calculation. see: TOBAGO-2541 */
- this.dropdownMenuElement.style.maxHeight = "initial";
+ //calc vertical positioning and max-height
+ const upperBorder = this.stickyHeader ? this.stickyHeader.offsetHeight : 0;
+ const lowerBorder = this.fixedFooter ? this.fixedFooter.offsetTop : window.innerHeight;
+ const spaceAbove = refElementRect.top - upperBorder;
+ const spaceBelow = lowerBorder - refElementRect.bottom;
+ if (spaceBelow >= spaceAbove) {
+ this.dropdownMenuElement.style.marginTop = "0px";
+ this.dropdownMenuElement.style.top = "0px";
+ this.dropdownMenuElement.style.top = (refElementRect.bottom - this.dropdownRect.top) + "px";
+ this.dropdownMenuElement.style.bottom = null;
+ this.dropdownMenuElement.style.marginTop = "var(--tobago-dropdown-menu-component-offset)";
+ this.dropdownMenuElement.style.marginBottom = null;
+ this.dropdownMenuElement.style.maxHeight = spaceBelow
+ - parseFloat(getComputedStyle(this.dropdownMenuElement).marginBottom) + "px";
+ } else {
+ this.dropdownMenuElement.style.marginBottom = "0px";
+ this.dropdownMenuElement.style.top = null;
+ this.dropdownMenuElement.style.bottom = "0px";
+ this.dropdownMenuElement.style.bottom = (this.dropdownRect.bottom - refElementRect.top) + "px";
+ this.dropdownMenuElement.style.marginTop = null;
+ this.dropdownMenuElement.style.marginBottom = "var(--tobago-dropdown-menu-component-offset)";
+ this.dropdownMenuElement.style.maxHeight = spaceAbove
+ - parseFloat(getComputedStyle(this.dropdownMenuElement).marginTop) + "px";
+ }
//calc horizontal positioning and max-width
switch (this.alignment) {
@@ -182,31 +203,6 @@ export class DropdownMenu {
}
break;
}
-
- //calc vertical positioning and max-height
- const upperBorder = this.stickyHeader ? this.stickyHeader.offsetHeight : 0;
- const lowerBorder = this.fixedFooter ? this.fixedFooter.offsetTop : window.innerHeight;
- const spaceAbove = refElementRect.top - upperBorder;
- const spaceBelow = lowerBorder - refElementRect.bottom;
- if (spaceBelow >= spaceAbove) {
- this.dropdownMenuElement.style.marginTop = "0px";
- this.dropdownMenuElement.style.top = "0px";
- this.dropdownMenuElement.style.top = (refElementRect.bottom - this.dropdownRect.top) + "px";
- this.dropdownMenuElement.style.bottom = null;
- this.dropdownMenuElement.style.marginTop = "var(--tobago-dropdown-menu-component-offset)";
- this.dropdownMenuElement.style.marginBottom = null;
- this.dropdownMenuElement.style.maxHeight = spaceBelow
- - parseFloat(getComputedStyle(this.dropdownMenuElement).marginBottom) + "px";
- } else {
- this.dropdownMenuElement.style.marginBottom = "0px";
- this.dropdownMenuElement.style.top = null;
- this.dropdownMenuElement.style.bottom = "0px";
- this.dropdownMenuElement.style.bottom = (this.dropdownRect.bottom - refElementRect.top) + "px";
- this.dropdownMenuElement.style.marginTop = null;
- this.dropdownMenuElement.style.marginBottom = "var(--tobago-dropdown-menu-component-offset)";
- this.dropdownMenuElement.style.maxHeight = spaceAbove
- - parseFloat(getComputedStyle(this.dropdownMenuElement).marginTop) + "px";
- }
}
private calcHorizontalPositioningAndMaxWidth(alignment: DropdownMenuAlignment, extend: boolean,