diff --git a/packages/fiori/src/ShellBar.ts b/packages/fiori/src/ShellBar.ts index a4c5e624029c..0107f9dc97e7 100644 --- a/packages/fiori/src/ShellBar.ts +++ b/packages/fiori/src/ShellBar.ts @@ -41,7 +41,6 @@ import type { UI5CustomEvent, } from "@ui5/webcomponents-base"; import type ListItemBase from "@ui5/webcomponents/dist/ListItemBase.js"; -import type PopoverHorizontalAlign from "@ui5/webcomponents/dist/types/PopoverHorizontalAlign.js"; import throttle from "@ui5/webcomponents-base/dist/util/throttle.js"; import { getScopedVarName } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; import getActiveElement from "@ui5/webcomponents-base/dist/util/getActiveElement.js"; @@ -1524,10 +1523,6 @@ class ShellBar extends UI5Element { return this.primaryTitle || this.showLogoInMenuButton; } - get popoverHorizontalAlign(): `${PopoverHorizontalAlign}` { - return this.effectiveDir === "rtl" ? "Start" : "End"; - } - get hasAssistant() { return !!this.assistant.length; } diff --git a/packages/fiori/src/ShellBarPopoverTemplate.tsx b/packages/fiori/src/ShellBarPopoverTemplate.tsx index b32f7491d225..f523ef439460 100644 --- a/packages/fiori/src/ShellBarPopoverTemplate.tsx +++ b/packages/fiori/src/ShellBarPopoverTemplate.tsx @@ -1,5 +1,6 @@ import Popover from "@ui5/webcomponents/dist/Popover.js"; import List from "@ui5/webcomponents/dist/List.js"; +import PopoverHorizontalAlign from "@ui5/webcomponents/dist/types/PopoverHorizontalAlign.js"; import ListItemStandard from "@ui5/webcomponents/dist/ListItemStandard.js"; import type ShellBar from "./ShellBar.js"; @@ -21,7 +22,7 @@ export default function PopoversTemplate(this: ShellBar) { {
); - + cy.get("[ui5-popover]").invoke("removeAttr", "accessible-name"); - + cy.get("[ui5-popover]") .shadow() .find(".ui5-popup-root") .should("have.attr", "aria-labelledby"); - + cy.get("[ui5-popover]") .shadow() .find(".ui5-popup-root") .should("not.have.attr", "aria-label"); }); - + it("should use aria-label when accessible-name attribute is set dynamically", () => { cy.mount(
); - + cy.get("[ui5-popover]").invoke("attr", "accessible-name", "text"); - + cy.get("[ui5-popover]") .shadow() .find(".ui5-popup-root") .should("not.have.attr", "aria-labelledby"); - + cy.get("[ui5-popover]") .shadow() .find(".ui5-popup-root") .should("have.attr", "aria-label"); }); - + it("tests accessible-name-ref", () => { cy.mount( @@ -652,25 +652,25 @@ describe("Popover opener", () => { ); - + cy.get("#first-focusable").should("be.focused"); - + cy.realPress("Tab"); cy.wait(500); cy.get("#li1").should("be.focused"); cy.get("#first-focusable").should("not.be.focused"); - + cy.realPress("Tab"); - + cy.get("#first-focusable").should("be.focused"); - + cy.realPress("Tab"); cy.realPress("Tab"); - + cy.get("#first-focusable").should("be.focused"); - + cy.realPress("Escape"); - + cy.get("[ui5-popover]").should("not.be.visible"); }); @@ -967,7 +967,7 @@ describe("Popover opener", () => { pop.addEventListener("ui5-before-open", async () => { const applyFocusResult = pop.applyFocus(); - pop.remove(); + pop.remove(); try { await applyFocusResult; @@ -1020,31 +1020,31 @@ describe("Popover opener", () => { const container = document.createElement("div"); container.id = "container"; root[0].appendChild(container); - + const shadowRoot = container.attachShadow({ mode: "open" }); - + const opener = document.createElement("ui5-button"); opener.setAttribute("id", "lnk"); opener.textContent = "Open Popover"; shadowRoot.appendChild(opener); - + const popover = document.createElement("ui5-popover"); popover.setAttribute("id", "pop"); popover.setAttribute("header-text", "Popover in Shadow Root"); popover.setAttribute("opener", "lnk"); - + const content = document.createElement("div"); content.textContent = "Popover content"; popover.appendChild(content); - + shadowRoot.appendChild(popover); }); - + cy.get("#container") .shadow() .find("#lnk") .realClick(); - + cy.get("#container") .shadow() .find("#pop") @@ -1053,7 +1053,7 @@ describe("Popover opener", () => { cy.get("#container").then(container => { container.remove(); }); - }); + }); it("tests opener set as ID in window.document, while popover is in a shadow root", () => { cy.mount( @@ -1421,6 +1421,82 @@ describe("Placement", () => { expect(top).to.be.lt(100) }); }); + + it("placement=Start in RTL", () => { + cy.mount( +
+ + +
+ Popover with Start placement in RTL mode +
+
+
+ ); + + cy.get("[ui5-popover]").invoke("prop", "open", true); + + cy.get("[ui5-popover]").should("be.visible"); + + // wait for the popover to be positioned + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(200); + + let popover; + cy.get('[ui5-popover]') + .then($popover => { + popover = $popover; + }); + + cy.get('#btnStart').should($opener => { + const popoverRect = popover[0].getBoundingClientRect(); + const openerRect = $opener[0].getBoundingClientRect(); + + // In RTL mode, Start placement should position popover to the right of the opener + expect(popoverRect.left).to.be.greaterThan(openerRect.right - 5); + }); + }); + + it("placement=End in RTL", () => { + cy.mount( +
+ + +
+ Popover with End placement in RTL mode +
+
+
+ ); + + cy.get("[ui5-popover]").invoke("prop", "open", true); + + cy.get("[ui5-popover]").should("be.visible"); + + // wait for the popover to be positioned + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(200); + + let popover; + cy.get('[ui5-popover]') + .then($popover => { + popover = $popover; + }); + + cy.get('#btnEnd').should($opener => { + const popoverRect = popover[0].getBoundingClientRect(); + const openerRect = $opener[0].getBoundingClientRect(); + + // In RTL mode, End placement should position popover to the left of the opener + expect(popoverRect.right).to.be.lessThan(openerRect.left + 5); + }); + }); }); describe("Alignment", () => { diff --git a/packages/main/src/ComboBox.ts b/packages/main/src/ComboBox.ts index 418692326425..22fb72924d70 100644 --- a/packages/main/src/ComboBox.ts +++ b/packages/main/src/ComboBox.ts @@ -87,7 +87,6 @@ import "./ComboBoxItemGroup.js"; // eslint-disable-next-line import { isInstanceOfComboBoxItemGroup } from "./ComboBoxItemGroup.js"; import type ComboBoxFilter from "./types/ComboBoxFilter.js"; -import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import type Input from "./Input.js"; import type { InputEventDetail } from "./Input.js"; import type InputComposition from "./features/InputComposition.js"; @@ -1479,10 +1478,6 @@ class ComboBox extends UI5Element implements IFormInputElement { return !this.valueStateMessage.length && this.hasValueStateText; } - get _valueStatePopoverHorizontalAlign(): `${PopoverHorizontalAlign}` { - return this.effectiveDir !== "rtl" ? PopoverHorizontalAlign.Start : PopoverHorizontalAlign.End; - } - /** * This method is relevant for sap_horizon theme only */ diff --git a/packages/main/src/ComboBoxPopoverTemplate.tsx b/packages/main/src/ComboBoxPopoverTemplate.tsx index 30ed7bbdc4ac..77a483304361 100644 --- a/packages/main/src/ComboBoxPopoverTemplate.tsx +++ b/packages/main/src/ComboBoxPopoverTemplate.tsx @@ -2,6 +2,7 @@ import Icon from "./Icon.js"; import Button from "./Button.js"; import List from "./List.js"; import Input from "./Input.js"; +import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import Popover from "./Popover.js"; import ResponsivePopover from "./ResponsivePopover.js"; import BusyIndicator from "./BusyIndicator.js"; @@ -116,7 +117,7 @@ export default function ComboBoxPopoverTemplate(this: ComboBox) { hideArrow={true} tabindex={-1} class="ui5-valuestatemessage-popover" - horizontalAlign={this._valueStatePopoverHorizontalAlign} + horizontalAlign={PopoverHorizontalAlign.Start} placement="Bottom" opener={this} open={this.valueStateOpen} diff --git a/packages/main/src/Input.ts b/packages/main/src/Input.ts index 08da1a4eaa1b..0b45e9194712 100644 --- a/packages/main/src/Input.ts +++ b/packages/main/src/Input.ts @@ -62,7 +62,7 @@ import InputType from "./types/InputType.js"; import type Popover from "./Popover.js"; import type Icon from "./Icon.js"; import type { IIcon } from "./Icon.js"; -import type PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; + // Templates import InputTemplate from "./InputTemplate.js"; import { StartsWith } from "./Filters.js"; @@ -1969,10 +1969,6 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement return ""; } - get _valueStatePopoverHorizontalAlign(): `${PopoverHorizontalAlign}` { - return this.effectiveDir !== "rtl" ? "Start" : "End"; - } - /** * This method is relevant for sap_horizon theme only */ diff --git a/packages/main/src/InputPopoverTemplate.tsx b/packages/main/src/InputPopoverTemplate.tsx index a1f23e7fab64..1b0fc9534dda 100644 --- a/packages/main/src/InputPopoverTemplate.tsx +++ b/packages/main/src/InputPopoverTemplate.tsx @@ -6,6 +6,7 @@ import alert from "@ui5/webcomponents-icons/dist/alert.js"; import sysEnter2 from "@ui5/webcomponents-icons/dist/sys-enter-2.js"; import information from "@ui5/webcomponents-icons/dist/information.js"; +import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import Popover from "./Popover.js"; import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; @@ -24,7 +25,7 @@ export default function InputPopoverTemplate(this: Input, hooks?: { suggestionsL class="ui5-valuestatemessage-popover" placement="Bottom" tabindex={-1} - horizontalAlign={this._valueStatePopoverHorizontalAlign} + horizontalAlign={PopoverHorizontalAlign.Start} opener={this} open={this.valueStateOpen} onClose={this._handleValueStatePopoverAfterClose} diff --git a/packages/main/src/MenuItem.ts b/packages/main/src/MenuItem.ts index 14937aa7de71..a73787cfb80c 100644 --- a/packages/main/src/MenuItem.ts +++ b/packages/main/src/MenuItem.ts @@ -30,7 +30,6 @@ import type { ListItemAccessibilityAttributes } from "./ListItem.js"; import type List from "./List.js"; import ListItem from "./ListItem.js"; import type ResponsivePopover from "./ResponsivePopover.js"; -import type PopoverPlacement from "./types/PopoverPlacement.js"; import { isInstanceOfMenuSeparator } from "./MenuSeparator.js"; import { isInstanceOfMenuItemGroup } from "./MenuItemGroup.js"; import MenuItemTemplate from "./MenuItemTemplate.js"; @@ -357,10 +356,6 @@ class MenuItem extends ListItem implements IMenuItem { } } - get placement(): `${PopoverPlacement}` { - return this.isRtl ? "Start" : "End"; - } - get isRtl() { return this.effectiveDir === "rtl"; } diff --git a/packages/main/src/MenuItemTemplate.tsx b/packages/main/src/MenuItemTemplate.tsx index 47046eacdd0f..1d5cd262d070 100644 --- a/packages/main/src/MenuItemTemplate.tsx +++ b/packages/main/src/MenuItemTemplate.tsx @@ -1,4 +1,5 @@ import type MenuItem from "./MenuItem.js"; +import PopoverPlacement from "./types/PopoverPlacement.js"; import ResponsivePopover from "./ResponsivePopover.js"; import Button from "./Button.js"; import List from "./List.js"; @@ -91,7 +92,7 @@ function listItemPostContent(this: MenuItem) { preventFocusRestore={true} hideArrow={true} allowTargetOverlap={true} - placement={this.placement} + placement={PopoverPlacement.End} verticalAlign="Top" accessibleName={this.accessibleNameText} onBeforeOpen={this._beforePopoverOpen} diff --git a/packages/main/src/MultiComboBox.ts b/packages/main/src/MultiComboBox.ts index 15fb35bf27a7..c941d6eaf633 100644 --- a/packages/main/src/MultiComboBox.ts +++ b/packages/main/src/MultiComboBox.ts @@ -112,7 +112,6 @@ import type ComboBoxFilter from "./types/ComboBoxFilter.js"; import CheckBox from "./CheckBox.js"; import Input from "./Input.js"; import type { InputEventDetail } from "./Input.js"; -import type PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import SuggestionItem from "./SuggestionItem.js"; import type InputComposition from "./features/InputComposition.js"; @@ -2199,10 +2198,6 @@ class MultiComboBox extends UI5Element implements IFormInputElement { return shouldBeExpanded; } - get _valueStatePopoverHorizontalAlign(): `${PopoverHorizontalAlign}` { - return this.effectiveDir !== "rtl" ? "Start" : "End"; - } - get iconsCount() { const slottedIconsCount = this.icon?.length || 0; const clearIconCount = Number(this._effectiveShowClearIcon) ?? 0; diff --git a/packages/main/src/MultiComboBoxPopoverTemplate.tsx b/packages/main/src/MultiComboBoxPopoverTemplate.tsx index 3c0811ddc28f..52d4353fd133 100644 --- a/packages/main/src/MultiComboBoxPopoverTemplate.tsx +++ b/packages/main/src/MultiComboBoxPopoverTemplate.tsx @@ -7,6 +7,7 @@ import ToggleButton from "./ToggleButton.js"; import SuggestionItem from "./SuggestionItem.js"; import Icon from "./Icon.js"; import List from "./List.js"; +import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import Popover from "./Popover.js"; import CheckBox from "./CheckBox.js"; @@ -114,7 +115,7 @@ export default function MultiComboBoxPopoverTemplate(this: MultiComboBox) { hideArrow={true} class="ui5-valuestatemessage-popover" placement="Bottom" - horizontalAlign={this._valueStatePopoverHorizontalAlign} + horizontalAlign={PopoverHorizontalAlign.Start} tabIndex={-1} open={this.valueStateOpen} opener={this} diff --git a/packages/main/src/Popover.ts b/packages/main/src/Popover.ts index 3f10d1ea4b72..51751a3e44cb 100644 --- a/packages/main/src/Popover.ts +++ b/packages/main/src/Popover.ts @@ -32,11 +32,25 @@ type ArrowPosition = { y: number; } +enum PopoverActualHorizontalAlign { + Center = "Center", + Left = "Left", + Right = "Right", + Stretch = "Stretch", +} + +enum PopoverActualPlacement { + Left = "Left", + Right = "Right", + Top = "Top", + Bottom = "Bottom", +} + type CalculatedPlacement = { arrow: ArrowPosition, top: number, left: number, - placement: `${PopoverPlacement}`, + actualPlacement: `${PopoverActualPlacement}`, } /** @@ -166,7 +180,7 @@ class Popover extends Popup { * @private */ @property() - actualPlacement: `${PopoverPlacement}` = "End"; + actualPlacement: `${PopoverActualPlacement}` = "Right"; @property({ type: Number, noAttribute: true }) _maxHeight?: number; @@ -316,11 +330,11 @@ class Popover extends Popup { return openerHTMLElement; } - shouldCloseDueToOverflow(placement: `${PopoverPlacement}`, openerRect: DOMRect): boolean { + shouldCloseDueToOverflow(placement: `${PopoverActualPlacement}`, openerRect: DOMRect): boolean { const threshold = 32; const limits = { - "Start": openerRect.right, - "End": openerRect.left, + "Left": openerRect.right, + "Right": openerRect.left, "Top": openerRect.top, "Bottom": openerRect.bottom, }; @@ -416,7 +430,7 @@ class Popover extends Popup { } this._oldPlacement = placement; - this.actualPlacement = placement.placement; + this.actualPlacement = placement.actualPlacement; let left = clamp( this._left!, @@ -424,7 +438,7 @@ class Popover extends Popup { document.documentElement.clientWidth - popoverSize.width - Popover.VIEWPORT_MARGIN, ); - if (this.actualPlacement === PopoverPlacement.End) { + if (this.actualPlacement === PopoverActualPlacement.Right) { left = Math.max(left, this._left!); } @@ -434,7 +448,7 @@ class Popover extends Popup { document.documentElement.clientHeight - popoverSize.height - Popover.VIEWPORT_MARGIN, ); - if (this.actualPlacement === PopoverPlacement.Bottom) { + if (this.actualPlacement === PopoverActualPlacement.Bottom) { top = Math.max(top, this._top!); } @@ -532,12 +546,12 @@ class Popover extends Popup { let maxHeight = clientHeight; let maxWidth = clientWidth; - const placement = this.getActualPlacement(targetRect); + const actualPlacement = this.getActualPlacement(targetRect); - this._preventRepositionAndClose = this.shouldCloseDueToNoOpener(targetRect) || this.shouldCloseDueToOverflow(placement, targetRect); + this._preventRepositionAndClose = this.shouldCloseDueToNoOpener(targetRect) || this.shouldCloseDueToOverflow(actualPlacement, targetRect); - const isVertical = placement === PopoverPlacement.Top - || placement === PopoverPlacement.Bottom; + const isVertical = actualPlacement === PopoverActualPlacement.Top + || actualPlacement === PopoverActualPlacement.Bottom; if (this.horizontalAlign === PopoverHorizontalAlign.Stretch && isVertical) { popoverSize.width = targetRect.width; @@ -550,8 +564,8 @@ class Popover extends Popup { const arrowOffset = this.hideArrow ? 0 : ARROW_SIZE; // calc popover positions - switch (placement) { - case PopoverPlacement.Top: + switch (actualPlacement) { + case PopoverActualPlacement.Top: left = this.getVerticalLeft(targetRect, popoverSize); top = Math.max(targetRect.top - popoverSize.height - arrowOffset, 0); @@ -559,7 +573,7 @@ class Popover extends Popup { maxHeight = targetRect.top - arrowOffset; } break; - case PopoverPlacement.Bottom: + case PopoverActualPlacement.Bottom: left = this.getVerticalLeft(targetRect, popoverSize); top = targetRect.bottom + arrowOffset; @@ -569,7 +583,7 @@ class Popover extends Popup { maxHeight = clientHeight - targetRect.bottom - arrowOffset; } break; - case PopoverPlacement.Start: + case PopoverActualPlacement.Left: left = Math.max(targetRect.left - popoverSize.width - arrowOffset, 0); top = this.getHorizontalTop(targetRect, popoverSize); @@ -577,7 +591,7 @@ class Popover extends Popup { maxWidth = targetRect.left - arrowOffset; } break; - case PopoverPlacement.End: + case PopoverActualPlacement.Right: left = targetRect.left + targetRect.width + arrowOffset; top = this.getHorizontalTop(targetRect, popoverSize); @@ -624,7 +638,7 @@ class Popover extends Popup { arrow: arrowPos, top: this._top, left: this._left, - placement, + actualPlacement, }; } @@ -644,14 +658,14 @@ class Popover extends Popup { * @returns Arrow's coordinates */ getArrowPosition(targetRect: DOMRect, popoverSize: PopoverSize, left: number, top: number, isVertical: boolean, borderRadius: number): ArrowPosition { - const horizontalAlign = this._actualHorizontalAlign; - let arrowXCentered = horizontalAlign === PopoverHorizontalAlign.Center || horizontalAlign === PopoverHorizontalAlign.Stretch; + const actualHorizontalAlign = this._actualHorizontalAlign; + let arrowXCentered = actualHorizontalAlign === PopoverActualHorizontalAlign.Center || actualHorizontalAlign === PopoverActualHorizontalAlign.Stretch; - if (horizontalAlign === PopoverHorizontalAlign.End && left <= targetRect.left) { + if (actualHorizontalAlign === PopoverActualHorizontalAlign.Right && left <= targetRect.left) { arrowXCentered = true; } - if (horizontalAlign === PopoverHorizontalAlign.Start && left + popoverSize.width >= targetRect.left + targetRect.width) { + if (actualHorizontalAlign === PopoverActualHorizontalAlign.Left && left + popoverSize.width >= targetRect.left + targetRect.width) { arrowXCentered = true; } @@ -691,31 +705,46 @@ class Popover extends Popup { * Fallbacks to new placement, prioritizing `Left` and `Right` placements. * @private */ - fallbackPlacement(clientWidth: number, clientHeight: number, targetRect: DOMRect, popoverSize: PopoverSize): PopoverPlacement | undefined { + fallbackPlacement(clientWidth: number, clientHeight: number, targetRect: DOMRect, popoverSize: PopoverSize): PopoverActualPlacement | undefined { if (targetRect.left > popoverSize.width) { - return PopoverPlacement.Start; + return PopoverActualPlacement.Left; } if (clientWidth - targetRect.right > targetRect.left) { - return PopoverPlacement.End; + return PopoverActualPlacement.Right; } if (clientHeight - targetRect.bottom > popoverSize.height) { - return PopoverPlacement.Bottom; + return PopoverActualPlacement.Bottom; } if (clientHeight - targetRect.bottom < targetRect.top) { - return PopoverPlacement.Top; + return PopoverActualPlacement.Top; } } - getActualPlacement(targetRect: DOMRect): `${PopoverPlacement}` { + getActualPlacement(targetRect: DOMRect): `${PopoverActualPlacement}` { const placement = this.placement; - let actualPlacement = placement; - const isVertical = placement === PopoverPlacement.Top - || placement === PopoverPlacement.Bottom; + const isVertical = placement === PopoverPlacement.Top || placement === PopoverPlacement.Bottom; const popoverSize = this.getPopoverSize(!this.allowTargetOverlap); + let actualPlacement: PopoverActualPlacement = PopoverActualPlacement.Right; + + switch (placement) { + case PopoverPlacement.Start: + actualPlacement = this.isRtl ? PopoverActualPlacement.Right : PopoverActualPlacement.Left; + break; + case PopoverPlacement.End: + actualPlacement = this.isRtl ? PopoverActualPlacement.Left : PopoverActualPlacement.Right; + break; + case PopoverPlacement.Top: + actualPlacement = PopoverActualPlacement.Top; + break; + case PopoverPlacement.Bottom: + actualPlacement = PopoverActualPlacement.Bottom; + break; + } + const clientWidth = document.documentElement.clientWidth; let clientHeight = document.documentElement.clientHeight; let popoverHeight = popoverSize.height; @@ -725,27 +754,27 @@ class Popover extends Popup { clientHeight -= Popover.VIEWPORT_MARGIN; } - switch (placement) { - case PopoverPlacement.Top: + switch (actualPlacement) { + case PopoverActualPlacement.Top: if (targetRect.top < popoverHeight && targetRect.top < clientHeight - targetRect.bottom) { - actualPlacement = PopoverPlacement.Bottom; + actualPlacement = PopoverActualPlacement.Bottom; } break; - case PopoverPlacement.Bottom: + case PopoverActualPlacement.Bottom: if (clientHeight - targetRect.bottom < popoverHeight && clientHeight - targetRect.bottom < targetRect.top) { - actualPlacement = PopoverPlacement.Top; + actualPlacement = PopoverActualPlacement.Top; } break; - case PopoverPlacement.Start: + case PopoverActualPlacement.Left: if (targetRect.left < popoverSize.width) { - actualPlacement = this.fallbackPlacement(clientWidth, clientHeight, targetRect, popoverSize) || placement; + actualPlacement = this.fallbackPlacement(clientWidth, clientHeight, targetRect, popoverSize) || actualPlacement; } break; - case PopoverPlacement.End: + case PopoverActualPlacement.Right: if (clientWidth - targetRect.right < popoverSize.width) { - actualPlacement = this.fallbackPlacement(clientWidth, clientHeight, targetRect, popoverSize) || placement; + actualPlacement = this.fallbackPlacement(clientWidth, clientHeight, targetRect, popoverSize) || actualPlacement; } break; } @@ -754,18 +783,18 @@ class Popover extends Popup { } getVerticalLeft(targetRect: DOMRect, popoverSize: PopoverSize): number { - const horizontalAlign = this._actualHorizontalAlign; + const actualHorizontalAlign = this._actualHorizontalAlign; let left = Popover.VIEWPORT_MARGIN; - switch (horizontalAlign) { - case PopoverHorizontalAlign.Center: - case PopoverHorizontalAlign.Stretch: + switch (actualHorizontalAlign) { + case PopoverActualHorizontalAlign.Center: + case PopoverActualHorizontalAlign.Stretch: left = targetRect.left - (popoverSize.width - targetRect.width) / 2; break; - case PopoverHorizontalAlign.Start: + case PopoverActualHorizontalAlign.Left: left = targetRect.left; break; - case PopoverHorizontalAlign.End: + case PopoverActualHorizontalAlign.Right: left = targetRect.right - popoverSize.width; break; } @@ -838,18 +867,22 @@ class Popover extends Popup { return true; } - get _actualHorizontalAlign() { - if (this.effectiveDir === "rtl") { - if (this.horizontalAlign === PopoverHorizontalAlign.Start) { - return PopoverHorizontalAlign.End; - } + get isRtl() { + return this.effectiveDir === "rtl"; + } - if (this.horizontalAlign === PopoverHorizontalAlign.End) { - return PopoverHorizontalAlign.Start; - } + get _actualHorizontalAlign() : PopoverActualHorizontalAlign { + switch (this.horizontalAlign) { + case PopoverHorizontalAlign.Start: + return this.isRtl ? PopoverActualHorizontalAlign.Right : PopoverActualHorizontalAlign.Left; + case PopoverHorizontalAlign.End: + return this.isRtl ? PopoverActualHorizontalAlign.Left : PopoverActualHorizontalAlign.Right; + case PopoverHorizontalAlign.Stretch: + return PopoverActualHorizontalAlign.Stretch; + case PopoverHorizontalAlign.Center: + default: + return PopoverActualHorizontalAlign.Center; } - - return this.horizontalAlign; } } diff --git a/packages/main/src/TextArea.ts b/packages/main/src/TextArea.ts index c879b7aa0be2..01bdda9214ba 100644 --- a/packages/main/src/TextArea.ts +++ b/packages/main/src/TextArea.ts @@ -17,7 +17,6 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js"; import type { IFormInputElement } from "@ui5/webcomponents-base/dist/features/InputElementsFormSupport.js"; import type Popover from "./Popover.js"; -import type PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import TextAreaTemplate from "./TextAreaTemplate.js"; @@ -658,10 +657,6 @@ class TextArea extends UI5Element implements IFormInputElement { return this.valueState === ValueState.Negative || this.valueState === ValueState.Critical || this.valueState === ValueState.Information; } - get _valueStatePopoverHorizontalAlign(): `${PopoverHorizontalAlign}` { - return this.effectiveDir !== "rtl" ? "Start" : "End"; - } - get valueStateTextMappings() { return { "Positive": TextArea.i18nBundle.getText(VALUE_STATE_SUCCESS), diff --git a/packages/main/src/TextAreaPopoverTemplate.tsx b/packages/main/src/TextAreaPopoverTemplate.tsx index ea829d1ebb77..a316249eb53f 100644 --- a/packages/main/src/TextAreaPopoverTemplate.tsx +++ b/packages/main/src/TextAreaPopoverTemplate.tsx @@ -1,4 +1,5 @@ import Icon from "./Icon.js"; +import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js"; import Popover from "./Popover.js"; import type TextArea from "./TextArea.js"; import error from "@ui5/webcomponents-icons/dist/error.js"; @@ -25,7 +26,7 @@ export default function TextAreaPopoverTemplate(this: TextArea) { class="ui5-valuestatemessage-popover" style={{ "max-width": `${this._width!}px` }} placement="Bottom" - horizontalAlign={this._valueStatePopoverHorizontalAlign} + horizontalAlign={PopoverHorizontalAlign.Start} >
Open Popover placement End +
+ Placement Start +
+
+
+ Placement End +
+
+
Email @@ -84,6 +93,28 @@
+ +
+
+ Some content +
+
+
+ + +
+
+ Some content +
+
+
+