Skip to content

chore(ui5-side-navigation): simplify rendering templates #11900

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9bc7c21
chore(ui5-side-navigation): simplify rendering templates
TeodorTaushanov Jul 10, 2025
8e63b79
chore: fix lint error
TeodorTaushanov Jul 11, 2025
6a64855
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 11, 2025
620ee2e
chore: simplify code
TeodorTaushanov Jul 11, 2025
2c8f7f0
chore: simplify code
TeodorTaushanov Jul 11, 2025
94a94b0
fix: fixed aria-haspopup logic
TeodorTaushanov Jul 11, 2025
e9716d4
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 11, 2025
0f7d28a
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 14, 2025
bc8eb06
chore: simplifying code
TeodorTaushanov Jul 14, 2025
ecddfb5
chore: simplifying code
TeodorTaushanov Jul 14, 2025
739cdd0
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 15, 2025
d27c1e4
chore: simplifying code
TeodorTaushanov Jul 15, 2025
12ada28
chore: add base template
TeodorTaushanov Jul 15, 2025
a9563ca
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 15, 2025
423babc
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 16, 2025
cf21e73
fix: fix tests
TeodorTaushanov Jul 16, 2025
9d862fe
chore: simplify template attributes
TeodorTaushanov Jul 16, 2025
84aa2c8
chore: fix lint error
TeodorTaushanov Jul 16, 2025
8682944
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 17, 2025
0bdf6b6
chore: simplify code
TeodorTaushanov Jul 17, 2025
9a6e33e
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 25, 2025
5430c7a
chore: remove base template
TeodorTaushanov Jul 25, 2025
7f24f98
Merge remote-tracking branch 'origin/main' into sidenav_templates
TeodorTaushanov Jul 29, 2025
f9d214a
chore: remove obsolete code
TeodorTaushanov Jul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions packages/fiori/src/SideNavigationGroupTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,24 @@ function TreeItemTemplate(this: SideNavigationGroup) {
role="none"
>
<div class="ui5-sn-item-separator"></div>
<div class={`ui5-sn-item ui5-sn-item-group ${this._classes}`}
role="treeitem"
data-sap-focus-ref
onKeyDown={this._onkeydown}
onClick={this._onclick}
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex ? parseInt(this.effectiveTabIndex) : undefined}
aria-expanded={this._expanded}
title={this._tooltip}
aria-owns={this._groupId}
<div id={this._id}
data-sap-focus-ref
class={`ui5-sn-item ui5-sn-item-group ${this._classes}`}
role="treeitem"
onKeyDown={this._onkeydown}
onClick={this._onclick}
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex}
aria-expanded={this._expanded}
title={this._tooltip}
aria-owns={this._groupId}
>
<div class="ui5-sn-item-text">{this.text}</div>
{!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={this.expanded ? navDownArrow : navRightArrow}
accessibleName={this._arrowTooltip}
showTooltip={true}
name={this.expanded ? navDownArrow : navRightArrow}
accessibleName={this._arrowTooltip}
showTooltip={true}
/>
}
</div>
Expand Down
18 changes: 11 additions & 7 deletions packages/fiori/src/SideNavigationItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,27 +145,31 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
return "tree";
}

if (this.accessibilityAttributes?.hasPopup) {
return this.accessibilityAttributes.hasPopup;
}

return undefined;
}

get _ariaChecked() {
if (this.isOverflow || this.unselectable) {
if (this.isOverflow || this.unselectable || !this.sideNavCollapsed) {
return undefined;
}

return this.selected;
}

get _groupId() {
if (!this.items.length) {
if (!this.items.length || this.sideNavCollapsed) {
return undefined;
}

return `${this._id}-group`;
}

get _expanded() {
if (!this.items.length) {
if (!this.items.length || this.sideNavCollapsed) {
return undefined;
}

Expand Down Expand Up @@ -313,15 +317,15 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
this.getDomRef()!.classList.add("ui5-sn-item-no-hover-effect");
}

get isSideNavigationItem() {
return true;
}

_toggle() {
if (this.items.length && !this.effectiveDisabled) {
this.expanded = !this.expanded;
}
}

get isSideNavigationItem() {
return true;
}
}

SideNavigationItem.define();
Expand Down
2 changes: 1 addition & 1 deletion packages/fiori/src/SideNavigationItemBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class SideNavigationItemBase extends UI5Element implements ITabbable {
}

get effectiveTabIndex() {
return this.forcedTabIndex || undefined;
return this.forcedTabIndex !== undefined ? parseInt(this.forcedTabIndex) : undefined;
}

get sideNavigation() {
Expand Down
188 changes: 53 additions & 135 deletions packages/fiori/src/SideNavigationItemTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,154 +6,72 @@ import type SideNavigationItem from "./SideNavigationItem.js";

export default function SideNavigationItemTemplate(this: SideNavigationItem) {
if (this.sideNavCollapsed) {
return MenuItemTemplate.call(this);
return ItemTemplate.call(this);
}
return TreeItemTemplate.call(this);

return (
<li id={this._id} class="ui5-sn-list-li" role="none">
{ItemTemplate.call(this)}
</li>
);
}

function MenuItemTemplate(this: SideNavigationItem) {
return (<>
{this._href ?
<a id={this._id}
class={`ui5-sn-item ui5-sn-item-level1 ${this._classes}`}
role={this.ariaRole}
data-sap-focus-ref
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onFocusIn={this._onfocusin}
onFocusOut={this._onfocusout}
onMouseEnter={this._onmouseenter}
onMouseLeave={this._onmouseleave}
tabIndex={this.effectiveTabIndex !== undefined ? parseInt(this.effectiveTabIndex) : undefined}
aria-haspopup={this._ariaHasPopup}
aria-checked={this._ariaChecked}
title={this._tooltip}
href={this._href}
target={this._target}
function ItemTemplate(this: SideNavigationItem) {
const EffectiveTag = this._effectiveTag;

return (
<>
<EffectiveTag id={this._id}
data-sap-focus-ref
class={`ui5-sn-item ui5-sn-item-level1 ${this._classes}`}
role={this.ariaRole}
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex}
aria-current={this._ariaCurrent}
aria-selected={this._ariaSelected}
title={this._tooltip}
aria-disabled={this.effectiveDisabled}
href={this._href}
target={this._target}
aria-haspopup={this._ariaHasPopup}
onFocusOut={this._onfocusout}
onMouseEnter={this._onmouseenter}
onMouseLeave={this._onmouseleave}
aria-checked={this._ariaChecked}
aria-owns={this._groupId}
aria-label={this._ariaLabel}
aria-expanded={this._expanded}
>
<Icon class="ui5-sn-item-icon" name={this.icon}/>
{this.sideNavCollapsed ?
<Icon class="ui5-sn-item-icon" name={this.icon}/>
:
this.icon && <Icon class="ui5-sn-item-icon" name={this.icon}/>
}
<div class="ui5-sn-item-text">{this.text}</div>
{!!this.items.length &&
{this.sideNavCollapsed ?
!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={navRightArrow}
name={navRightArrow}
/>
}
{this.isExternalLink &&
<Icon class="ui5-sn-item-external-link-icon"
name={arrowRight}
/>
}
</a>
:
<div id={this._id}
class={`ui5-sn-item ui5-sn-item-level1 ${this._classes}`}
role={this.ariaRole}
data-sap-focus-ref
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onFocusIn={this._onfocusin}
onFocusOut={this._onfocusout}
onMouseEnter={this._onmouseenter}
onMouseLeave={this._onmouseleave}
tabIndex={this.effectiveTabIndex !== undefined ? parseInt(this.effectiveTabIndex) : undefined}
aria-haspopup={this._ariaHasPopup}
aria-checked={this._ariaChecked}
title={this._tooltip}
aria-label={this._ariaLabel}
>
<Icon class="ui5-sn-item-icon" name={this.icon}/>
<div class="ui5-sn-item-text">{this.text}</div>
{!!this.items.length &&
:
!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={navRightArrow}
name={this.expanded ? navDownArrow : navRightArrow}
accessibleName={this._arrowTooltip}
showTooltip={true}
onClick={this._onToggleClick}
/>
}
{this.isExternalLink &&
<Icon class="ui5-sn-item-external-link-icon"
name={arrowRight}
name={arrowRight}
/>
}
</div>
}
</>);
}

function TreeItemTemplate(this: SideNavigationItem) {
return (
<li id={this._id} class="ui5-sn-list-li" role="none">
{this._href ?
<a class={`ui5-sn-item ui5-sn-item-level1 ${this._classes}`}
role={this.ariaRole}
data-sap-focus-ref
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex !== undefined ? parseInt(this.effectiveTabIndex) : undefined}
aria-expanded={this._expanded}
aria-current={this._ariaCurrent}
aria-selected={this.selected}
title={this._tooltip}
aria-owns={this._groupId}
href={this._href}
target={this._target}
>
{this.icon &&
<Icon class="ui5-sn-item-icon" name={this.icon}/>
}
<div class="ui5-sn-item-text">{this.text}</div>
{this.isExternalLink &&
<Icon class="ui5-sn-item-external-link-icon"
name={arrowRight}
/>
}
{!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={this.expanded ? navDownArrow : navRightArrow}
accessibleName={this._arrowTooltip}
showTooltip={true}
onClick={this._onToggleClick}
/>
}
</a>
:
<div class={`ui5-sn-item ui5-sn-item-level1 ${this._classes}`}
role={this.ariaRole}
data-sap-focus-ref
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex !== undefined ? parseInt(this.effectiveTabIndex) : undefined}
aria-expanded={this._expanded}
aria-current={this._ariaCurrent}
aria-selected={this.selected}
aria-haspopup={this.accessibilityAttributes?.hasPopup}
title={this._tooltip}
aria-owns={this._groupId}
>
{this.icon &&
<Icon class="ui5-sn-item-icon" name={this.icon}/>
}
<div class="ui5-sn-item-text">{this.text}</div>
{this.isExternalLink &&
<Icon class="ui5-sn-item-external-link-icon"
name={arrowRight}
/>
}
{!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={this.expanded ? navDownArrow : navRightArrow}
accessibleName={this._arrowTooltip}
showTooltip={true}
onClick={this._onToggleClick}
/>
}
</div>
}
{!!this.items.length &&
</EffectiveTag>
{!this.sideNavCollapsed && !!this.items.length &&
<ul id={this._groupId}
class="ui5-sn-item-ul"
aria-label={this.text}
Expand All @@ -162,6 +80,6 @@ function TreeItemTemplate(this: SideNavigationItem) {
<slot></slot>
</ul>
}
</li>
</>
);
}
47 changes: 18 additions & 29 deletions packages/fiori/src/SideNavigationPopoverTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ import SideNavigationItem from "./SideNavigationItem.js";
import SideNavigationSubItem from "./SideNavigationSubItem.js";

export default function SideNavigationTemplate(this: SideNavigation) {
const renderMenuItem = (item: SideNavigationItem | SideNavigationSubItem) => (
<NavigationMenuItem
accessibilityAttributes={item.accessibilityAttributes}
text={item.text}
icon={item.icon}
design={item.design}
disabled={item.disabled}
href={item.href}
target={item.target}
title={item.title}
tooltip={item._tooltip}
ref={this.captureRef.bind(item)}
>
{(item as any).items?.map(renderMenuItem)}
</NavigationMenuItem>
);

return (<>
<NavigationMenu
id={`${this._id}-side-navigation-overflow-menu`}
Expand All @@ -14,35 +31,7 @@ export default function SideNavigationTemplate(this: SideNavigation) {
onClose={this._onMenuClose}
class="ui5-side-navigation-popover ui5-side-navigation-overflow-menu"
>
{this._menuPopoverItems.map(item =>
<NavigationMenuItem
accessibilityAttributes={item.accessibilityAttributes}
text={item.text}
icon={item.icon}
design={item.design}
disabled={item.disabled}
href={item.href}
target={item.target}
title={item.title}
tooltip={item._tooltip}
ref={this.captureRef.bind(item)}
>
{item.items.map(subItem =>
<NavigationMenuItem
accessibilityAttributes={subItem.accessibilityAttributes}
text={subItem.text}
icon={subItem.icon}
design={subItem.design}
disabled={subItem.disabled}
ref={this.captureRef.bind(subItem)}
href={subItem.href}
target={subItem.target}
title={subItem.title}
tooltip={subItem._tooltip}
/>
)}
</NavigationMenuItem>
)}
{this._menuPopoverItems.map(renderMenuItem)}
</NavigationMenu>
<ResponsivePopover
verticalAlign="Top"
Expand Down
Loading
Loading