Skip to content

feat(ui5-tree-item): image slot added #11106

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 3 commits into from
Apr 10, 2025
Merged
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
24 changes: 24 additions & 0 deletions packages/main/cypress/specs/Tree.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import Tree from "../../src/Tree.js";
import "../../src/TreeItem.js";
import TreeItem from "../../src/TreeItem.js";
import Icon from "../../src/Icon.js";
import bell from "@ui5/webcomponents-icons/dist/bell.js";

describe("Tree Tests", () => {
it("tests accessibility properties forwarded to the list", () => {
@@ -27,4 +30,25 @@ describe("Tree Tests", () => {
.and("have.attr", "accessible-description", "Description")
.and("have.attr", "accessible-description-ref", "lblDesc2");
});

it("Tests image slot", () => {
cy.mount(
<Tree>
<TreeItem id="image-slot-tree-item">
<Icon name={bell} slot="image" id="slotted-icon"></Icon>
</TreeItem>
</Tree>
);

cy.get("#image-slot-tree-item")
.shadow()
.find("slot[name='image']")
.should("exist")
.then($slot => {
const slotElement = $slot[0] as HTMLSlotElement;
const assignedNodes = slotElement.assignedNodes();
expect(assignedNodes.length).to.be.greaterThan(0);
cy.wrap(assignedNodes[0]).should("have.attr", "id", "slotted-icon");
});
});
});
23 changes: 23 additions & 0 deletions packages/main/src/TreeItemBase.ts
Original file line number Diff line number Diff line change
@@ -195,6 +195,12 @@ class TreeItemBase extends ListItem {
@property({ type: Boolean })
_fixed = false;

/**
* @private
*/
@property({ type: Boolean })
_hasImage = false;

/**
* Defines the items of the component.
*
@@ -211,11 +217,24 @@ class TreeItemBase extends ListItem {
})
items!: Array<TreeItemBase>;

/**
* **Note:** While the slot allows option for setting custom avatar, to match the
* design guidelines, please use the `ui5-avatar` with size XS.
*
* **Note:** If bigger `ui5-avatar` needs to be used, then the size of the
* `ui5-tree-item` should be customized in order to fit.
* @since 2.10.0
* @public
*/
@slot()
image!: Array<HTMLElement>;

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

onBeforeRendering() {
this.showToggleButton = this.requiresToggleButton;
this._hasImage = this.hasImage;
}

get classes(): ClassMap {
@@ -244,6 +263,10 @@ class TreeItemBase extends ListItem {
return this.level > 1;
}

get hasImage(): boolean {
return !!this.image.length;
}

get _toggleIconName() {
return this.expanded ? "navigation-down-arrow" : "navigation-right-arrow";
}
8 changes: 7 additions & 1 deletion packages/main/src/TreeItemBaseTemplate.tsx
Original file line number Diff line number Diff line change
@@ -54,7 +54,13 @@ function listItemPostContent(this: TreeItemBase) {
}

function listItemContent() { }
function imageBegin() { }
function imageBegin(this: TreeItemBase) {
if (this.hasImage) {
return <div class="ui5-tree-item-image">
<slot name="image"></slot>
</div>;
}
}
function iconBegin(this: TreeItemBase) {
return this.icon ? <Icon part="icon" name={this.icon} class="ui5-li-icon" /> : <></>;
}
25 changes: 16 additions & 9 deletions packages/main/src/themes/ListItem.css
Original file line number Diff line number Diff line change
@@ -67,6 +67,21 @@
object-fit: contain
}

::slotted([ui5-icon][slot="image"]){
color: var(--sapContent_NonInteractiveIconColor);
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
padding-inline-end: var(--_ui5_list_item_icon_padding-inline-end);
}

::slotted([ui5-avatar][slot="image"]) {
min-width: var(--_ui5_list_item_img_size);
min-height: var(--_ui5_list_item_img_size);
margin-top: var(--_ui5_list_item_img_top_margin);
margin-bottom: var(--_ui5_list_item_img_bottom_margin);
margin-inline-end: var(--_ui5_list_item_img_hn_margin);
}

:host([description]) .ui5-li-root {
padding: 1rem;
}
@@ -119,14 +134,6 @@
align-self: flex-end;
}

.ui5-li-image {
min-width: var(--_ui5_list_item_img_size);
min-height: var(--_ui5_list_item_img_size);
margin-top: var(--_ui5_list_item_img_top_margin);
margin-bottom: var(--_ui5_list_item_img_bottom_margin);
margin-inline-end: var(--_ui5_list_item_img_hn_margin);
}

.ui5-li-icon {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
@@ -197,4 +204,4 @@

:host([highlight="Information"]) .ui5-li-highlight {
background: var(--sapInformativeTextColor);
}
}
9 changes: 9 additions & 0 deletions packages/main/src/themes/TreeItem.css
Original file line number Diff line number Diff line change
@@ -46,6 +46,15 @@
background-color: var(--sapList_Hover_SelectionBackground);
}

:host([_has-image]) {
height: unset;
}

::slotted([ui5-avatar][slot="image"]) {
min-width: var(--_ui5_avatar_fontsize_XS);
min-height: var(--_ui5_avatar_fontsize_XS);
}

.ui5-li-tree-toggle-box {
min-width: var(--_ui5-tree-toggle-box-width);
min-height: var(--_ui5-tree-toggle-box-height);
36 changes: 8 additions & 28 deletions packages/main/test/pages/List.html
Original file line number Diff line number Diff line change
@@ -184,45 +184,25 @@ <h2>ui5-list</h2>
<br/><br/>

<ui5-list header-text="API: icon">
<ui5-li icon="navigation-right-arrow">Option 1</ui5-li>
<ui5-li icon="navigation-right-arrow">Option 1</ui5-li>
</ui5-list>

<br/><br/>
<hr />
<br/><br/>

<ui5-list header-text="API: image">
<ui5-li>Laptop HP
<ui5-list header-text="API: image slot">
<ui5-li>Avatar with src inside image slot
<ui5-avatar slot="image">
<img src="./img/HT-1000.jpg" alt="Woman image">
</ui5-avatar>
</ui5-li>
<ui5-li>laptop Lenovo
<ui5-avatar slot="image">
<img src="./img/HT-1010.jpg" alt="Woman image">
</ui5-avatar>
</ui5-li>
<ui5-li>IPhone 3
<ui5-avatar slot="image">
<img src="./img/HT-1022.jpg" alt="Woman image">
</ui5-avatar>
<ui5-li>Icon inside image slot
<ui5-icon slot="image" name="bell"> </ui5-icon>
</ui5-li>
</ui5-list>

<br/><br/>

<ui5-list header-text="API: image">
<ui5-li> Avatar inside image slot
<div slot="image">
<ui5-avatar shape="Square" initials="ABC" color-scheme="Accent2"></ui5-avatar>
</div>
</ui5-li>
<ui5-li> Avatar inside image slot
<div slot="image">
<ui5-avatar >
<img src="./img/woman_avatar_5.png" alt="Woman image">
</ui5-avatar>
</div>
<ui5-li>Icon and Avatar with initials inside image slot
<ui5-icon slot="image" name="bell"> </ui5-icon>
<ui5-avatar slot="image" initials="AB"></ui5-avatar>
</ui5-li>
</ui5-list>

17 changes: 17 additions & 0 deletions packages/main/test/pages/Tree.html
Original file line number Diff line number Diff line change
@@ -225,6 +225,23 @@ <h2>With accessible description</h2>
<ui5-tree-item text="Item 3"></ui5-tree-item>
</ui5-tree>

<br><br>

<h2>API: image slot</h2>
<ui5-label id="description">Tree items with image slot used</ui5-label>
<ui5-tree accessible-description-ref="description">
<ui5-tree-item text="Icon inside image slot">
<ui5-icon slot="image" name="bell"> </ui5-icon>
</ui5-tree-item>
<ui5-tree-item text="Avatar inside image slot">
<ui5-avatar slot="image" size="XS" initials="BL"> </ui5-avatar>
</ui5-tree-item>
<ui5-tree-item text="Avatar and Icon inside image slot">
<ui5-avatar slot="image" size="XS" initials="BL"> </ui5-avatar>
<ui5-icon slot="image" name="bell"> </ui5-icon>
</ui5-tree-item>
</ui5-tree>

<script>
const mouseOverInput = document.getElementById("mouseover-counter");
const mouseOutInput = document.getElementById("mouseout-counter");
4 changes: 3 additions & 1 deletion packages/website/docs/_samples/main/Tree/Basic/main.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import "@ui5/webcomponents/dist/Tree.js";
import "@ui5/webcomponents/dist/TreeItem.js";
import "@ui5/webcomponents/dist/TreeItem.js";
import "@ui5/webcomponents-icons/dist/paste.js";
import "@ui5/webcomponents-icons/dist/copy.js";