From 15b2f747e2db3a8bbb30a8c13506a3fac08581b0 Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Fri, 12 Jun 2026 17:00:25 +0300 Subject: [PATCH 1/6] feat(ui5-dialog): add fullscreen toggle button The dialog now supports a fullscreen toggle button in the header, controlled by the `showFullscreenButton` property. The button toggles the `stretch` property and is not available on phone devices. - Keyboard shortcut: Shift+Ctrl+F - Double-click on header toggles fullscreen - Button shows Maximize/Restore tooltip and aria-keyshortcuts - Resets drag/resize state when toggling --- packages/main/cypress/specs/Dialog.cy.tsx | 252 ++++++++++++++++++ packages/main/src/Dialog.ts | 92 ++++++- packages/main/src/DialogTemplate.tsx | 14 + .../main/src/i18n/messagebundle.properties | 6 + packages/main/src/themes/Dialog.css | 13 +- packages/main/test/pages/Dialog.html | 21 ++ .../docs/_components_pages/main/Dialog.mdx | 5 + .../main/Dialog/Fullscreen/Fullscreen.md | 5 + .../_samples/main/Dialog/Fullscreen/main.js | 21 ++ .../main/Dialog/Fullscreen/sample.html | 29 ++ .../main/Dialog/Fullscreen/sample.tsx | 50 ++++ 11 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 packages/website/docs/_samples/main/Dialog/Fullscreen/Fullscreen.md create mode 100644 packages/website/docs/_samples/main/Dialog/Fullscreen/main.js create mode 100644 packages/website/docs/_samples/main/Dialog/Fullscreen/sample.html create mode 100644 packages/website/docs/_samples/main/Dialog/Fullscreen/sample.tsx diff --git a/packages/main/cypress/specs/Dialog.cy.tsx b/packages/main/cypress/specs/Dialog.cy.tsx index a9ded9140d87..6b70d8d59fb5 100644 --- a/packages/main/cypress/specs/Dialog.cy.tsx +++ b/packages/main/cypress/specs/Dialog.cy.tsx @@ -1844,3 +1844,255 @@ describe("Native drag-and-drop in draggable dialogs", () => { }); }); }); + +describe("Fullscreen Button", () => { + it("should show fullscreen button when showFullscreenButton is set", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("exist") + .and("be.visible"); + }); + + it("should not show fullscreen button when showFullscreenButton is not set", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("not.exist"); + }); + + it("should toggle stretch property when fullscreen button is clicked", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + + cy.get("#dialog").then($dialog => { + ($dialog.get(0) as Dialog)._toggleFullscreen(); + }); + + cy.get("#dialog") + .should("have.attr", "stretch"); + + cy.get("#dialog").then($dialog => { + ($dialog.get(0) as Dialog)._toggleFullscreen(); + }); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + }); + + it("should show full-screen icon when not stretched and exit-full-screen when stretched", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("have.attr", "icon", "full-screen"); + + cy.get("#dialog").then($dialog => { + ($dialog.get(0) as Dialog)._toggleFullscreen(); + }); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("have.attr", "icon", "exit-full-screen"); + }); + + it("should have correct tooltip based on stretch state", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("have.attr", "tooltip", "Maximize"); + + cy.get("#dialog").then($dialog => { + ($dialog.get(0) as Dialog)._toggleFullscreen(); + }); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("have.attr", "tooltip", "Restore"); + }); + + it("should have aria-keyshortcuts attribute", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .shadow() + .find("button") + .should("have.attr", "aria-keyshortcuts", "Shift+Control+F"); + }); + + it("should toggle fullscreen with Shift+Ctrl+F keyboard shortcut", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + + cy.get("#input").realClick(); + cy.realPress(["Shift", "Control", "f"]); + + cy.get("#dialog") + .should("have.attr", "stretch"); + + cy.realPress(["Shift", "Control", "f"]); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + }); + + it("should toggle fullscreen on header double-click", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + + cy.get("#dialog").then($dialog => { + const dialog = $dialog.get(0) as Dialog; + const headerRoot = dialog.shadowRoot!.querySelector(".ui5-popup-header-root")!; + const event = new MouseEvent("dblclick", { bubbles: true, composed: true }); + Object.defineProperty(event, "target", { value: headerRoot }); + headerRoot.dispatchEvent(event); + }); + + cy.get("#dialog") + .should("have.attr", "stretch"); + }); + + it("should not toggle fullscreen on double-click when showFullscreenButton is false", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-popup-header-root") + .realClick({ clickCount: 2 }); + + cy.get("#dialog") + .should("not.have.attr", "stretch"); + }); + + it("should reset drag/resize state when toggling fullscreen", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog").then($dialog => { + const dialog = $dialog.get(0) as Dialog; + dialog._draggedOrResized = true; + Object.assign(dialog.style, { top: "100px", left: "100px", width: "400px", height: "300px" }); + }); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .realClick(); + + cy.get("#dialog").then($dialog => { + const dialog = $dialog.get(0) as Dialog; + expect(dialog._draggedOrResized).to.be.false; + expect(dialog.style.width).to.equal(""); + expect(dialog.style.height).to.equal(""); + }); + }); + + it("should display header when only showFullscreenButton is set", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-popup-header-root") + .should("exist"); + }); + + it("should reflect stretch state if stretch is initially true", () => { + cy.mount( + + + + ); + + cy.get("#dialog").ui5DialogOpened(); + + cy.get("#dialog") + .shadow() + .find(".ui5-dialog-fullscreen-btn") + .should("have.attr", "icon", "exit-full-screen") + .and("have.attr", "tooltip", "Restore"); + + cy.get("#dialog").invoke("prop", "open", false); + }); +}); diff --git a/packages/main/src/Dialog.ts b/packages/main/src/Dialog.ts index 9596e0562044..61b56f6f288f 100644 --- a/packages/main/src/Dialog.ts +++ b/packages/main/src/Dialog.ts @@ -10,12 +10,15 @@ import { import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import toLowercaseEnumValue from "@ui5/webcomponents-base/dist/util/toLowercaseEnumValue.js"; import Popup from "./Popup.js"; import "@ui5/webcomponents-icons/dist/error.js"; import "@ui5/webcomponents-icons/dist/alert.js"; import "@ui5/webcomponents-icons/dist/sys-enter-2.js"; import "@ui5/webcomponents-icons/dist/information.js"; +import "@ui5/webcomponents-icons/dist/full-screen.js"; +import "@ui5/webcomponents-icons/dist/exit-full-screen.js"; import { DIALOG_HEADER_ARIA_ROLE_DESCRIPTION, @@ -25,6 +28,8 @@ import { DIALOG_HEADER_ARIA_LABEL, DIALOG_CONTENT_ARIA_LABEL, DIALOG_FOOTER_ARIA_LABEL, + DIALOG_FULLSCREEN_MAXIMIZE, + DIALOG_FULLSCREEN_RESTORE, } from "./generated/i18n/i18n-defaults.js"; // Template @@ -39,6 +44,10 @@ import PopupAccessibleRole from "./types/PopupAccessibleRole.js"; */ const STEP_SIZE = 16; +const FULLSCREEN_BUTTON_ACCESSIBILITY_ATTRIBUTES = { + ariaKeyShortcuts: "Shift+Control+F", +}; + type ValueStateWithIcon = ValueState.Negative | ValueState.Critical | ValueState.Positive | ValueState.Information; /** * Defines the icons corresponding to the dialog's state. @@ -169,6 +178,18 @@ class Dialog extends Popup { @property({ type: Boolean }) resizable = false; + /** + * Defines whether a fullscreen toggle button is shown in the dialog header. + * When pressed, it toggles the `stretch` property. + * The fullscreen button is not available on phone devices. + * + * **Note:** The fullscreen toggle can also be triggered by pressing Shift+Ctrl+F or by double-clicking the dialog header. + * @default false + * @public + */ + @property({ type: Boolean }) + showFullscreenButton = false; + /** * Defines the state of the `Dialog`. * @@ -187,6 +208,7 @@ class Dialog extends Popup { _resizeMouseMoveHandler: (e: MouseEvent) => void; _resizeMouseUpHandler: (e: MouseEvent) => void; _dragStartHandler: (e: DragEvent) => void; + _fullscreenKeydownHandler: (e: KeyboardEvent) => void; _y?: number; _x?: number; _isRTL?: boolean; @@ -235,6 +257,7 @@ class Dialog extends Popup { this._resizeMouseUpHandler = this._onResizeMouseUp.bind(this); this._dragStartHandler = this._handleDragStart.bind(this); + this._fullscreenKeydownHandler = this._onFullscreenKeydown.bind(this); } static _isHeader(element: HTMLElement) { @@ -279,7 +302,7 @@ class Dialog extends Popup { * Determines if the header should be shown. */ get _displayHeader() { - return this.header.length || this.headerText || this.draggable || this.resizable; + return this.header.length || this.headerText || this.draggable || this.resizable || this.showFullscreenButton; } get _movable() { @@ -294,6 +317,24 @@ class Dialog extends Popup { return this.resizable && this.onDesktop; } + get _showFullscreenButton() { + return this.showFullscreenButton && !this.onPhone; + } + + get _fullscreenButtonIcon() { + return this.stretch ? "exit-full-screen" : "full-screen"; + } + + get _fullscreenButtonTooltip() { + return this.stretch + ? Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_RESTORE as I18nText) + : Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_MAXIMIZE as I18nText); + } + + get _fullscreenButtonAccessibilityAttributes() { + return FULLSCREEN_BUTTON_ACCESSIBILITY_ATTRIBUTES; + } + get _minHeight() { let minHeight = Number.parseInt(window.getComputedStyle(this.contentDOM).minHeight); @@ -375,11 +416,15 @@ class Dialog extends Popup { _attachBrowserEvents() { this._attachScreenResizeHandler(); this._registerDragHandler(); + if (this.showFullscreenButton) { + document.addEventListener("keydown", this._fullscreenKeydownHandler); + } } _detachBrowserEvents() { this._detachScreenResizeHandler(); this._deregisterDragHandler(); + document.removeEventListener("keydown", this._fullscreenKeydownHandler); } _attachScreenResizeHandler() { @@ -432,6 +477,51 @@ class Dialog extends Popup { /** * Event handlers */ + _toggleFullscreen() { + if (this.onPhone) { + return; + } + + const wasStretched = this.stretch; + this.stretch = !this.stretch; + + this._revertSize(); + this._draggedOrResized = false; + + if (wasStretched) { + requestAnimationFrame(() => { + if (this.open) { + this._center(); + } + }); + } + } + + _onHeaderDblClick(e: MouseEvent) { + if (!this._showFullscreenButton) { + return; + } + + const target = e.target as HTMLElement; + const headerRoot = this._root.querySelector(".ui5-popup-header-root"); + if (target !== headerRoot && !target.classList.contains("ui5-popup-header-text")) { + return; + } + + this._toggleFullscreen(); + } + + _onFullscreenKeydown(e: KeyboardEvent) { + if (this._showFullscreenButton && this._isFullscreenShortcut(e)) { + e.preventDefault(); + this._toggleFullscreen(); + } + } + + _isFullscreenShortcut(e: KeyboardEvent) { + return (e.key === "f" || e.key === "F") && e.ctrlKey && e.shiftKey && !e.altKey; + } + _onDragMouseDown(e: MouseEvent) { // allow dragging only on the header if (!this._movable || !this.draggable || !Dialog._isHeader(e.target as HTMLElement)) { diff --git a/packages/main/src/DialogTemplate.tsx b/packages/main/src/DialogTemplate.tsx index 3575a770d021..226e865ba219 100644 --- a/packages/main/src/DialogTemplate.tsx +++ b/packages/main/src/DialogTemplate.tsx @@ -3,6 +3,7 @@ import type Dialog from "./Dialog.js"; import PopupTemplate from "./PopupTemplate.js"; import Title from "./Title.js"; import Icon from "./Icon.js"; +import Button from "./Button.js"; export default function DialogTemplate(this: Dialog) { return PopupTemplate.call(this, { @@ -24,6 +25,7 @@ function beforeContent(this: Dialog) { tabIndex={this._headerTabIndex} onKeyDown={this._onDragOrResizeKeyDown} onMouseDown={this._onDragMouseDown} + onDblClick={this.showFullscreenButton ? this._onHeaderDblClick : undefined} part="header" // state={this.state} > @@ -36,6 +38,18 @@ function beforeContent(this: Dialog) { {this.headerText} } + {this._showFullscreenButton && + + } + {this.resizable ? this.draggable ? diff --git a/packages/main/src/i18n/messagebundle.properties b/packages/main/src/i18n/messagebundle.properties index a151c7fc8801..1d23eb93dea5 100644 --- a/packages/main/src/i18n/messagebundle.properties +++ b/packages/main/src/i18n/messagebundle.properties @@ -852,6 +852,12 @@ DIALOG_CONTENT_ARIA_LABEL=Content #XACT: ARIA label for the Dialog footer region DIALOG_FOOTER_ARIA_LABEL=Footer + +#XACT: Tooltip for dialog fullscreen button (maximize) +DIALOG_FULLSCREEN_MAXIMIZE=Maximize + +#XACT: Tooltip for dialog fullscreen button (restore) +DIALOG_FULLSCREEN_RESTORE=Restore #XFLD: A colon to separate the "label" from an input. In some languages there might be a different symbol used for such a colon LABEL_COLON=: diff --git a/packages/main/src/themes/Dialog.css b/packages/main/src/themes/Dialog.css index a99dfbbcb206..fc6790c8432a 100644 --- a/packages/main/src/themes/Dialog.css +++ b/packages/main/src/themes/Dialog.css @@ -29,7 +29,7 @@ cursor: move; } -:host([draggable]) .ui5-popup-header-root * { +:host([draggable]) .ui5-popup-header-root *:not(.ui5-dialog-fullscreen-btn) { cursor: auto; } @@ -139,6 +139,17 @@ color: var(--sapButton_Lite_TextColor); } +.ui5-dialog-fullscreen-btn { + position: absolute; + inset-inline-end: 0.5rem; + inset-block-start: 50%; + transform: translateY(-50%); +} + +:host([on-phone]) .ui5-dialog-fullscreen-btn { + display: none; +} + :host::backdrop { background-color: var(--_ui5_popup_block_layer_background); opacity: var(--_ui5_popup_block_layer_opacity); diff --git a/packages/main/test/pages/Dialog.html b/packages/main/test/pages/Dialog.html index 160b30e7151e..e32dee93d90d 100644 --- a/packages/main/test/pages/Dialog.html +++ b/packages/main/test/pages/Dialog.html @@ -35,6 +35,7 @@ +

Open Dialog with Input @@ -82,6 +83,9 @@ Open draggable & resizable dialog

+ Open fullscreen dialog +
+
Open RTL draggable & resizable dialog

@@ -439,6 +443,17 @@ + +

This dialog has a fullscreen toggle button in the header.

+

Press the fullscreen button or use Shift+Ctrl+F to toggle fullscreen mode.

+

You can also double-click the header to toggle.

+ + +
+ Close +
+
+

Move this dialog around the screen by dragging it by its header.

@@ -898,6 +913,10 @@ scrollHelper.style.display = cbScrollable.checked ? "block" : "none"; }); + cbRtl.addEventListener("ui5-change", function () { + document.documentElement.dir = cbRtl.checked ? "rtl" : "ltr"; + }); + let preventClosing = true; btnOpenDialog.addEventListener("click", function () { @@ -1000,6 +1019,8 @@ window["resizable-custom-header-close"].addEventListener("click", function () { window["resizable-dialog-custom-header"].open = false; }); window["draggable-and-resizable-open"].addEventListener("click", function () { window["draggable-and-resizable-dialog"].open = true; }); window["draggable-and-resizable-close"].addEventListener("click", function () { window["draggable-and-resizable-dialog"].open = false; }); + window["fullscreen-open"].addEventListener("click", function () { window["fullscreen-dialog"].open = true; }); + window["fullscreen-close"].addEventListener("click", function () { window["fullscreen-dialog"].open = false; }); window["rtl-draggable-and-resizable-open"].addEventListener("click", function () { window["rtl-draggable-and-resizable-dialog"].open = true; }); window["rtl-draggable-and-resizable-close"].addEventListener("click", function () { window["rtl-draggable-and-resizable-dialog"].open = false; }); window["rtl-maxwidth-resizable-open"].addEventListener("click", function () { window["rtl-maxwidth-resizable-dialog"].open = true; }); diff --git a/packages/website/docs/_components_pages/main/Dialog.mdx b/packages/website/docs/_components_pages/main/Dialog.mdx index 403387ab4706..539c059b0c53 100644 --- a/packages/website/docs/_components_pages/main/Dialog.mdx +++ b/packages/website/docs/_components_pages/main/Dialog.mdx @@ -4,6 +4,7 @@ slug: ../Dialog import Basic from "../../_samples/main/Dialog/Basic/Basic.md"; import DraggableAndResizable from "../../_samples/main/Dialog/DraggableAndResizable/DraggableAndResizable.md"; +import Fullscreen from "../../_samples/main/Dialog/Fullscreen/Fullscreen.md"; import BarInDialog from "../../_samples/main/Dialog/BarInDialog/BarInDialog.md"; import WithState from "../../_samples/main/Dialog/WithState/WithState.md"; @@ -19,6 +20,10 @@ import WithState from "../../_samples/main/Dialog/WithState/WithState.md"; ### Draggable and Resizable +### Fullscreen +Users can toggle between standard and full screen size. The full screen button is positioned top-right in the dialog's title bar. The fullscreen toggle can also be triggered by pressing Shift+Ctrl+F or by double-clicking the dialog header. + + ### Usage of Bar as header/footer The Bar component can be used as header and/or footer of the Dialog diff --git a/packages/website/docs/_samples/main/Dialog/Fullscreen/Fullscreen.md b/packages/website/docs/_samples/main/Dialog/Fullscreen/Fullscreen.md new file mode 100644 index 000000000000..0c062a836e84 --- /dev/null +++ b/packages/website/docs/_samples/main/Dialog/Fullscreen/Fullscreen.md @@ -0,0 +1,5 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; +import react from '!!raw-loader!./sample.tsx'; + + diff --git a/packages/website/docs/_samples/main/Dialog/Fullscreen/main.js b/packages/website/docs/_samples/main/Dialog/Fullscreen/main.js new file mode 100644 index 000000000000..380d54aca254 --- /dev/null +++ b/packages/website/docs/_samples/main/Dialog/Fullscreen/main.js @@ -0,0 +1,21 @@ +import "@ui5/webcomponents/dist/Dialog.js"; +import "@ui5/webcomponents/dist/Button.js"; +import "@ui5/webcomponents/dist/Toolbar.js"; +import "@ui5/webcomponents/dist/ToolbarButton.js"; + +var dialogOpener = document.getElementById("dialogOpener"); +var dialog = document.getElementById("dialog"); +var dialogClosers = [...dialog.querySelectorAll(".dialogCloser")]; + +dialogOpener.accessibilityAttributes = { + hasPopup: "dialog", + controls: dialog.id, +}; +dialogOpener.addEventListener("click", () => { + dialog.open = true; +}); +dialogClosers.forEach(btn => { + btn.addEventListener("click", () => { + dialog.open = false; + }); +}) diff --git a/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.html b/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.html new file mode 100644 index 000000000000..8e162573f4e6 --- /dev/null +++ b/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.html @@ -0,0 +1,29 @@ + + + + + + + + Sample + + + + + + Open Fullscreen Dialog + + +
This dialog has a fullscreen toggle button in the header.
+
Click the fullscreen button or press Shift+Ctrl+F to toggle fullscreen mode.
+
You can also double-click the header to toggle.
+ + + +
+ + + + + + diff --git a/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.tsx b/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.tsx new file mode 100644 index 000000000000..9bae0850e0f4 --- /dev/null +++ b/packages/website/docs/_samples/main/Dialog/Fullscreen/sample.tsx @@ -0,0 +1,50 @@ +import createReactComponent from "@ui5/webcomponents-base/dist/createReactComponent.js"; +import { useState } from "react"; +import ButtonClass from "@ui5/webcomponents/dist/Button.js"; +import DialogClass from "@ui5/webcomponents/dist/Dialog.js"; +import ToolbarClass from "@ui5/webcomponents/dist/Toolbar.js"; +import ToolbarButtonClass from "@ui5/webcomponents/dist/ToolbarButton.js"; + +const Button = createReactComponent(ButtonClass); +const Dialog = createReactComponent(DialogClass); +const Toolbar = createReactComponent(ToolbarClass); +const ToolbarButton = createReactComponent(ToolbarButtonClass); + +function App() { + const [dialogOpen, setDialogOpen] = useState(false); + + return ( + <> + + + setDialogOpen(false)} + > +
This dialog has a fullscreen toggle button in the header.
+
+ Click the fullscreen button or press Shift+Ctrl+F to toggle fullscreen + mode. +
+
You can also double-click the header to toggle.
+ + setDialogOpen(false)} + /> + +
+ + ); +} + +export default App; From 3aab8a06f8354480e6dbf3727d60b43052813d16 Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Fri, 12 Jun 2026 17:38:57 +0300 Subject: [PATCH 2/6] feat(ui5-dialog): add fullscreen toggle button Adds a padding-inline-end to prevents header content from overlapping with the button --- packages/main/src/themes/Dialog.css | 5 +++++ packages/main/src/themes/base/Dialog-parameters.css | 1 + 2 files changed, 6 insertions(+) diff --git a/packages/main/src/themes/Dialog.css b/packages/main/src/themes/Dialog.css index fc6790c8432a..ad94a14a1944 100644 --- a/packages/main/src/themes/Dialog.css +++ b/packages/main/src/themes/Dialog.css @@ -146,6 +146,11 @@ transform: translateY(-50%); } +/* Prevents header content from overlapping the absolutely positioned fullscreen button */ +:host([show-fullscreen-button]) .ui5-popup-header-root { + padding-inline-end: var(--_ui5_dialog_fullscreen_button_offset); +} + :host([on-phone]) .ui5-dialog-fullscreen-btn { display: none; } diff --git a/packages/main/src/themes/base/Dialog-parameters.css b/packages/main/src/themes/base/Dialog-parameters.css index c001a627e2db..b1467c34f572 100644 --- a/packages/main/src/themes/base/Dialog-parameters.css +++ b/packages/main/src/themes/base/Dialog-parameters.css @@ -5,4 +5,5 @@ --_ui5_dialog_header_focus_right_offset: 2px; --_ui5_dialog_header_border_radius: 0px; --_ui5_dialog_header_state_line_height: 0.0625rem; + --_ui5_dialog_fullscreen_button_offset: 2.5rem; } From 8a9133b2a4592fbe28611bff8d6f601bee3f1a14 Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Fri, 12 Jun 2026 18:12:23 +0300 Subject: [PATCH 3/6] feat(ui5-dialog): add fullscreen toggle button Lint errors fix --- packages/main/src/Dialog.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/main/src/Dialog.ts b/packages/main/src/Dialog.ts index 61b56f6f288f..80c7e019ebe5 100644 --- a/packages/main/src/Dialog.ts +++ b/packages/main/src/Dialog.ts @@ -10,7 +10,6 @@ import { import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; -import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import toLowercaseEnumValue from "@ui5/webcomponents-base/dist/util/toLowercaseEnumValue.js"; import Popup from "./Popup.js"; import "@ui5/webcomponents-icons/dist/error.js"; @@ -327,8 +326,8 @@ class Dialog extends Popup { get _fullscreenButtonTooltip() { return this.stretch - ? Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_RESTORE as I18nText) - : Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_MAXIMIZE as I18nText); + ? Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_RESTORE) + : Dialog.i18nBundle.getText(DIALOG_FULLSCREEN_MAXIMIZE); } get _fullscreenButtonAccessibilityAttributes() { From c7a9443c7a41c481f69d2c0d1171db5a07e7f6bc Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Mon, 15 Jun 2026 13:14:16 +0300 Subject: [PATCH 4/6] feat(ui5-dialog): add fullscreen toggle button Lint and bug fixes - Keyboard shortcut: Shift+Ctrl+F (works regardless of focus) - Double-click on header toggles fullscreen - Button shows Maximize/Restore tooltip and aria-keyshortcuts - Resets drag/resize state when toggling --- packages/main/src/Dialog.ts | 2 +- packages/main/src/i18n/messagebundle.properties | 1 + packages/main/src/themes/Dialog.css | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/main/src/Dialog.ts b/packages/main/src/Dialog.ts index 80c7e019ebe5..06c09ce71dbb 100644 --- a/packages/main/src/Dialog.ts +++ b/packages/main/src/Dialog.ts @@ -313,7 +313,7 @@ class Dialog extends Popup { } get _showResizeHandle() { - return this.resizable && this.onDesktop; + return this.resizable && this.onDesktop && !this.stretch; } get _showFullscreenButton() { diff --git a/packages/main/src/i18n/messagebundle.properties b/packages/main/src/i18n/messagebundle.properties index 1d23eb93dea5..a09c2f24e67d 100644 --- a/packages/main/src/i18n/messagebundle.properties +++ b/packages/main/src/i18n/messagebundle.properties @@ -858,6 +858,7 @@ DIALOG_FULLSCREEN_MAXIMIZE=Maximize #XACT: Tooltip for dialog fullscreen button (restore) DIALOG_FULLSCREEN_RESTORE=Restore + #XFLD: A colon to separate the "label" from an input. In some languages there might be a different symbol used for such a colon LABEL_COLON=: diff --git a/packages/main/src/themes/Dialog.css b/packages/main/src/themes/Dialog.css index ad94a14a1944..c34408c53f72 100644 --- a/packages/main/src/themes/Dialog.css +++ b/packages/main/src/themes/Dialog.css @@ -142,8 +142,8 @@ .ui5-dialog-fullscreen-btn { position: absolute; inset-inline-end: 0.5rem; - inset-block-start: 50%; - transform: translateY(-50%); + inset-block: 0; + margin-block: auto; } /* Prevents header content from overlapping the absolutely positioned fullscreen button */ From d77f4e56cc1187c84f9800d02c9e85b6d0086ee8 Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Mon, 15 Jun 2026 14:56:55 +0300 Subject: [PATCH 5/6] feat(ui5-dialog): add fullscreen toggle button Removes absolute positioning and and adds fullscreen spacing instead of offset - Keyboard shortcut: Shift+Ctrl+F (works regardless of focus) - Double-click on header toggles fullscreen - Button shows Maximize/Restore tooltip and aria-keyshortcuts - Resets drag/resize state when toggling --- packages/main/src/themes/Dialog.css | 12 +++++------- .../main/src/themes/base/Dialog-parameters.css | 2 +- packages/main/test/pages/Dialog.html | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/main/src/themes/Dialog.css b/packages/main/src/themes/Dialog.css index c34408c53f72..d0c6cc0ec163 100644 --- a/packages/main/src/themes/Dialog.css +++ b/packages/main/src/themes/Dialog.css @@ -139,16 +139,14 @@ color: var(--sapButton_Lite_TextColor); } -.ui5-dialog-fullscreen-btn { - position: absolute; - inset-inline-end: 0.5rem; - inset-block: 0; - margin-block: auto; +.ui5-popup-header-text { + flex: 1; + min-width: 0; + justify-content: flex-start; } -/* Prevents header content from overlapping the absolutely positioned fullscreen button */ :host([show-fullscreen-button]) .ui5-popup-header-root { - padding-inline-end: var(--_ui5_dialog_fullscreen_button_offset); + padding-inline-end: var(--_ui5_dialog_fullscreen_button_inline_end_spacing); } :host([on-phone]) .ui5-dialog-fullscreen-btn { diff --git a/packages/main/src/themes/base/Dialog-parameters.css b/packages/main/src/themes/base/Dialog-parameters.css index b1467c34f572..946a6c447704 100644 --- a/packages/main/src/themes/base/Dialog-parameters.css +++ b/packages/main/src/themes/base/Dialog-parameters.css @@ -5,5 +5,5 @@ --_ui5_dialog_header_focus_right_offset: 2px; --_ui5_dialog_header_border_radius: 0px; --_ui5_dialog_header_state_line_height: 0.0625rem; - --_ui5_dialog_fullscreen_button_offset: 2.5rem; + --_ui5_dialog_fullscreen_button_inline_end_spacing: 0.25rem; } diff --git a/packages/main/test/pages/Dialog.html b/packages/main/test/pages/Dialog.html index e32dee93d90d..5758fd24b02b 100644 --- a/packages/main/test/pages/Dialog.html +++ b/packages/main/test/pages/Dialog.html @@ -86,6 +86,9 @@ Open fullscreen dialog

+ Open fullscreen dialog (long title) +
+
Open RTL draggable & resizable dialog

@@ -454,6 +457,15 @@
+ +

Compare the title position with and without the fullscreen button.

+

With flex:1 approach, the title shifts toward the start instead of being visually centered in the header.

+ +
+ Close +
+
+

Move this dialog around the screen by dragging it by its header.

@@ -1021,6 +1033,8 @@ window["draggable-and-resizable-close"].addEventListener("click", function () { window["draggable-and-resizable-dialog"].open = false; }); window["fullscreen-open"].addEventListener("click", function () { window["fullscreen-dialog"].open = true; }); window["fullscreen-close"].addEventListener("click", function () { window["fullscreen-dialog"].open = false; }); + window["fullscreen-long-title-open"].addEventListener("click", function () { window["fullscreen-long-title"].open = true; }); + window["fullscreen-long-title-close"].addEventListener("click", function () { window["fullscreen-long-title"].open = false; }); window["rtl-draggable-and-resizable-open"].addEventListener("click", function () { window["rtl-draggable-and-resizable-dialog"].open = true; }); window["rtl-draggable-and-resizable-close"].addEventListener("click", function () { window["rtl-draggable-and-resizable-dialog"].open = false; }); window["rtl-maxwidth-resizable-open"].addEventListener("click", function () { window["rtl-maxwidth-resizable-dialog"].open = true; }); From 9660dff8c6d6c1ab94a1ea3a65d1746111d9e39f Mon Sep 17 00:00:00 2001 From: Konstantin Kondov Date: Mon, 15 Jun 2026 15:38:31 +0300 Subject: [PATCH 6/6] feat(ui5-dialog): add fullscreen toggle button Removed unnecessary spacing --- packages/main/src/themes/Dialog.css | 4 ---- packages/main/src/themes/base/Dialog-parameters.css | 1 - 2 files changed, 5 deletions(-) diff --git a/packages/main/src/themes/Dialog.css b/packages/main/src/themes/Dialog.css index d0c6cc0ec163..2cbd0ef5c52c 100644 --- a/packages/main/src/themes/Dialog.css +++ b/packages/main/src/themes/Dialog.css @@ -145,10 +145,6 @@ justify-content: flex-start; } -:host([show-fullscreen-button]) .ui5-popup-header-root { - padding-inline-end: var(--_ui5_dialog_fullscreen_button_inline_end_spacing); -} - :host([on-phone]) .ui5-dialog-fullscreen-btn { display: none; } diff --git a/packages/main/src/themes/base/Dialog-parameters.css b/packages/main/src/themes/base/Dialog-parameters.css index 946a6c447704..c001a627e2db 100644 --- a/packages/main/src/themes/base/Dialog-parameters.css +++ b/packages/main/src/themes/base/Dialog-parameters.css @@ -5,5 +5,4 @@ --_ui5_dialog_header_focus_right_offset: 2px; --_ui5_dialog_header_border_radius: 0px; --_ui5_dialog_header_state_line_height: 0.0625rem; - --_ui5_dialog_fullscreen_button_inline_end_spacing: 0.25rem; }