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
109 changes: 93 additions & 16 deletions packages/main/cypress/specs/RatingIndicator.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,116 @@
import RatingIndicator from "../../src/RatingIndicator.js";
import { RATING_INDICATOR_ARIA_DESCRIPTION } from "../../src/generated/i18n/i18n-defaults.js";
import "@ui5/webcomponents-icons/dist/heart.js";
import "@ui5/webcomponents-icons/dist/heart-2.js";
import "@ui5/webcomponents-icons/dist/thumb-up.js";
import "@ui5/webcomponents-icons/dist/thumb-down.js";

describe("RatingIndicator", () => {
describe("Half Icon appearance", () => {
it("Half icon should be filled when rating indicator is disabled", () => {
const attributeValue = "favorite";
describe("Custom Icons", () => {
it("should render default icons when no custom icons are specified", () => {
cy.mount(<RatingIndicator value={3}></RatingIndicator>);

cy.mount(<RatingIndicator value={2.5} disabled={true}></RatingIndicator>);
cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-sel [ui5-icon]")
.first()
.should("have.attr", "name", "favorite");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-unsel [ui5-icon]")
.first()
.should("have.attr", "name", "unfavorite");
});

it("should render custom icons for selected and unselected states", () => {
cy.mount(<RatingIndicator value={3} iconSelected="heart" iconUnselected="heart-2"></RatingIndicator>);

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-sel [ui5-icon]")
.first()
.should("have.attr", "name", "heart");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-unsel [ui5-icon]")
.first()
.should("have.attr", "name", "heart-2");
});

it("should render custom icon with default unselected icon when only iconSelected is specified", () => {
cy.mount(<RatingIndicator value={2} iconSelected="thumb-up"></RatingIndicator>);

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-sel [ui5-icon]")
.first()
.should("have.attr", "name", "thumb-up");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-unsel [ui5-icon]")
.first()
.should("have.attr", "name", "unfavorite");
});

it("should render custom unselected icon with default selected icon when only iconUnselected is specified", () => {
cy.mount(<RatingIndicator value={2} iconUnselected="thumb-down"></RatingIndicator>);

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-sel [ui5-icon]")
.first()
.should("have.attr", "name", "favorite");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half [ui5-icon]")
.should("have.attr", "name", attributeValue);
.find(".ui5-rating-indicator-item-unsel [ui5-icon]")
.first()
.should("have.attr", "name", "thumb-down");
});

it("Half icon should be filled when rating indicator is readonly", () => {
const attributeValue = "favorite";
it("should render custom icons in half-star state", () => {
cy.mount(<RatingIndicator value={2.5} iconSelected="heart" iconUnselected="heart-2"></RatingIndicator>);

cy.mount(<RatingIndicator value={2.5} readonly={true}></RatingIndicator>);
cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-left [ui5-icon]")
.should("have.attr", "name", "heart");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half [ui5-icon]")
.should("have.attr", "name", attributeValue);
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-right [ui5-icon]")
.should("have.attr", "name", "heart-2");
});

it("Half icon should be border only when rating indicator is regular", () => {
const attributeValue = "unfavorite";
it("should render custom icon (filled) in half-star state when readonly", () => {
cy.mount(<RatingIndicator value={2.5} iconSelected="heart" iconUnselected="heart-2" readonly></RatingIndicator>);

cy.mount(<RatingIndicator value={2.5}></RatingIndicator>);
cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-left [ui5-icon]")
.should("have.attr", "name", "heart");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-right [ui5-icon]")
.should("have.attr", "name", "heart");
});

it("should render custom icon (filled) in half-star state when disabled", () => {
cy.mount(<RatingIndicator value={2.5} iconSelected="heart" iconUnselected="heart-2" disabled></RatingIndicator>);

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-left [ui5-icon]")
.should("have.attr", "name", "heart");

cy.get("[ui5-rating-indicator]")
.shadow()
.find(".ui5-rating-indicator-item-half [ui5-icon]")
.should("have.attr", "name", attributeValue);
.find(".ui5-rating-indicator-item-half .ui5-rating-indicator-half-icon-right [ui5-icon]")
.should("have.attr", "name", "heart");
});
});

Expand Down
27 changes: 27 additions & 0 deletions packages/main/src/RatingIndicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,25 @@ class RatingIndicator extends UI5Element {
@property()
tooltip?: string;

/**
* Defines the icon to be displayed for the selected (filled) rating symbol.
*
* @default "favorite"
* @public
* @since 2.20
*/
@property()
iconSelected?: string;

/**
* Defines the icon to be displayed for the unselected (empty) rating symbol.
* @default "unfavorite"
* @public
* @since 2.20
*/
@property()
iconUnselected?: string;

/**
* @private
*/
Expand Down Expand Up @@ -341,6 +360,14 @@ class RatingIndicator extends UI5Element {
get ariaReadonly() {
return this.readonly ? "true" : undefined;
}

get effectiveIconSelected() {
return this.iconSelected || "favorite";
}

get effectiveIconUnselected() {
return this.iconUnselected || "unfavorite";
}
}

RatingIndicator.define();
Expand Down
20 changes: 10 additions & 10 deletions packages/main/src/RatingIndicatorTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type RatingIndicator from "./RatingIndicator.js";
import type { Star } from "./RatingIndicator.js";
import Icon from "./Icon.js";
import favorite from "@ui5/webcomponents-icons/dist/favorite.js";
import unfavorite from "@ui5/webcomponents-icons/dist/unfavorite.js";

export default function RatingIndicatorTemplate(this: RatingIndicator) {
return (
Expand Down Expand Up @@ -37,38 +35,40 @@ function starLi(this: RatingIndicator, star: Star) {
if (star.selected) {
return (
<li data-ui5-value={star.index} class="ui5-rating-indicator-item ui5-rating-indicator-item-sel">
<Icon data-ui5-value={star.index} name={favorite} />
<Icon data-ui5-value={star.index} name={this.effectiveIconSelected} />
</li>
);
} if (star.halfStar) {
return (
<li class="ui5-rating-indicator-item ui5-rating-indicator-item-half">
<Icon data-ui5-value={star.index} name={halfStarIconName.call(this)} />
<div class="ui5-rating-indicator-half-icon-wrapper">
<Icon data-ui5-value={star.index} name={favorite} class="ui5-rating-indicator-half-icon" />
<div class="ui5-rating-indicator-half-icon-wrapper ui5-rating-indicator-half-icon-left">
<Icon data-ui5-value={star.index} name={this.effectiveIconSelected} />
</div>
<div class="ui5-rating-indicator-half-icon-wrapper ui5-rating-indicator-half-icon-right">
<Icon data-ui5-value={star.index} name={halfStarIconName.call(this)} />
</div>
</li>
);
} if (this.readonly) {
return (
<li class="ui5-rating-indicator-item ui5-rating-indicator-item-unsel">
<Icon data-ui5-value={star.index} name={favorite} />
<Icon data-ui5-value={star.index} name={this.effectiveIconSelected} />
</li>
);
} if (this.disabled) {
return (
<li class="ui5-rating-indicator-item ui5-rating-indicator-item-unsel">
<Icon data-ui5-value={star.index} name={favorite} />
<Icon data-ui5-value={star.index} name={this.effectiveIconSelected} />
</li>
);
}
return (
<li data-ui5-value={star.index} class="ui5-rating-indicator-item ui5-rating-indicator-item-unsel">
<Icon data-ui5-value={star.index} name={unfavorite}/>
<Icon data-ui5-value={star.index} name={this.effectiveIconUnselected}/>
</li>
);
}

function halfStarIconName(this: RatingIndicator) {
return this.disabled || this.readonly ? favorite : unfavorite;
return this.disabled || this.readonly ? this.effectiveIconSelected : this.effectiveIconUnselected;
}
38 changes: 26 additions & 12 deletions packages/main/src/themes/RatingIndicator.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,35 @@
}

.ui5-rating-indicator-item.ui5-rating-indicator-item-half {
color: var(--sapContent_UnratedColor);
display: flex;
flex-direction: row;
}

.ui5-rating-indicator-half-icon-wrapper {
width: 50%;
height: 100%;
overflow: hidden;
position: relative;
}

.ui5-rating-indicator-item [ui5-icon].ui5-rating-indicator-half-icon {
.ui5-rating-indicator-half-icon-wrapper [ui5-icon] {
position: absolute;
inset-inline-start: 50%;
width: var(--_ui5_rating_indicator_item_width);
height: var(--_ui5_rating_indicator_item_height);
}

.ui5-rating-indicator-half-icon-left {
color: var(--sapContent_RatedColor);
}

.ui5-rating-indicator-half-icon-wrapper {
width: 100%;
height: 100%;
position: absolute;
inset-inline-start: -50%;
top: 0;
z-index: 32;
overflow: hidden;
}
.ui5-rating-indicator-half-icon-left [ui5-icon] {
inset-inline-start: 0;
}

.ui5-rating-indicator-half-icon-right {
color: var(--sapContent_UnratedColor);
}

.ui5-rating-indicator-half-icon-right [ui5-icon] {
inset-inline-end: 0;
}
26 changes: 26 additions & 0 deletions packages/main/test/pages/RatingIndicator.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,32 @@ <h3>sizes</h3>
<br>

</section>

<h3>Custom Icons - Hearts</h3>
<ui5-rating-indicator id="rating-hearts" value="3" icon-selected="heart" icon-unselected="heart-2"></ui5-rating-indicator>
<br>
<br>

<h3>Custom Icons - Thumbs Up</h3>
<ui5-rating-indicator id="rating-thumbs" value="2.5" icon-selected="thumb-up" icon-unselected="border"></ui5-rating-indicator>
<br>
<br>

<h3>Custom Icons - Hearts (readonly)</h3>
<ui5-rating-indicator id="rating-hearts-readonly" value="2.5" icon-selected="heart" icon-unselected="heart-2" readonly></ui5-rating-indicator>
<br>
<br>

<h3>Custom Icons - Hearts (disabled)</h3>
<ui5-rating-indicator id="rating-hearts-disabled" value="3" icon-selected="heart" icon-unselected="heart-2" disabled></ui5-rating-indicator>
<br>
<br>

<h3>Custom Icons - Only selected icon (circles)</h3>
<ui5-rating-indicator id="rating-circle" value="2" icon-selected="circle-task-2"></ui5-rating-indicator>
<br>
<br>

<script>
var changeCount = 0;
var ratingIndicator4 = document.getElementById("rating-indicator4");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ slug: ../RatingIndicator

import Basic from "../../_samples/main/RatingIndicator/Basic/Basic.md";
import Sizes from "../../_samples/main/RatingIndicator/Sizes/Sizes.md";
import CustomIcons from "../../_samples/main/RatingIndicator/CustomIcons/CustomIcons.md";

<%COMPONENT_OVERVIEW%>

Expand All @@ -18,3 +19,8 @@ import Sizes from "../../_samples/main/RatingIndicator/Sizes/Sizes.md";
The RatingIndicator supports several sizes of the Icons (S, M and L).

<Sizes />

### Custom Icons
The RatingIndicator supports custom icons for both selected and unselected states using the `icon-selected` and `icon-unselected` properties.

<CustomIcons />
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import "@ui5/webcomponents/dist/RatingIndicator.js";
import "@ui5/webcomponents/dist/RatingIndicator.js";
import "@ui5/webcomponents-icons/dist/favorite.js";
import "@ui5/webcomponents-icons/dist/unfavorite.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import html from '!!raw-loader!./sample.html';
import js from '!!raw-loader!./main.js';

<Editor html={html} js={js} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "@ui5/webcomponents/dist/RatingIndicator.js";
import "@ui5/webcomponents-icons/dist/heart.js";
import "@ui5/webcomponents-icons/dist/heart-2.js";
import "@ui5/webcomponents-icons/dist/thumb-up.js";
import "@ui5/webcomponents-icons/dist/border.js";
import "@ui5/webcomponents-icons/dist/circle-task-2.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- playground-hide -->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample</title>
</head>

<body style="background-color: var(--sapBackgroundColor)">
<!-- playground-hide-end -->
<ui5-rating-indicator value="3" icon-selected="heart" icon-unselected="heart-2"></ui5-rating-indicator></br>
<ui5-rating-indicator value="4" icon-selected="thumb-up" icon-unselected="border"></ui5-rating-indicator></br>
<ui5-rating-indicator value="2.5" icon-selected="circle-task-2" icon-unselected="border" readonly></ui5-rating-indicator>
<!-- playground-hide -->
<script type="module" src="main.js"></script>
</body>

</html>
<!-- playground-hide-end -->
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import "@ui5/webcomponents/dist/RatingIndicator.js";
import "@ui5/webcomponents/dist/RatingIndicator.js";
import "@ui5/webcomponents-icons/dist/favorite.js";
import "@ui5/webcomponents-icons/dist/unfavorite.js";
Loading