Skip to content

Commit b8b9a98

Browse files
authored
feat(ui5-dynamic-page-title): implement snapped title on mobile (#9898)
* 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. * 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. * feat(ui5-dynamic-page-title): refactor snapped title documentation * 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.
1 parent 2d19119 commit b8b9a98

9 files changed

+427
-40
lines changed

packages/fiori/src/DynamicPage.hbs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
{{> header-actions}}
1818
{{/if}}
1919
</header>
20-
20+
2121
{{#if headerInContent}}
2222
<slot tabindex="{{headerTabIndex}}" ?aria-hidden="{{headerAriaHidden}}" name="headerArea"></slot>
2323
{{/if}}
@@ -42,17 +42,19 @@
4242
</div>
4343

4444
{{#*inline "header-actions"}}
45-
{{#if hasHeading}}
46-
<ui5-dynamic-page-header-actions
47-
?snapped="{{headerSnapped}}"
48-
?pinned="{{headerPinned}}"
49-
?hide-pin-button="{{hidePinButton}}"
50-
.accessibilityAttributes="{{_accAttributesForHeaderActions}}"
51-
@ui5-expand-button-click={{onExpandClick}}
52-
@ui5-pin-button-click={{onPinClick}}
53-
@ui5-expand-button-hover-in={{onExpandHoverIn}}
54-
@ui5-expand-button-hover-out={{onExpandHoverOut}}
55-
>
56-
</ui5-dynamic-page-header-actions>
57-
{{/if}}
45+
{{#unless hasSnappedTitleOnMobile}}
46+
{{#if hasHeading}}
47+
<ui5-dynamic-page-header-actions
48+
?snapped="{{headerSnapped}}"
49+
?pinned="{{headerPinned}}"
50+
?hide-pin-button="{{hidePinButton}}"
51+
.accessibilityAttributes="{{_accAttributesForHeaderActions}}"
52+
@ui5-expand-button-click={{onExpandClick}}
53+
@ui5-pin-button-click={{onPinClick}}
54+
@ui5-expand-button-hover-in={{onExpandHoverIn}}
55+
@ui5-expand-button-hover-out={{onExpandHoverOut}}
56+
>
57+
</ui5-dynamic-page-header-actions>
58+
{{/if}}
59+
{{/unless}}
5860
{{/inline}}

packages/fiori/src/DynamicPage.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import announce from "@ui5/webcomponents-base/dist/util/InvisibleMessage.js";
1313
import InvisibleMessageMode from "@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js";
1414
import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
1515
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
16+
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
1617

1718
import debounce from "@ui5/webcomponents-base/dist/util/debounce.js";
1819

@@ -223,6 +224,7 @@ class DynamicPage extends UI5Element {
223224
if (this.dynamicPageTitle) {
224225
this.dynamicPageTitle.snapped = this._headerSnapped;
225226
this.dynamicPageTitle.interactive = this.hasHeading;
227+
this.dynamicPageTitle.hasSnappedTitleOnMobile = !!this.hasSnappedTitleOnMobile;
226228
}
227229
}
228230

@@ -278,6 +280,10 @@ class DynamicPage extends UI5Element {
278280
return this._headerSnapped;
279281
}
280282

283+
get hasSnappedTitleOnMobile() {
284+
return isPhone() && this.headerSnapped && this.dynamicPageTitle?.snappedTitleOnMobile.length;
285+
}
286+
281287
/**
282288
* Defines if the header is snapped.
283289
*
@@ -327,6 +333,11 @@ class DynamicPage extends UI5Element {
327333
this.fireEvent("title-toggle");
328334
await renderFinished();
329335
this.headerActions?.focusExpandButton();
336+
337+
if (this.hasSnappedTitleOnMobile) {
338+
this.dynamicPageTitle?.focus();
339+
}
340+
330341
announce(this._headerLabel, InvisibleMessageMode.Polite);
331342
}
332343

packages/fiori/src/DynamicPageTitle.hbs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,48 @@
99
aria-labelledby="{{_ariaLabelledBy}}"
1010
aria-describedby="{{_id}}-toggle-description">
1111
</span>
12-
<div class="ui5-dynamic-page-title--top-area">
13-
<slot name="breadcrumbs"></slot>
1412

15-
{{#if mobileNavigationActions}}
16-
<slot name="navigationBar"></slot>
17-
{{/if}}
18-
</div>
13+
{{#if hasSnappedTitleOnMobile}}
14+
<div id="{{_id}}-heading" class="ui5-dynamic-page--snapped-title-on-mobile">
15+
<slot name="snappedTitleOnMobile"></slot>
16+
<ui5-icon name="slim-arrow-down" mode="Decorative"></ui5-icon>
17+
</div>
18+
{{else}}
19+
<div class="ui5-dynamic-page-title--top-area">
20+
<slot name="breadcrumbs"></slot>
1921

20-
<div class="ui5-dynamic-page-title--wrapper"
21-
@ui5-_min-content-width-change={{onMinContentWidthChange}}>
22-
<div id="{{_id}}-heading" class="ui5-dynamic-page-title--heading">
23-
<slot name="{{headingSlotName}}"></slot>
22+
{{#if mobileNavigationActions}}
23+
<slot name="navigationBar"></slot>
24+
{{/if}}
2425
</div>
2526

26-
{{#if hasContent}}
27-
<div class="ui5-dynamic-page-title--content"
28-
style="{{styles.content}}">
29-
<slot></slot>
27+
<div class="ui5-dynamic-page-title--wrapper"
28+
@ui5-_min-content-width-change={{onMinContentWidthChange}}>
29+
<div id="{{_id}}-heading" class="ui5-dynamic-page-title--heading">
30+
<slot name="{{headingSlotName}}"></slot>
3031
</div>
31-
{{/if}}
3232

33-
<div class="ui5-dynamic-page-title--actions"
34-
style="{{styles.actions}}">
35-
<slot name="actionsBar"></slot>
36-
{{#unless mobileNavigationActions}}
37-
{{#if _needsSeparator}}
38-
<div class="ui5-dynamic-page-title--actions-separator"></div>
39-
{{/if}}
40-
<slot name="navigationBar"></slot>
41-
{{/unless}}
33+
{{#if hasContent}}
34+
<div class="ui5-dynamic-page-title--content"
35+
style="{{styles.content}}">
36+
<slot></slot>
37+
</div>
38+
{{/if}}
39+
40+
<div class="ui5-dynamic-page-title--actions"
41+
style="{{styles.actions}}">
42+
<slot name="actionsBar"></slot>
43+
{{#unless mobileNavigationActions}}
44+
{{#if _needsSeparator}}
45+
<div class="ui5-dynamic-page-title--actions-separator"></div>
46+
{{/if}}
47+
<slot name="navigationBar"></slot>
48+
{{/unless}}
49+
</div>
4250
</div>
43-
</div>
4451

45-
<slot name="{{subheadingSlotName}}"></slot>
52+
<slot name="{{subheadingSlotName}}"></slot>
53+
{{/if}}
54+
4655
<span id="{{_id}}-toggle-description" class="ui5-hidden-text">{{_ariaDescribedbyText}}</span>
4756
</div>

packages/fiori/src/DynamicPageTitle.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import type Toolbar from "@ui5/webcomponents/dist/Toolbar.js";
1313
import type { ToolbarMinWidthChangeEventDetail } from "@ui5/webcomponents/dist/Toolbar.js";
1414
import ToolbarItemOverflowBehavior from "@ui5/webcomponents/dist/types/ToolbarItemOverflowBehavior.js";
1515
import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
16+
import Icon from "@ui5/webcomponents/dist/Icon.js";
17+
import Title from "@ui5/webcomponents/dist/Title.js";
1618

1719
// Template
1820
import DynamicPageTitleTemplate from "./generated/templates/DynamicPageTitleTemplate.lit.js";
@@ -63,6 +65,7 @@ import {
6365
renderer: litRender,
6466
styles: DynamicPageTitleCss,
6567
template: DynamicPageTitleTemplate,
68+
dependencies: [Title, Icon],
6669
})
6770

6871
/**
@@ -110,6 +113,13 @@ class DynamicPageTitle extends UI5Element {
110113
@property({ type: Number })
111114
minActionsWidth?: number;
112115

116+
/**
117+
* Indicates whether the title has snapped on mobile devices.
118+
* @private
119+
*/
120+
@property({ type: Boolean })
121+
hasSnappedTitleOnMobile = false;
122+
113123
/**
114124
* Defines the content of the Heading of the Dynamic Page.
115125
*
@@ -132,6 +142,22 @@ class DynamicPageTitle extends UI5Element {
132142
@slot({ type: HTMLElement })
133143
snappedHeading!: HTMLElement[];
134144

145+
/**
146+
* Defines the content of the snapped title on mobile devices.
147+
*
148+
* This slot is displayed only when the `DynamicPageTitle` is in the snapped state on mobile devices.
149+
* It should be used to provide a simplified, single-line title that takes up less space on smaller screens.
150+
*
151+
* **Note:**
152+
* - The content set in this slot **overrides** all other content set in the `DynamicPageTitle` slots when displayed.
153+
* - The slot is intended for a single `ui5-title` component.
154+
*
155+
* @public
156+
* @since 2.3.0
157+
*/
158+
@slot({ type: HTMLElement })
159+
snappedTitleOnMobile!: Array<Title>;
160+
135161
/**
136162
* Defines the bar with actions in the Dynamic page title.
137163
*

packages/fiori/src/themes/DynamicPage.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,11 @@
126126

127127
:host([media-range="XL"]) ::slotted([slot="headerArea"]) {
128128
padding: var(--_ui5_dynamic_page_header_padding_XL);
129+
}
130+
131+
/* snappedTitleOnMobile */
132+
:host([_header-snapped]) ::slotted([slot="headerArea"]) {
133+
height: 0;
134+
padding: 0;
135+
visibility: hidden;
129136
}

packages/fiori/src/themes/DynamicPageTitle.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
box-shadow: var(--sapContent_HeaderShadow);
3636
}
3737

38+
:host([has-snapped-title-on-mobile]) {
39+
min-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_min_height);
40+
line-height: var(--_ui5_dynamic_page_snapped_title_on_mobile_line_height);
41+
}
42+
3843
/* breadcrumbs */
3944
::slotted([ui5-breadcrumbs][slot="breadcrumbs"]) {
4045
padding: var(--_ui5_dynamic_page_title_breadcrumbs_padding_top) 0
@@ -88,6 +93,13 @@
8893
min-width: 1px;
8994
}
9095

96+
.ui5-dynamic-page--snapped-title-on-mobile {
97+
display: flex;
98+
justify-content: space-between;
99+
align-items: center;
100+
pointer-events: none;
101+
}
102+
91103
.ui5-dynamic-page-title--content {
92104
padding: 0 0 0 1rem;
93105
flex-shrink: 1.6;

packages/fiori/src/themes/base/DynamicPageTitle-parameters.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616

1717
--_ui5_dynamic_page_title_hover_background: var(--sapObjectHeader_Hover_Background);
1818

19+
--_ui5_dynamic_page_snapped_title_on_mobile_line_height: 2rem;
20+
--_ui5_dynamic_page_snapped_title_on_mobile_min_height: 2rem;
1921
}

0 commit comments

Comments
 (0)