diff options
Diffstat (limited to 'toolkit/content/widgets/moz-five-star')
3 files changed, 168 insertions, 0 deletions
diff --git a/toolkit/content/widgets/moz-five-star/moz-five-star.css b/toolkit/content/widgets/moz-five-star/moz-five-star.css new file mode 100644 index 0000000000..44d2a3e252 --- /dev/null +++ b/toolkit/content/widgets/moz-five-star/moz-five-star.css @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +:host { + display: flex; + justify-content: space-between; +} + +:host([hidden]) { + display: none; +} + +.stars { + --rating-star-size: 1em; + --rating-star-spacing: 0.3ch; + + display: inline-grid; + grid-template-columns: repeat(5, var(--rating-star-size)); + grid-column-gap: var(--rating-star-spacing); + align-content: center; +} + +.rating-star { + display: inline-block; + width: var(--rating-star-size); + height: var(--rating-star-size); + background-image: url("chrome://global/skin/icons/rating-star.svg#empty"); + background-position: center; + background-repeat: no-repeat; + background-size: 100%; + + fill: var(--icon-color); + -moz-context-properties: fill; +} + +.rating-star[fill="half"] { + background-image: url("chrome://global/skin/icons/rating-star.svg#half"); +} +.rating-star[fill="full"] { + background-image: url("chrome://global/skin/icons/rating-star.svg#full"); +} + +.rating-star[fill="half"]:dir(rtl) { + transform: scaleX(-1); +} diff --git a/toolkit/content/widgets/moz-five-star/moz-five-star.mjs b/toolkit/content/widgets/moz-five-star/moz-five-star.mjs new file mode 100644 index 0000000000..e95c74e0ed --- /dev/null +++ b/toolkit/content/widgets/moz-five-star/moz-five-star.mjs @@ -0,0 +1,71 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { ifDefined, html } from "../vendor/lit.all.mjs"; +import { MozLitElement } from "../lit-utils.mjs"; + +window.MozXULElement?.insertFTLIfNeeded("toolkit/global/mozFiveStar.ftl"); + +/** + * The visual representation is five stars, each of them either empty, + * half-filled or full. The fill state is derived from the rating, + * rounded to the nearest half. + * + * @tagname moz-five-star + * @property {number} rating - The rating out of 5. + * @property {string} title - The title text. + */ +export default class MozFiveStar extends MozLitElement { + static properties = { + rating: { type: Number, reflect: true }, + title: { type: String }, + }; + + static get queries() { + return { + starEls: { all: ".rating-star" }, + starsWrapperEl: ".stars", + }; + } + + getStarsFill() { + let starFill = []; + let roundedRating = Math.round(this.rating * 2) / 2; + for (let i = 1; i <= 5; i++) { + if (i <= roundedRating) { + starFill.push("full"); + } else if (i - roundedRating === 0.5) { + starFill.push("half"); + } else { + starFill.push("empty"); + } + } + return starFill; + } + + render() { + let starFill = this.getStarsFill(); + return html` + <link + rel="stylesheet" + href="chrome://global/content/elements/moz-five-star.css" + /> + <div + class="stars" + role="img" + data-l10n-id=${ifDefined( + this.title ? undefined : "moz-five-star-rating" + )} + data-l10n-args=${ifDefined( + this.title ? undefined : JSON.stringify({ rating: this.rating ?? 0 }) + )} + > + ${starFill.map( + fill => html`<span class="rating-star" fill="${fill}"></span>` + )} + </div> + `; + } +} +customElements.define("moz-five-star", MozFiveStar); diff --git a/toolkit/content/widgets/moz-five-star/moz-five-star.stories.mjs b/toolkit/content/widgets/moz-five-star/moz-five-star.stories.mjs new file mode 100644 index 0000000000..cbbbe9da26 --- /dev/null +++ b/toolkit/content/widgets/moz-five-star/moz-five-star.stories.mjs @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { html, ifDefined } from "../vendor/lit.all.mjs"; +// eslint-disable-next-line import/no-unassigned-import +import "./moz-five-star.mjs"; + +export default { + title: "UI Widgets/Five Star", + component: "moz-five-star", + parameters: { + status: "in-development", + fluent: ` +moz-five-star-title = + .title = This is the title +moz-five-star-aria-label = + .aria-label = This is the aria-label + `, + }, +}; + +const Template = ({ rating, ariaLabel, l10nId }) => html` + <div style="max-width: 400px"> + <moz-five-star + rating=${rating} + aria-label=${ifDefined(ariaLabel)} + data-l10n-id=${ifDefined(l10nId)} + data-l10n-attrs="aria-label, title" + > + </moz-five-star> + </div> +`; + +export const FiveStar = Template.bind({}); +FiveStar.args = { + rating: 5.0, + l10nId: "moz-five-star-aria-label", +}; + +export const WithTitle = Template.bind({}); +WithTitle.args = { + ...FiveStar.args, + rating: 0, + l10nId: "moz-five-star-title", +}; + +export const Default = Template.bind({}); +Default.args = { + rating: 3.33, +}; |