diff --git a/packages/fiori/src/SideNavigationItem.ts b/packages/fiori/src/SideNavigationItem.ts index bf2699ad4583..01faae9255e5 100644 --- a/packages/fiori/src/SideNavigationItem.ts +++ b/packages/fiori/src/SideNavigationItem.ts @@ -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"; @@ -81,6 +82,16 @@ class SideNavigationItem extends SideNavigationSelectableItemBase { @slot({ type: HTMLElement, invalidateOnChildChange: true, "default": true }) items!: DefaultSlot; + /** + * Defines the tag to be displayed. + * Only `ui5-tag` component should be used. + * + * @public + * @since 2.7.0 + */ + @slot({ type: HTMLElement }) + tag!: Slot; + @i18n("@ui5/webcomponents-fiori") static i18nBundle: I18nBundle; @@ -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() { diff --git a/packages/fiori/src/SideNavigationItemTemplate.tsx b/packages/fiori/src/SideNavigationItemTemplate.tsx index 30ef50c8c6aa..d348bfb54af6 100644 --- a/packages/fiori/src/SideNavigationItemTemplate.tsx +++ b/packages/fiori/src/SideNavigationItemTemplate.tsx @@ -52,6 +52,9 @@ function ItemTemplate(this: SideNavigationItem) { this.icon && } {this.text} + {this.hasTag && + + } {this.sideNavCollapsed ? !!this.items.length && { + if (el && item.tag.length > 0) { + const existingTags = Array.from(el.children).filter(child => child.getAttribute('slot') === 'endContent'); + if (existingTags.length === 0) { + item.tag.forEach((tagEl) => { + const clonedTag = tagEl.cloneNode(true) as HTMLElement; + clonedTag.slot = 'endContent'; + el.appendChild(clonedTag); + }); + } + } + this.captureRef.bind(item)(el as any); + }} > - {item.children.length > 0 && !item.unselectable && () + ref={(el: HTMLElement | null) => { + if (el && item.tag.length > 0) { + const existingTags = el.querySelectorAll('[slot="endContent"]'); + if (existingTags.length === 0) { + item.tag.forEach((tagEl) => { + const clonedTag = tagEl.cloneNode(true) as HTMLElement; + clonedTag.slot = 'endContent'; + el.appendChild(clonedTag); + }); + } + } + this.captureRef.bind(item)(el as any); + }} + > + ) } {(item as any).items?.map(renderMenuItem)} @@ -79,7 +103,19 @@ export default function SideNavigationTemplate(this: SideNavigation) { 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'); + 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 => + 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); + }} + > + )} diff --git a/packages/fiori/src/SideNavigationSelectableItemBase.ts b/packages/fiori/src/SideNavigationSelectableItemBase.ts index 318af80f4ba6..68138d81cbbe 100644 --- a/packages/fiori/src/SideNavigationSelectableItemBase.ts +++ b/packages/fiori/src/SideNavigationSelectableItemBase.ts @@ -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"; diff --git a/packages/fiori/src/SideNavigationSubItem.ts b/packages/fiori/src/SideNavigationSubItem.ts index 6fabffe14dbf..32931d34e01a 100644 --- a/packages/fiori/src/SideNavigationSubItem.ts +++ b/packages/fiori/src/SideNavigationSubItem.ts @@ -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"; @@ -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; + + get hasTag() { + return !!this.tag.length; + } + + get _describedBy() { + return this.hasTag ? this._tagId : undefined; + } + _onkeydown(e: KeyboardEvent) { super._onkeydown(e); } diff --git a/packages/fiori/src/SideNavigationSubItemTemplate.tsx b/packages/fiori/src/SideNavigationSubItemTemplate.tsx index 0d7727ef5a34..72646ca41b78 100644 --- a/packages/fiori/src/SideNavigationSubItemTemplate.tsx +++ b/packages/fiori/src/SideNavigationSubItemTemplate.tsx @@ -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 && } {this.text} + {this.hasTag && + + } {this.isExternalLink && + + + + Side Navigation - Indication Tags PoC + + + + + + + + + Side Navigation Indication Tags - PoC + + + + + + + + + + + New + + + + + + New + + + Alpha + + + + + + + + RC + + + Preview + + + + + Deprecated + + + + + + New + + + + + Toggle Collapsed + + + + + + + + + + + + Beta + + + + New + + + + Canary + + + Alpha + + + Beta + + + + + + + Dev + + + + Beta + + + + Alpha + + + + New + + + + Experimental + + + + Preview + + + + Sunset + + + + + + New + + + + + Toggle Expanded + + + + + + + + + + + + Beta Version + + + + Experimental Phase + + + + Alpha Release + + New Feature + + + Preview Build + + + + + Beta Testing + + + + + + + New Content + + + + + Toggle Collapsed + + + + + + + +