From 136f3d263a083fa3403629484f121fa0f504492d Mon Sep 17 00:00:00 2001 From: Konstantin Gogov <konstantin.gogov@sap.com> Date: Wed, 4 Sep 2024 18:26:20 +0300 Subject: [PATCH 1/4] feat(ui5-dynamic-page-title): add snapped title for mobile devices - Introduced `snappedTitleOnMobile` property to display a simplified title on mobile when the header is snapped. - Added `snappedTitleOnMobileText` to define the text for the mobile-specific snapped title. - This feature optimizes title display on small screens, improving mobile usability. - Clicking the snapped title on mobile expands the header. - On non-mobile devices, the standard title is displayed, ignoring the mobile-specific title. --- packages/fiori/src/DynamicPage.hbs | 30 +-- packages/fiori/src/DynamicPage.ts | 12 + packages/fiori/src/DynamicPageTitle.hbs | 61 +++--- packages/fiori/src/DynamicPageTitle.ts | 38 +++- packages/fiori/src/themes/DynamicPage.css | 7 + .../fiori/src/themes/DynamicPageTitle.css | 15 ++ .../base/DynamicPageTitle-parameters.css | 2 + .../DynamicPageWithSnappedTitleOnMobile.html | 205 ++++++++++++++++++ .../test/specs/DynamicPage.mobile.spec.js | 105 +++++++++ packages/fiori/test/specs/DynamicPage.spec.js | 18 ++ 10 files changed, 452 insertions(+), 41 deletions(-) create mode 100644 packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html create mode 100644 packages/fiori/test/specs/DynamicPage.mobile.spec.js diff --git a/packages/fiori/src/DynamicPage.hbs b/packages/fiori/src/DynamicPage.hbs index 8354e83c5a1e..c037ba01571b 100644 --- a/packages/fiori/src/DynamicPage.hbs +++ b/packages/fiori/src/DynamicPage.hbs @@ -17,7 +17,7 @@ {{> header-actions}} {{/if}} </header> - + {{#if headerInContent}} <slot tabindex="{{headerTabIndex}}" ?aria-hidden="{{headerAriaHidden}}" name="headerArea"></slot> {{/if}} @@ -42,17 +42,19 @@ </div> {{#*inline "header-actions"}} - {{#if hasHeading}} - <ui5-dynamic-page-header-actions - ?snapped="{{headerSnapped}}" - ?pinned="{{headerPinned}}" - ?hide-pin-button="{{hidePinButton}}" - .accessibilityAttributes="{{_accAttributesForHeaderActions}}" - @ui5-expand-button-click={{onExpandClick}} - @ui5-pin-button-click={{onPinClick}} - @ui5-expand-button-hover-in={{onExpandHoverIn}} - @ui5-expand-button-hover-out={{onExpandHoverOut}} - > - </ui5-dynamic-page-header-actions> - {{/if}} + {{#unless hasSnappedTitleOnMobile}} + {{#if hasHeading}} + <ui5-dynamic-page-header-actions + ?snapped="{{headerSnapped}}" + ?pinned="{{headerPinned}}" + ?hide-pin-button="{{hidePinButton}}" + .accessibilityAttributes="{{_accAttributesForHeaderActions}}" + @ui5-expand-button-click={{onExpandClick}} + @ui5-pin-button-click={{onPinClick}} + @ui5-expand-button-hover-in={{onExpandHoverIn}} + @ui5-expand-button-hover-out={{onExpandHoverOut}} + > + </ui5-dynamic-page-header-actions> + {{/if}} + {{/unless}} {{/inline}} diff --git a/packages/fiori/src/DynamicPage.ts b/packages/fiori/src/DynamicPage.ts index b9dbb5cfbef5..8b38ddd37dfd 100644 --- a/packages/fiori/src/DynamicPage.ts +++ b/packages/fiori/src/DynamicPage.ts @@ -13,6 +13,7 @@ import announce from "@ui5/webcomponents-base/dist/util/InvisibleMessage.js"; import InvisibleMessageMode from "@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js"; import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { isPhone } from "@ui5/webcomponents-base/dist/Device.js"; import debounce from "@ui5/webcomponents-base/dist/util/debounce.js"; @@ -278,6 +279,12 @@ class DynamicPage extends UI5Element { return this._headerSnapped; } + get hasSnappedTitleOnMobile() { + return isPhone() + && this.headerSnapped + && (this.dynamicPageTitle?.snappedTitleOnMobile ?? false); + } + /** * Defines if the header is snapped. * @@ -327,6 +334,11 @@ class DynamicPage extends UI5Element { this.fireEvent("title-toggle"); await renderFinished(); this.headerActions?.focusExpandButton(); + + if (this.hasSnappedTitleOnMobile) { + this.dynamicPageTitle?.focus(); + } + announce(this._headerLabel, InvisibleMessageMode.Polite); } diff --git a/packages/fiori/src/DynamicPageTitle.hbs b/packages/fiori/src/DynamicPageTitle.hbs index d7e6de98ebfa..fa6b20f0e623 100644 --- a/packages/fiori/src/DynamicPageTitle.hbs +++ b/packages/fiori/src/DynamicPageTitle.hbs @@ -9,39 +9,48 @@ aria-labelledby="{{_ariaLabelledBy}}" aria-describedby="{{_id}}-toggle-description"> </span> - <div class="ui5-dynamic-page-title--top-area"> - <slot name="breadcrumbs"></slot> - {{#if mobileNavigationActions}} - <slot name="navigationBar"></slot> - {{/if}} - </div> + {{#if hasSnappedTitleOnMobile}} + <div id="{{_id}}-heading" class="ui5-dynamic-page--snapped-title-on-mobile"> + <ui5-title size="H4">{{snappedTitleOnMobileText}}</ui5-title> + <ui5-icon name="slim-arrow-down" mode="Decorative"></ui5-icon> + </div> + {{else}} + <div class="ui5-dynamic-page-title--top-area"> + <slot name="breadcrumbs"></slot> - <div class="ui5-dynamic-page-title--wrapper" - @ui5-_min-content-width-change={{onMinContentWidthChange}}> - <div id="{{_id}}-heading" class="ui5-dynamic-page-title--heading"> - <slot name="{{headingSlotName}}"></slot> + {{#if mobileNavigationActions}} + <slot name="navigationBar"></slot> + {{/if}} </div> - {{#if hasContent}} - <div class="ui5-dynamic-page-title--content" - style="{{styles.content}}"> - <slot></slot> + <div class="ui5-dynamic-page-title--wrapper" + @ui5-_min-content-width-change={{onMinContentWidthChange}}> + <div id="{{_id}}-heading" class="ui5-dynamic-page-title--heading"> + <slot name="{{headingSlotName}}"></slot> </div> - {{/if}} - <div class="ui5-dynamic-page-title--actions" - style="{{styles.actions}}"> - <slot name="actionsBar"></slot> - {{#unless mobileNavigationActions}} - {{#if _needsSeparator}} - <div class="ui5-dynamic-page-title--actions-separator"></div> - {{/if}} - <slot name="navigationBar"></slot> - {{/unless}} + {{#if hasContent}} + <div class="ui5-dynamic-page-title--content" + style="{{styles.content}}"> + <slot></slot> + </div> + {{/if}} + + <div class="ui5-dynamic-page-title--actions" + style="{{styles.actions}}"> + <slot name="actionsBar"></slot> + {{#unless mobileNavigationActions}} + {{#if _needsSeparator}} + <div class="ui5-dynamic-page-title--actions-separator"></div> + {{/if}} + <slot name="navigationBar"></slot> + {{/unless}} + </div> </div> - </div> - <slot name="{{subheadingSlotName}}"></slot> + <slot name="{{subheadingSlotName}}"></slot> + {{/if}} + <span id="{{_id}}-toggle-description" class="ui5-hidden-text">{{_ariaDescribedbyText}}</span> </div> \ No newline at end of file diff --git a/packages/fiori/src/DynamicPageTitle.ts b/packages/fiori/src/DynamicPageTitle.ts index 4c25fa163740..4f98fc4f4b79 100644 --- a/packages/fiori/src/DynamicPageTitle.ts +++ b/packages/fiori/src/DynamicPageTitle.ts @@ -12,7 +12,9 @@ import { isEnter, isSpace } from "@ui5/webcomponents-base/dist/Keys.js"; import type Toolbar from "@ui5/webcomponents/dist/Toolbar.js"; import type { ToolbarMinWidthChangeEventDetail } from "@ui5/webcomponents/dist/Toolbar.js"; import ToolbarItemOverflowBehavior from "@ui5/webcomponents/dist/types/ToolbarItemOverflowBehavior.js"; -import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js"; +import { isDesktop, isPhone } from "@ui5/webcomponents-base/dist/Device.js"; +import Icon from "@ui5/webcomponents/dist/Icon.js"; +import Title from "@ui5/webcomponents/dist/Title.js"; // Template import DynamicPageTitleTemplate from "./generated/templates/DynamicPageTitleTemplate.lit.js"; @@ -63,6 +65,7 @@ import { renderer: litRender, styles: DynamicPageTitleCss, template: DynamicPageTitleTemplate, + dependencies: [Title, Icon], }) /** @@ -81,6 +84,33 @@ class DynamicPageTitle extends UI5Element { @property({ type: Boolean }) snapped = false; + /** + * Defines if snapped title on mobile is enabled. + * + * Using this property enables you to provide a simple, single-line title that takes less space + * on the smaller phone screens when the DynamicPageHeader is in its collapsed (snapped) state. + * + * **Note:** The content set in `snappedTitleOnMobileText` overrides all other content set in the `DynamicPageTitle` slots + * and is only visible on phone screen sizes when the header is in snapped state. + * + * @public + */ + @property({ type: Boolean }) + snappedTitleOnMobile = false; + + /** + * Defines the text of the snapped title on mobile. + * + * The only content that is displayed in the DynamicPageTitle when it is viewed on a mobile device + * and the DynamicPageHeader is in collapsed (snapped) state. + * + * **Note:** This property takes effect if the `snappedTitleOnMobile` property is set to `true`. + * + * @public + */ + @property({ type: String }) + snappedTitleOnMobileText = ""; + /** * Defines if the mobileNavigationActions are shown. * @@ -244,6 +274,12 @@ class DynamicPageTitle extends UI5Element { return this.interactive ? "0" : undefined; } + get hasSnappedTitleOnMobile() { + return isPhone() + && this.snapped + && (this.snappedTitleOnMobile ?? false); + } + get _headerExpanded() { return !this.snapped; } diff --git a/packages/fiori/src/themes/DynamicPage.css b/packages/fiori/src/themes/DynamicPage.css index 93db2137cae4..c4415e41418b 100644 --- a/packages/fiori/src/themes/DynamicPage.css +++ b/packages/fiori/src/themes/DynamicPage.css @@ -126,4 +126,11 @@ :host([media-range="XL"]) ::slotted([slot="headerArea"]) { padding: var(--_ui5_dynamic_page_header_padding_XL); +} + +/* snappedTitleOnMobile */ +:host([_header-snapped]) ::slotted([slot="headerArea"]) { + height: 0; + padding: 0; + visibility: hidden; } \ No newline at end of file diff --git a/packages/fiori/src/themes/DynamicPageTitle.css b/packages/fiori/src/themes/DynamicPageTitle.css index e1159a671714..035f0da0486f 100644 --- a/packages/fiori/src/themes/DynamicPageTitle.css +++ b/packages/fiori/src/themes/DynamicPageTitle.css @@ -35,6 +35,10 @@ box-shadow: var(--sapContent_HeaderShadow); } +:host([snapped][snapped-title-on-mobile]) { + min-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_min_height); +} + /* breadcrumbs */ ::slotted([ui5-breadcrumbs][slot="breadcrumbs"]) { padding: var(--_ui5_dynamic_page_title_breadcrumbs_padding_top) 0 @@ -88,6 +92,17 @@ min-width: 1px; } +.ui5-dynamic-page--snapped-title-on-mobile { + display: flex; + justify-content: space-between; + align-items: center; + pointer-events: none; + + [ui5-title] { + line-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_line_height); + } +} + .ui5-dynamic-page-title--content { padding: 0 0 0 1rem; flex-shrink: 1.6; diff --git a/packages/fiori/src/themes/base/DynamicPageTitle-parameters.css b/packages/fiori/src/themes/base/DynamicPageTitle-parameters.css index eebbce124b13..c6f0fabc51ab 100644 --- a/packages/fiori/src/themes/base/DynamicPageTitle-parameters.css +++ b/packages/fiori/src/themes/base/DynamicPageTitle-parameters.css @@ -16,4 +16,6 @@ --_ui5_dynamic_page_title_hover_background: var(--sapObjectHeader_Hover_Background); + --_ui5_dynamic_page_snapped_title_on_mobile_line_height: 2rem; + --_ui5_dynamic_page_snapped_title_on_mobile_min_height: 2rem; } \ No newline at end of file diff --git a/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html b/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html new file mode 100644 index 000000000000..87c3bff7ae17 --- /dev/null +++ b/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html @@ -0,0 +1,205 @@ +<!DOCTYPE html> +<html> + <head> + <meta + name="viewport" + content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" + /> + <meta charset="utf-8" /> + + <title>Dynamic page</title> + + <script> + // delete Document.prototype.adoptedStyleSheets + </script> + + <script src="%VITE_BUNDLE_PATH%" type="module"></script> + + <link rel="stylesheet" type="text/css" href="./styles/DynamicPage.css" /> + + </head> + + <body> + <ui5-dynamic-page id="page" show-footer> + <ui5-dynamic-page-title slot="titleArea" snapped-title-on-mobile snapped-title-on-mobile-text="Snapped Title On Mobile"> + <ui5-breadcrumbs slot="breadcrumbs"> + <ui5-breadcrumbs-item href="#">Man</ui5-breadcrumbs-item> + <ui5-breadcrumbs-item href="#">Shoes</ui5-breadcrumbs-item> + <ui5-breadcrumbs-item href="#">Running Shoes</ui5-breadcrumbs-item> + </ui5-breadcrumbs> + + <ui5-title wrapping-type="None" slot="heading">Special Running Shoe</ui5-title> + + <div slot="snappedHeading" class="snapped-title-heading"> + <ui5-avatar shape="square" icon="laptop" color-scheme="Accent5" size="S"></ui5-avatar> + <ui5-title wrapping-type="None">Special Running Shoe</ui5-title> + </div> + + <p slot="subheading" class="text">PO-48865</p> + <p slot="snappedSubheading" class="text">PO-48865</p> + + <ui5-tag color-scheme="7">Special 157.4M EUR</ui5-tag> + + <ui5-toolbar id="actionsToolbar" slot="actionsBar" design="Transparent"> + <ui5-toolbar-button text="Create"></ui5-toolbar-button> + <ui5-toolbar-button id="edit-button" design="Transparent" text="Edit"></ui5-toolbar-button> + <ui5-toolbar-button design="Transparent" text="Paste"></ui5-toolbar-button> + </ui5-toolbar> + + <ui5-toolbar slot="navigationBar" design="Transparent"> + <ui5-toolbar-button design="Transparent" icon="share"></ui5-toolbar-button> + <ui5-toolbar-button design="Transparent" icon="action-settings"></ui5-toolbar-button> + </ui5-toolbar> + </ui5-dynamic-page-title> + + <ui5-dynamic-page-header slot="headerArea"> + <div class="product-info"> + <ui5-avatar id="avatar" shape="square" icon="laptop" color-scheme="Accent5" size="L"></ui5-avatar> + <div class="product-info-cell"> + <ui5-label>Availability</ui5-label> + <p class="text availability">In Stock</p> + </div> + <div class="product-info-cell"> + <ui5-label>Price</ui5-label> + <p class="text price">379.99 USD</p> + </div> + <div class="product-info-cell"> + <ui5-label>Product Description</ui5-label> + <p class="text product-description">Super-lightweight cushioning propels you forward from landing to toe-off and has a fast, snappy feel.</p> + </div> + </div> + </ui5-dynamic-page-header> + + <ui5-list header-text="Products (13)" mode="SingleSelect"> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="47.00 EUR">10 inch Portable DVD</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="249.00 EUR">7 inch WidescreenPortable DVD Player w MP3</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="947.00 EUR">Astro Laptop 1516</ui5-li> + <ui5-li description="HT-1251" icon="slim-arrow-right" icon-end additional-text="647.00 EUR">Astro Phone 6</ui5-li> + <ui5-li description="HT-1252" icon="slim-arrow-right" icon-end additional-text="27.99 EUR">Audio/Video Cable Kit - 4m</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="447.90 EUR">Beam Breaker B-1</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="647.50 EUR">Beam Breaker B-2</ui5-li> + <ui5-li description="HT-6001" icon="slim-arrow-right" icon-end additional-text="847.80 EUR">Beam Breaker B-3</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="1,250.00 EUR">Beam Breaker B-4</ui5-li> + <ui5-li description="HT-8001" icon="slim-arrow-right" icon-end additional-text="1,288.00 EUR">Camcorder View</ui5-li> + <ui5-li description="HT-2001" icon="slim-arrow-right" icon-end additional-text="996.00 EUR">Benda Laptop 1408</ui5-li> + <ui5-li description="HT-0003" icon="slim-arrow-right" icon-end additional-text="147.00 EUR">Cepat Tablet 10.5</ui5-li> + <ui5-li description="HT-1001" icon="slim-arrow-right" icon-end additional-text="87.90 EUR">Gladiator MX</ui5-li> + </ui5-list> + + <ui5-bar slot="footerArea" design="FloatingFooter"> + <ui5-button id="save-edit" slot="endContent">Save</ui5-button> + <ui5-button id="cancel-edit" slot="endContent">Close</ui5-button> + </ui5-bar> + </ui5-dynamic-page> + + <script> + const dynamicPage = document.querySelector("ui5-dynamic-page"); + const editButton = document.querySelector("#edit-button"); + + const cancelEdit = document.querySelector("#cancel-edit"); + const saveEdit = document.querySelector("#save-edit"); + + editButton.addEventListener("click", () => { + dynamicPage.setAttribute("show-footer", true); + }); + + [saveEdit, cancelEdit].forEach(button => { + button.addEventListener("click", () => { + dynamicPage.removeAttribute("show-footer"); + }); + }); + + dynamicPage.addEventListener("pin-button-toggle", event => { + console.log("Pin button toggled", dynamicPage.headerPinned) + }); + + dynamicPage.addEventListener("title-toggle", event => { + console.log("Title toggled", dynamicPage.headerSnapped) + }); + </script> + </body> +</html> diff --git a/packages/fiori/test/specs/DynamicPage.mobile.spec.js b/packages/fiori/test/specs/DynamicPage.mobile.spec.js new file mode 100644 index 000000000000..41dcfe3b6406 --- /dev/null +++ b/packages/fiori/test/specs/DynamicPage.mobile.spec.js @@ -0,0 +1,105 @@ +import { assert } from "chai"; + +describe("DynamicPage Mobile Behaviour", () => { + before(async () => { + await browser.url(`test/pages/DynamicPage_test.html`); + await browser.emulateDevice('iPhone X'); + }); + + it("should display snapped title on mobile when snappedTitleOnMobile is true and header is snapped", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to true and snap the header + await title.setProperty("snappedTitleOnMobile", true); + await title.setProperty("snappedTitleOnMobileText", "Snapped Title"); + await dynamicPage.setProperty("headerSnapped", true); + + // Check if the snapped title on mobile is visible + const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + assert.ok( + await snappedTitleOnMobile.isExisting(), + "Snapped title on mobile should be displayed when header is snapped and snappedTitleOnMobile is true." + ); + assert.strictEqual( + await snappedTitleOnMobile.getText(), + "Snapped Title", + "The snapped title on mobile should display the correct text." + ); + }); + + it("should not display snapped title on mobile when snappedTitleOnMobile is false", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to false and snap the header + await title.setProperty("snappedTitleOnMobile", false); + await dynamicPage.setProperty("headerSnapped", true); + + // Check if the snapped title on mobile is not visible + const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + assert.strictEqual( + await snappedTitleOnMobile.isExisting(), + false, + "Snapped title on mobile should not be displayed when snappedTitleOnMobile is false." + ); + }); + + it("should expand the header when clicked on the snapped title on mobile", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to true and snap the header + await title.setProperty("snappedTitleOnMobile", true); + await dynamicPage.setProperty("headerSnapped", true); + + // Click on the snapped title on mobile + const titleFocusArea = await title.shadow$(".ui5-dynamic-page-title-focus-area"); + await titleFocusArea.click(); + + // Check if the header is expanded + assert.strictEqual( + await dynamicPage.getProperty("headerSnapped"), + false, + "Header should expand when snapped title on mobile is clicked." + ); + }); + + it("should not display snapped title on mobile when header is not snapped", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to true but keep the header expanded + await title.setProperty("snappedTitleOnMobile", true); + await dynamicPage.setProperty("headerSnapped", false); + + // Check if the snapped title on mobile is not visible + const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + assert.strictEqual( + await snappedTitleOnMobile.isExisting(), + false, + "Snapped title on mobile should not be displayed when the header is not snapped." + ); + }); + + it("should focus the title focus area when header action is clicked to snap the header", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to true but keep the header expanded + await title.setProperty("snappedTitleOnMobile", true); + await dynamicPage.setProperty("headerSnapped", false); + + // Click on the header action to snap the header + const snapButton = await dynamicPage.shadow$("ui5-dynamic-page-header-actions") + .shadow$(".ui5-dynamic-page-header-action"); + await snapButton.click(); + + // Check if the title focus area is focused + const isFocused = await title.isFocused(); + assert.ok( + isFocused, + "Focus should be applied to the title focus area after snapping the header via header action." + ); + }); +}); \ No newline at end of file diff --git a/packages/fiori/test/specs/DynamicPage.spec.js b/packages/fiori/test/specs/DynamicPage.spec.js index a8a762379f1a..3c55b7649cd8 100644 --- a/packages/fiori/test/specs/DynamicPage.spec.js +++ b/packages/fiori/test/specs/DynamicPage.spec.js @@ -285,6 +285,24 @@ describe("Page general interaction", () => { assert.strictEqual(await page.getProperty("headerSnapped"), true, "Header is snapped"); }); + + it("should not display snapped title on non-mobile devices even if snappedTitleOnMobile is true", async () => { + const dynamicPage = await browser.$("#page"); + const title = await browser.$("#page ui5-dynamic-page-title"); + + // Set snappedTitleOnMobile to true and snap the header + await title.setProperty("snappedTitleOnMobile", true); + await title.setProperty("snappedTitleOnMobileText", "Snapped Title"); + await dynamicPage.setProperty("headerSnapped", true); + + // Check if the snapped title on mobile is not visible + const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + assert.strictEqual( + await snappedTitleOnMobile.isExisting(), + false, + "Snapped title on mobile should not be displayed on desktop devices even when snappedTitleOnMobile is true." + ); + }); }); describe("Page layout when content has 100% height", () => { From 16cc39334eb9290c1d50eaa78264931c53d6e20e Mon Sep 17 00:00:00 2001 From: Konstantin Gogov <konstantin.gogov@sap.com> Date: Wed, 25 Sep 2024 17:58:42 +0300 Subject: [PATCH 2/4] feat(ui5-dynamic-page-title): refactor snapped title implementation - Addressed review comments by changing the implementation of the snapped title on mobile. - Replaced properties with a slot for better flexibility and maintainability. --- packages/fiori/src/DynamicPage.ts | 4 +- packages/fiori/src/DynamicPageTitle.hbs | 4 +- packages/fiori/src/DynamicPageTitle.ts | 61 +++++++++--------- .../fiori/src/themes/DynamicPageTitle.css | 7 +-- .../DynamicPageWithSnappedTitleOnMobile.html | 4 +- .../test/specs/DynamicPage.mobile.spec.js | 62 ++++++++++--------- packages/fiori/test/specs/DynamicPage.spec.js | 18 ------ 7 files changed, 73 insertions(+), 87 deletions(-) diff --git a/packages/fiori/src/DynamicPage.ts b/packages/fiori/src/DynamicPage.ts index 8b38ddd37dfd..d7f72c8d0940 100644 --- a/packages/fiori/src/DynamicPage.ts +++ b/packages/fiori/src/DynamicPage.ts @@ -280,9 +280,7 @@ class DynamicPage extends UI5Element { } get hasSnappedTitleOnMobile() { - return isPhone() - && this.headerSnapped - && (this.dynamicPageTitle?.snappedTitleOnMobile ?? false); + return isPhone() && this.headerSnapped && this.dynamicPageTitle?.snappedTitleOnMobile.length; } /** diff --git a/packages/fiori/src/DynamicPageTitle.hbs b/packages/fiori/src/DynamicPageTitle.hbs index fa6b20f0e623..25aa2682b6ce 100644 --- a/packages/fiori/src/DynamicPageTitle.hbs +++ b/packages/fiori/src/DynamicPageTitle.hbs @@ -12,8 +12,8 @@ {{#if hasSnappedTitleOnMobile}} <div id="{{_id}}-heading" class="ui5-dynamic-page--snapped-title-on-mobile"> - <ui5-title size="H4">{{snappedTitleOnMobileText}}</ui5-title> - <ui5-icon name="slim-arrow-down" mode="Decorative"></ui5-icon> + <slot name="snappedTitleOnMobile"></slot> + <ui5-icon name="slim-arrow-down" mode="Decorative"></ui5-icon> </div> {{else}} <div class="ui5-dynamic-page-title--top-area"> diff --git a/packages/fiori/src/DynamicPageTitle.ts b/packages/fiori/src/DynamicPageTitle.ts index 4f98fc4f4b79..29c8587c6cf6 100644 --- a/packages/fiori/src/DynamicPageTitle.ts +++ b/packages/fiori/src/DynamicPageTitle.ts @@ -84,33 +84,6 @@ class DynamicPageTitle extends UI5Element { @property({ type: Boolean }) snapped = false; - /** - * Defines if snapped title on mobile is enabled. - * - * Using this property enables you to provide a simple, single-line title that takes less space - * on the smaller phone screens when the DynamicPageHeader is in its collapsed (snapped) state. - * - * **Note:** The content set in `snappedTitleOnMobileText` overrides all other content set in the `DynamicPageTitle` slots - * and is only visible on phone screen sizes when the header is in snapped state. - * - * @public - */ - @property({ type: Boolean }) - snappedTitleOnMobile = false; - - /** - * Defines the text of the snapped title on mobile. - * - * The only content that is displayed in the DynamicPageTitle when it is viewed on a mobile device - * and the DynamicPageHeader is in collapsed (snapped) state. - * - * **Note:** This property takes effect if the `snappedTitleOnMobile` property is set to `true`. - * - * @public - */ - @property({ type: String }) - snappedTitleOnMobileText = ""; - /** * Defines if the mobileNavigationActions are shown. * @@ -162,6 +135,30 @@ class DynamicPageTitle extends UI5Element { @slot({ type: HTMLElement }) snappedHeading!: HTMLElement[]; + /** + * Defines the content of the snapped title on mobile devices. + * + * This slot is displayed only when the `DynamicPageTitle` is in the snapped state on mobile devices. + * It should be used to provide a simplified, single-line title that takes up less space on smaller screens. + * + * **Note:** + * - The content set in this slot overrides all other content set in the `DynamicPageTitle` slots when displayed. + * - The slot is intended for a single `ui5-title` component. + * + * **Usage Example:** + * ```html + * <ui5-dynamic-page-title> + * <!-- Other slots like heading, subheading, etc. --> + * <ui5-title slot="snappedTitleOnMobile" size="H4" wrapping-type="None">My Snapped Mobile Title</ui5-title> + * </ui5-dynamic-page-title> + * ``` + * + * @public + * @since 2.3.0 + */ + @slot({ type: Title }) + snappedTitleOnMobile!: Array<Title>; + /** * Defines the bar with actions in the Dynamic page title. * @@ -242,6 +239,12 @@ class DynamicPageTitle extends UI5Element { onBeforeRendering() { this.prepareLayoutActions(); + + if (this.hasSnappedTitleOnMobile) { + this.setAttribute("_snapped-title-on-mobile", ""); + } else { + this.removeAttribute("_snapped-title-on-mobile"); + } } get styles() { @@ -275,9 +278,7 @@ class DynamicPageTitle extends UI5Element { } get hasSnappedTitleOnMobile() { - return isPhone() - && this.snapped - && (this.snappedTitleOnMobile ?? false); + return isPhone() && this.snapped && this.snappedTitleOnMobile.length; } get _headerExpanded() { diff --git a/packages/fiori/src/themes/DynamicPageTitle.css b/packages/fiori/src/themes/DynamicPageTitle.css index 035f0da0486f..87c1c720ae82 100644 --- a/packages/fiori/src/themes/DynamicPageTitle.css +++ b/packages/fiori/src/themes/DynamicPageTitle.css @@ -35,8 +35,9 @@ box-shadow: var(--sapContent_HeaderShadow); } -:host([snapped][snapped-title-on-mobile]) { +:host([snapped][_snapped-title-on-mobile]) { min-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_min_height); + line-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_line_height); } /* breadcrumbs */ @@ -97,10 +98,6 @@ justify-content: space-between; align-items: center; pointer-events: none; - - [ui5-title] { - line-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_line_height); - } } .ui5-dynamic-page-title--content { diff --git a/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html b/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html index 87c3bff7ae17..0d30bc33fb3a 100644 --- a/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html +++ b/packages/fiori/test/pages/DynamicPageWithSnappedTitleOnMobile.html @@ -21,7 +21,7 @@ <body> <ui5-dynamic-page id="page" show-footer> - <ui5-dynamic-page-title slot="titleArea" snapped-title-on-mobile snapped-title-on-mobile-text="Snapped Title On Mobile"> + <ui5-dynamic-page-title slot="titleArea"> <ui5-breadcrumbs slot="breadcrumbs"> <ui5-breadcrumbs-item href="#">Man</ui5-breadcrumbs-item> <ui5-breadcrumbs-item href="#">Shoes</ui5-breadcrumbs-item> @@ -30,6 +30,8 @@ <ui5-title wrapping-type="None" slot="heading">Special Running Shoe</ui5-title> + <ui5-title wrapping-type="None" slot="snappedTitleOnMobile" size="H4">Snapped Title On Mobile</ui5-title> + <div slot="snappedHeading" class="snapped-title-heading"> <ui5-avatar shape="square" icon="laptop" color-scheme="Accent5" size="S"></ui5-avatar> <ui5-title wrapping-type="None">Special Running Shoe</ui5-title> diff --git a/packages/fiori/test/specs/DynamicPage.mobile.spec.js b/packages/fiori/test/specs/DynamicPage.mobile.spec.js index 41dcfe3b6406..6407fb7a5dab 100644 --- a/packages/fiori/test/specs/DynamicPage.mobile.spec.js +++ b/packages/fiori/test/specs/DynamicPage.mobile.spec.js @@ -1,47 +1,52 @@ import { assert } from "chai"; describe("DynamicPage Mobile Behaviour", () => { - before(async () => { - await browser.url(`test/pages/DynamicPage_test.html`); - await browser.emulateDevice('iPhone X'); + beforeEach(async () => { + await browser.url("test/pages/DynamicPageWithSnappedTitleOnMobile.html"); + await browser.emulateDevice("iPhone X"); }); - it("should display snapped title on mobile when snappedTitleOnMobile is true and header is snapped", async () => { + it("should display snapped title on mobile when snappedTitleOnMobile slot has content and header is snapped", async () => { const dynamicPage = await browser.$("#page"); const title = await browser.$("#page ui5-dynamic-page-title"); - // Set snappedTitleOnMobile to true and snap the header - await title.setProperty("snappedTitleOnMobile", true); - await title.setProperty("snappedTitleOnMobileText", "Snapped Title"); + // Ensure the header is snapped await dynamicPage.setProperty("headerSnapped", true); // Check if the snapped title on mobile is visible const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + const isDisplayed = await snappedTitleOnMobile.isDisplayed(); + assert.ok( - await snappedTitleOnMobile.isExisting(), - "Snapped title on mobile should be displayed when header is snapped and snappedTitleOnMobile is true." - ); - assert.strictEqual( - await snappedTitleOnMobile.getText(), - "Snapped Title", - "The snapped title on mobile should display the correct text." + isDisplayed, + "Snapped title on mobile should be displayed when header is snapped and snappedTitleOnMobile slot has content." ); }); - it("should not display snapped title on mobile when snappedTitleOnMobile is false", async () => { + it("should not display snapped title on mobile when snappedTitleOnMobile slot is empty", async () => { const dynamicPage = await browser.$("#page"); const title = await browser.$("#page ui5-dynamic-page-title"); - // Set snappedTitleOnMobile to false and snap the header - await title.setProperty("snappedTitleOnMobile", false); + // Remove content from the snappedTitleOnMobile slot + await browser.execute(() => { + const titleElement = document.querySelector("#page ui5-dynamic-page-title"); + const snappedTitleContent = titleElement.querySelector("[slot='snappedTitleOnMobile']"); + if (snappedTitleContent) { + titleElement.removeChild(snappedTitleContent); + } + }); + + // Snap the header await dynamicPage.setProperty("headerSnapped", true); // Check if the snapped title on mobile is not visible const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + const isDisplayed = await snappedTitleOnMobile.isDisplayed(); + assert.strictEqual( - await snappedTitleOnMobile.isExisting(), + isDisplayed, false, - "Snapped title on mobile should not be displayed when snappedTitleOnMobile is false." + "Snapped title on mobile should not be displayed when the snappedTitleOnMobile slot is empty." ); }); @@ -49,17 +54,18 @@ describe("DynamicPage Mobile Behaviour", () => { const dynamicPage = await browser.$("#page"); const title = await browser.$("#page ui5-dynamic-page-title"); - // Set snappedTitleOnMobile to true and snap the header - await title.setProperty("snappedTitleOnMobile", true); + // Ensure the header is snapped await dynamicPage.setProperty("headerSnapped", true); - // Click on the snapped title on mobile + // Click on the title focus area to expand the header const titleFocusArea = await title.shadow$(".ui5-dynamic-page-title-focus-area"); await titleFocusArea.click(); // Check if the header is expanded + const headerSnapped = await dynamicPage.getProperty("headerSnapped"); + assert.strictEqual( - await dynamicPage.getProperty("headerSnapped"), + headerSnapped, false, "Header should expand when snapped title on mobile is clicked." ); @@ -69,14 +75,15 @@ describe("DynamicPage Mobile Behaviour", () => { const dynamicPage = await browser.$("#page"); const title = await browser.$("#page ui5-dynamic-page-title"); - // Set snappedTitleOnMobile to true but keep the header expanded - await title.setProperty("snappedTitleOnMobile", true); + // Ensure the header is not snapped await dynamicPage.setProperty("headerSnapped", false); // Check if the snapped title on mobile is not visible const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); + const isDisplayed = await snappedTitleOnMobile.isDisplayed(); + assert.strictEqual( - await snappedTitleOnMobile.isExisting(), + isDisplayed, false, "Snapped title on mobile should not be displayed when the header is not snapped." ); @@ -86,8 +93,7 @@ describe("DynamicPage Mobile Behaviour", () => { const dynamicPage = await browser.$("#page"); const title = await browser.$("#page ui5-dynamic-page-title"); - // Set snappedTitleOnMobile to true but keep the header expanded - await title.setProperty("snappedTitleOnMobile", true); + // Ensure the header is expanded await dynamicPage.setProperty("headerSnapped", false); // Click on the header action to snap the header diff --git a/packages/fiori/test/specs/DynamicPage.spec.js b/packages/fiori/test/specs/DynamicPage.spec.js index 3c55b7649cd8..a8a762379f1a 100644 --- a/packages/fiori/test/specs/DynamicPage.spec.js +++ b/packages/fiori/test/specs/DynamicPage.spec.js @@ -285,24 +285,6 @@ describe("Page general interaction", () => { assert.strictEqual(await page.getProperty("headerSnapped"), true, "Header is snapped"); }); - - it("should not display snapped title on non-mobile devices even if snappedTitleOnMobile is true", async () => { - const dynamicPage = await browser.$("#page"); - const title = await browser.$("#page ui5-dynamic-page-title"); - - // Set snappedTitleOnMobile to true and snap the header - await title.setProperty("snappedTitleOnMobile", true); - await title.setProperty("snappedTitleOnMobileText", "Snapped Title"); - await dynamicPage.setProperty("headerSnapped", true); - - // Check if the snapped title on mobile is not visible - const snappedTitleOnMobile = await title.shadow$(".ui5-dynamic-page--snapped-title-on-mobile"); - assert.strictEqual( - await snappedTitleOnMobile.isExisting(), - false, - "Snapped title on mobile should not be displayed on desktop devices even when snappedTitleOnMobile is true." - ); - }); }); describe("Page layout when content has 100% height", () => { From 5aaa5f6e1daf5a61a4ea6a69b0e8f068daa6479e Mon Sep 17 00:00:00 2001 From: Konstantin Gogov <konstantin.gogov@sap.com> Date: Wed, 25 Sep 2024 18:21:33 +0300 Subject: [PATCH 3/4] feat(ui5-dynamic-page-title): refactor snapped title documentation --- packages/fiori/src/DynamicPageTitle.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/fiori/src/DynamicPageTitle.ts b/packages/fiori/src/DynamicPageTitle.ts index 29c8587c6cf6..ca1ea7d4c263 100644 --- a/packages/fiori/src/DynamicPageTitle.ts +++ b/packages/fiori/src/DynamicPageTitle.ts @@ -142,17 +142,9 @@ class DynamicPageTitle extends UI5Element { * It should be used to provide a simplified, single-line title that takes up less space on smaller screens. * * **Note:** - * - The content set in this slot overrides all other content set in the `DynamicPageTitle` slots when displayed. + * - The content set in this slot **overrides** all other content set in the `DynamicPageTitle` slots when displayed. * - The slot is intended for a single `ui5-title` component. * - * **Usage Example:** - * ```html - * <ui5-dynamic-page-title> - * <!-- Other slots like heading, subheading, etc. --> - * <ui5-title slot="snappedTitleOnMobile" size="H4" wrapping-type="None">My Snapped Mobile Title</ui5-title> - * </ui5-dynamic-page-title> - * ``` - * * @public * @since 2.3.0 */ From 982ec0a9481071299aae2984c7a0c04331166658 Mon Sep 17 00:00:00 2001 From: Konstantin Gogov <konstantin.gogov@sap.com> Date: Thu, 26 Sep 2024 12:23:06 +0300 Subject: [PATCH 4/4] feat(ui5-dynamic-page-title): streamline snapped title handling on mobile Refactored the implementation to pass the "snappedTitleOnMobile" state from parent to child. This change ensures proper state management, addressing previous review comments. --- packages/fiori/src/DynamicPage.ts | 1 + packages/fiori/src/DynamicPageTitle.ts | 21 ++++++++----------- .../fiori/src/themes/DynamicPageTitle.css | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/fiori/src/DynamicPage.ts b/packages/fiori/src/DynamicPage.ts index d7f72c8d0940..c197dad11d68 100644 --- a/packages/fiori/src/DynamicPage.ts +++ b/packages/fiori/src/DynamicPage.ts @@ -224,6 +224,7 @@ class DynamicPage extends UI5Element { if (this.dynamicPageTitle) { this.dynamicPageTitle.snapped = this._headerSnapped; this.dynamicPageTitle.interactive = this.hasHeading; + this.dynamicPageTitle.hasSnappedTitleOnMobile = !!this.hasSnappedTitleOnMobile; } } diff --git a/packages/fiori/src/DynamicPageTitle.ts b/packages/fiori/src/DynamicPageTitle.ts index ca1ea7d4c263..acf37be2a2bf 100644 --- a/packages/fiori/src/DynamicPageTitle.ts +++ b/packages/fiori/src/DynamicPageTitle.ts @@ -12,7 +12,7 @@ import { isEnter, isSpace } from "@ui5/webcomponents-base/dist/Keys.js"; import type Toolbar from "@ui5/webcomponents/dist/Toolbar.js"; import type { ToolbarMinWidthChangeEventDetail } from "@ui5/webcomponents/dist/Toolbar.js"; import ToolbarItemOverflowBehavior from "@ui5/webcomponents/dist/types/ToolbarItemOverflowBehavior.js"; -import { isDesktop, isPhone } from "@ui5/webcomponents-base/dist/Device.js"; +import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js"; import Icon from "@ui5/webcomponents/dist/Icon.js"; import Title from "@ui5/webcomponents/dist/Title.js"; @@ -113,6 +113,13 @@ class DynamicPageTitle extends UI5Element { @property({ type: Number }) minActionsWidth?: number; + /** + * Indicates whether the title has snapped on mobile devices. + * @private + */ + @property({ type: Boolean }) + hasSnappedTitleOnMobile = false; + /** * Defines the content of the Heading of the Dynamic Page. * @@ -148,7 +155,7 @@ class DynamicPageTitle extends UI5Element { * @public * @since 2.3.0 */ - @slot({ type: Title }) + @slot({ type: HTMLElement }) snappedTitleOnMobile!: Array<Title>; /** @@ -231,12 +238,6 @@ class DynamicPageTitle extends UI5Element { onBeforeRendering() { this.prepareLayoutActions(); - - if (this.hasSnappedTitleOnMobile) { - this.setAttribute("_snapped-title-on-mobile", ""); - } else { - this.removeAttribute("_snapped-title-on-mobile"); - } } get styles() { @@ -269,10 +270,6 @@ class DynamicPageTitle extends UI5Element { return this.interactive ? "0" : undefined; } - get hasSnappedTitleOnMobile() { - return isPhone() && this.snapped && this.snappedTitleOnMobile.length; - } - get _headerExpanded() { return !this.snapped; } diff --git a/packages/fiori/src/themes/DynamicPageTitle.css b/packages/fiori/src/themes/DynamicPageTitle.css index 87c1c720ae82..3c2f875b9c27 100644 --- a/packages/fiori/src/themes/DynamicPageTitle.css +++ b/packages/fiori/src/themes/DynamicPageTitle.css @@ -35,7 +35,7 @@ box-shadow: var(--sapContent_HeaderShadow); } -:host([snapped][_snapped-title-on-mobile]) { +:host([has-snapped-title-on-mobile]) { min-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_min_height); line-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_line_height); }