import { css, CSSResultArray, html, LitElement, TemplateResult } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
/**
* @cssprop --filled-star-color - The color of the filled stars.
* @cssprop --empty-star-color - The color of the empty stars.
*/
@customElement('z-reviews.stars')
export class ReviewsStarsComponent extends LitElement {
/// Private variables ///
/// Protected variables ///
@state() protected _filledStarCount = 0;
/// Public variables ///
@property({ type: Number }) public rating: number | undefined;
@property({ type: Number, attribute: 'out-of' }) public outOf: number | undefined;
@property({ type: Number }) public stars: number = 5;
@property({ type: Boolean, attribute: 'allow-fractional' }) public allowFractional = false;
/// constructor & lifecycle ///
override connectedCallback(): void {
super.connectedCallback();
this.validateProperties();
}
override updated(changedProperties: Map): void {
super.updated(changedProperties);
this._filledStarCount = this.calculateFilledStarCount();
// this.requestUpdate();
}
/// Public methods ///
/// Protected methods ///
protected override render(): TemplateResult {
return html`
${this.renderStars()}
${this.renderStars()}
`;
}
protected renderStars(): TemplateResult {
const stars: TemplateResult[] = [];
for (let i = 0; i < this.stars; i++) {
stars.push(this.renderStar());
}
return html`${stars}`;
}
protected renderStar(): TemplateResult {
return html`
`;
}
/// Private methods ///
/**
* Validate the properties for the rules of availability.
*
* @throws {Error} If the properties are not valid.
*/
private validateProperties(): void {
console.log(this.rating, this.stars, this.outOf, this.allowFractional);
if (!this.rating) {
throw new Error('Rating is required.');
}
if (!this.outOf) {
throw new Error('Out of is required when rating is used.');
}
if (this.stars < 1) {
throw new Error('Stars cannot be less than 1.');
}
if (this.rating! > this.outOf) {
throw new Error('Rating cannot be greater than out of.');
}
}
private calculateFilledStarCount(): number {
if (this.allowFractional) {
return (this.rating! / this.outOf!) * this.stars;
}
return Math.round((this.rating! / this.outOf!) * this.stars);
}
/// Statics ///
static override styles: CSSResultArray = [
css`
:host {
display: flex;
position: relative;
}
.icon {
vertical-align: -0.125em;
flex: 0 0 1em;
height: 1em;
width: 1em;
fill: currentColor;
}
.stars {
display: flex;
color: var(--empty-star-color, #e4e5e9);
}
.stars--filled {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
opacity: 1;
right: calc(100% - var(--_filled-star-width));
color: var(--filled-star-color, #f7b731);
}
`,
];
}