Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 25 additions & 2 deletions packages/fiori/src/SideNavigationItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
SIDE_NAVIGATION_OVERFLOW_ITEM_LABEL,
SIDE_NAVIGATION_PARENT_ITEM_SELECTABLE_DESCRIPTION,
} from "./generated/i18n/i18n-defaults.js";
import type { DefaultSlot } from "@ui5/webcomponents-base/dist/UI5Element.js";
import type { DefaultSlot, Slot } from "@ui5/webcomponents-base/dist/UI5Element.js";
import "@ui5/webcomponents/dist/Tag.js";

// Templates
import SideNavigationItemTemplate from "./SideNavigationItemTemplate.js";
Expand Down Expand Up @@ -81,6 +82,16 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
@slot({ type: HTMLElement, invalidateOnChildChange: true, "default": true })
items!: DefaultSlot<SideNavigationSubItem>;

/**
* Defines the tag to be displayed.
* Only `ui5-tag` component should be used.
*
* @public
* @since 2.7.0
*/
@slot({ type: HTMLElement })
tag!: Slot<HTMLElement>;

@i18n("@ui5/webcomponents-fiori")
static i18nBundle: I18nBundle;

Expand Down Expand Up @@ -183,9 +194,21 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
}

get _describedBy() {
const parts: string[] = [];

if (this.hasTag) {
parts.push(this._tagId);
}

if (!this.effectiveDisabled && this.items.length && !this.unselectable) {
return SideNavigationItem.i18nBundle.getText(SIDE_NAVIGATION_PARENT_ITEM_SELECTABLE_DESCRIPTION, this.text ?? "");
parts.push(SideNavigationItem.i18nBundle.getText(SIDE_NAVIGATION_PARENT_ITEM_SELECTABLE_DESCRIPTION, this.text ?? ""));
}

return parts.length > 0 ? parts.join(" ") : undefined;
}

get hasTag() {
return !!this.tag.length;
}

get classesArray() {
Expand Down
3 changes: 3 additions & 0 deletions packages/fiori/src/SideNavigationItemTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ function ItemTemplate(this: SideNavigationItem) {
this.icon && <Icon class="ui5-sn-item-icon" name={this.icon}/>
}
<div class="ui5-sn-item-text">{this.text}</div>
{this.hasTag &&
<slot name="tag" id={this._tagId} class="ui5-sn-item-tag-slot"></slot>
}
{this.sideNavCollapsed ?
!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
Expand Down
63 changes: 56 additions & 7 deletions packages/fiori/src/SideNavigationPopoverTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,20 @@
target={item.target}
title={item.title}
tooltip={item._tooltip}
ref={this.captureRef.bind(item)}
ref={(el: HTMLElement | null) => {
if (el && item.tag.length > 0) {
const existingTags = Array.from(el.children).filter(child => child.getAttribute('slot') === 'endContent');

Check failure on line 22 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote

Check failure on line 22 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote
if (existingTags.length === 0) {
item.tag.forEach((tagEl) => {

Check failure on line 24 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Unexpected parentheses around single function argument
const clonedTag = tagEl.cloneNode(true) as HTMLElement;
clonedTag.slot = 'endContent';

Check failure on line 26 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote
el.appendChild(clonedTag);
});
}
}
this.captureRef.bind(item)(el as any);

Check failure on line 31 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Unsafe argument of type `any` assigned to a parameter of type `(HTMLElement & { associatedItem?: UI5Element | undefined; }) | null`
}}
>

{item.children.length > 0 && !item.unselectable &&
(<NavigationMenuItem
class="ui5-navigation-menu-item-root-parent"
Expand All @@ -31,8 +42,21 @@
target={item.target}
title={item.title}
tooltip={item._tooltip}
ref={this.captureRef.bind(item)}
></NavigationMenuItem>)
ref={(el: HTMLElement | null) => {
if (el && item.tag.length > 0) {
const existingTags = el.querySelectorAll('[slot="endContent"]');

Check failure on line 47 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote
if (existingTags.length === 0) {
item.tag.forEach((tagEl) => {

Check failure on line 49 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Unexpected parentheses around single function argument
const clonedTag = tagEl.cloneNode(true) as HTMLElement;
clonedTag.slot = 'endContent';

Check failure on line 51 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote
el.appendChild(clonedTag);
});
}
}
this.captureRef.bind(item)(el as any);

Check failure on line 56 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Unsafe argument of type `any` assigned to a parameter of type `(HTMLElement & { associatedItem?: UI5Element | undefined; }) | null`
}}
>
</NavigationMenuItem>)
}

{(item as any).items?.map(renderMenuItem)}
Expand Down Expand Up @@ -79,7 +103,19 @@
selected={this._popoverContents.item.selected}
unselectable={this._popoverContents.item.unselectable}
onui5-click={this.handlePopupItemClick}
ref={this.captureRef.bind(this._popoverContents.item)}
ref={(el: HTMLElement | null) => {
if (el && this._popoverContents.item.tag.length > 0) {
const existingTags = Array.from(el.children).filter(child => child.getAttribute('slot') === 'tag');

Check failure on line 108 in packages/fiori/src/SideNavigationPopoverTemplate.tsx

View workflow job for this annotation

GitHub Actions / check

Strings must use doublequote
if (existingTags.length === 0) {
this._popoverContents.item.tag.forEach((tagEl) => {
const clonedTag = tagEl.cloneNode(true) as HTMLElement;
clonedTag.slot = 'tag';
el.appendChild(clonedTag);
});
}
}
this.captureRef.bind(this._popoverContents.item)(el as SideNavigationItem | null);
}}
>
{this._popoverContents.subItems.map(item =>
<SideNavigationSubItem
Expand All @@ -93,8 +129,21 @@
selected={item.selected}
unselectable={item.unselectable}
onui5-click={this.handlePopupItemClick}
ref={this.captureRef.bind(item)}
/>
ref={(el: HTMLElement | null) => {
if (el && item.tag.length > 0) {
const existingTags = Array.from(el.children).filter(child => child.getAttribute('slot') === 'tag');
if (existingTags.length === 0) {
item.tag.forEach((tagEl) => {
const clonedTag = tagEl.cloneNode(true) as HTMLElement;
clonedTag.slot = 'tag';
el.appendChild(clonedTag);
});
}
}
this.captureRef.bind(item)(el as SideNavigationSubItem | null);
}}
>
</SideNavigationSubItem>
)}
</SideNavigationItem>
</SideNavigation>
Expand Down
4 changes: 4 additions & 0 deletions packages/fiori/src/SideNavigationSelectableItemBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ class SideNavigationSelectableItemBase extends SideNavigationItemBase {
return this.selected;
}

get _tagId() {
return `${this._id}-tag`;
}

_onkeydown(e: KeyboardEvent) {
const isRTL = this.effectiveDir === "rtl";

Expand Down
21 changes: 21 additions & 0 deletions packages/fiori/src/SideNavigationSubItem.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import jsxRender from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import slot from "@ui5/webcomponents-base/dist/decorators/slot-strict.js";
import type { Slot } from "@ui5/webcomponents-base/dist/UI5Element.js";
import SideNavigationSelectableItemBase from "./SideNavigationSelectableItemBase.js";
import SideNavigationSubItemTemplate from "./SideNavigationSubItemTemplate.js";
import "@ui5/webcomponents/dist/Tag.js";

// Styles
import SideNavigationSubItemCss from "./generated/themes/SideNavigationSubItem.css.js";
Expand Down Expand Up @@ -30,6 +33,24 @@ import SideNavigationSubItemCss from "./generated/themes/SideNavigationSubItem.c
styles: SideNavigationSubItemCss,
})
class SideNavigationSubItem extends SideNavigationSelectableItemBase {
/**
* Defines the tag to be displayed.
* Only `ui5-tag` component should be used.
*
* @public
* @since 2.7.0
*/
@slot({ type: HTMLElement })
tag!: Slot<HTMLElement>;

get hasTag() {
return !!this.tag.length;
}

get _describedBy() {
return this.hasTag ? this._tagId : undefined;
}

_onkeydown(e: KeyboardEvent) {
super._onkeydown(e);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/fiori/src/SideNavigationSubItemTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ export default function SideNavigationSubItemTemplate(this: SideNavigationSubIte
href={this._href}
target={this._target}
aria-haspopup={this._ariaHasPopup}
aria-describedby={this._describedBy}
>
{this.icon &&
<Icon class="ui5-sn-item-icon" name={this.icon}/>
}
<div class="ui5-sn-item-text">{this.text}</div>
{this.hasTag &&
<slot name="tag" id={this._tagId} class="ui5-sn-item-tag-slot"></slot>
}
{this.isExternalLink &&
<Icon class="ui5-sn-item-external-link-icon"
name={arrowRight}
Expand Down
35 changes: 35 additions & 0 deletions packages/fiori/src/themes/SideNavigationItemBase.css
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,41 @@ and there is an additional border that appears on hover. */
padding-inline-end: 0.375rem;
}

.ui5-sn-item-tag-slot {
padding-inline-start: 0.5rem;
padding-inline-end: 0.375rem;
display: inline-flex;
align-items: center;
}

.ui5-sn-item-tag-slot:has(+ .ui5-sn-item-toggle-icon),
.ui5-sn-item-tag-slot:has(+ .ui5-sn-item-external-link-icon) {
padding-inline-end: 0;
}

.ui5-sn-item-tag-slot + .ui5-sn-item-toggle-icon,
.ui5-sn-item-tag-slot + .ui5-sn-item-external-link-icon {
margin-inline-start: 0.375rem;
}

:host([side-nav-collapsed]) .ui5-sn-item-tag-slot {
display: none;
}

:host([side-nav-collapsed]) .ui5-sn-item:not(.ui5-sn-item-active):not(.ui5-sn-item-no-hover-effect):not(.ui5-sn-item-disabled):hover .ui5-sn-item-tag-slot,
:host([side-nav-collapsed]) .ui5-sn-item:not(.ui5-sn-item-active):not(.ui5-sn-item-no-hover-effect):focus .ui5-sn-item-tag-slot {
display: inline-flex;
max-width: 4rem;
}

:host([in-popover]) .ui5-sn-item-tag-slot {
display: inline-flex;
}

.ui5-sn-item-tag-slot::slotted([ui5-tag]) {
max-width: 4rem;
}

:host([side-nav-collapsed]) .ui5-sn-item-with-expander .ui5-sn-item-icon::after {
display: var(--_ui5_side_navigation_triangle_display);
content: "";
Expand Down
Loading
Loading