@trimble-oss/moduswebcomponents
Version:
Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust
316 lines (315 loc) • 12.5 kB
JavaScript
import { h, Host, } from "@stencil/core";
import { handleShadowDOMStyles } from "../base-component";
import { generateRandomId, inheritAriaAttributes } from "../utils";
import { convertPropsToClasses, getIndexedRatingItemClass, } from "./modus-wc-rating.tailwind";
/**
* A rating component that allows users to choose a rating from predefined options
*/
export class ModusWcRating {
constructor() {
this.inheritedAttributes = {};
this.VARIANTS_WITHOUT_HALF_SUPPORT = [
'smiley',
'thumb',
];
/** Whether to allow half-ratings. Only applies to star and heart variants. */
this.allowHalf = false;
/** The number of rating items to display */
this.count = 5;
/** Custom CSS class to apply */
this.customClass = '';
/** Whether the rating component is disabled */
this.disabled = false;
/** Function to provide aria-label text for a given rating-item index */
this.getAriaLabelText = (ratingValue) => `Rating item ${ratingValue}`;
/** The size of the rating component */
this.size = 'md';
/** The variant of the rating scale */
this.variant = 'smiley';
/** The current value of the rating */
this.value = 0;
this.uniqueRatingGroupName = `modus-wc-rating-group-${generateRandomId(4)}`;
}
componentWillLoad() {
// Auto-inject CSS if component is used inside user's shadow DOM
handleShadowDOMStyles(this.el);
if (!this.el.ariaLabel) {
this.el.ariaLabel = 'Rating scale component';
}
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
getClasses() {
const ratingClassList = ['modus-wc-rating'];
const ratingItemClassList = ['modus-wc-rating-item', 'modus-wc-mask'];
const { ratingPropClasses, ratingItemPropClasses } = convertPropsToClasses({
allowHalf: this.allowHalf,
size: this.size,
variant: this.variant,
});
// The order CSS classes are added matters to CSS specificity
if (ratingPropClasses)
ratingClassList.push(ratingPropClasses);
if (this.customClass)
ratingClassList.push(this.customClass);
if (ratingItemPropClasses)
ratingItemClassList.push(ratingItemPropClasses);
return {
ratingClasses: ratingClassList.join(' '),
ratingItemClasses: ratingItemClassList.join(' '),
};
}
/**
* Gets the total number of rating items to render based on variant and settings
*/
getTotalRatingItems() {
if (this.supportsHalfRatings()) {
return this.count * 2;
}
if (this.variant === 'thumb') {
return 2;
}
if (this.variant === 'smiley') {
return Math.max(2, Math.min(5, this.count));
}
return this.count;
}
getValueForIndex(index) {
return this.supportsHalfRatings() ? (index + 1) * 0.5 : index + 1;
}
handleChange(newValue) {
this.value = newValue;
this.ratingChange.emit({ newRating: newValue });
}
supportsHalfRatings() {
return (this.allowHalf &&
!this.VARIANTS_WITHOUT_HALF_SUPPORT.includes(this.variant));
}
renderRatingItems(ratingItemClasses) {
return Array.from({ length: this.getTotalRatingItems() }, (_, index) => {
const ratingValue = this.getValueForIndex(index);
const itemClass = getIndexedRatingItemClass(index, ratingItemClasses, this.supportsHalfRatings(), this.variant, this.count);
return (h("input", { "aria-label": this.getAriaLabelText(ratingValue), "aria-checked": this.value === ratingValue ? 'true' : 'false', checked: this.value === ratingValue, class: itemClass, disabled: this.disabled, key: index, name: this.uniqueRatingGroupName, onChange: () => this.handleChange(ratingValue), type: "radio", value: String(ratingValue) }));
});
}
/**
* Render the zero/reset option
*/
renderZeroOption() {
return (h("input", { "aria-label": this.getAriaLabelText(0), "aria-checked": this.value <= 0 ? 'true' : 'false', checked: this.value <= 0, class: "modus-wc-rating-hidden", disabled: this.disabled, name: this.uniqueRatingGroupName, onChange: () => this.handleChange(0), type: "radio", value: "0" }));
}
render() {
const { ratingClasses, ratingItemClasses } = this.getClasses();
return (h(Host, { key: '40e1d043c78a6a330d94c514e7cc75f309944406', class: "modus-wc-rating-container" }, h("div", Object.assign({ key: '674d4296dfee39a4d975884aef497595f715f6a9', class: ratingClasses, role: "radiogroup" }, this.inheritedAttributes), this.renderZeroOption(), this.renderRatingItems(ratingItemClasses))));
}
static get is() { return "modus-wc-rating"; }
static get originalStyleUrls() {
return {
"$": ["modus-wc-rating.scss"]
};
}
static get styleUrls() {
return {
"$": ["modus-wc-rating.css"]
};
}
static get properties() {
return {
"allowHalf": {
"type": "boolean",
"attribute": "allow-half",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Whether to allow half-ratings. Only applies to star and heart variants."
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
},
"count": {
"type": "number",
"attribute": "count",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The number of rating items to display"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "5"
},
"customClass": {
"type": "string",
"attribute": "custom-class",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Custom CSS class to apply"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "''"
},
"disabled": {
"type": "boolean",
"attribute": "disabled",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Whether the rating component is disabled"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "false"
},
"getAriaLabelText": {
"type": "unknown",
"attribute": "get-aria-label-text",
"mutable": false,
"complexType": {
"original": "(ratingValue: number) => string",
"resolved": "((ratingValue: number) => string) | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Function to provide aria-label text for a given rating-item index"
},
"getter": false,
"setter": false,
"defaultValue": "(ratingValue) =>\n `Rating item ${ratingValue}`"
},
"size": {
"type": "string",
"attribute": "size",
"mutable": false,
"complexType": {
"original": "ModusSize",
"resolved": "\"lg\" | \"md\" | \"sm\" | undefined",
"references": {
"ModusSize": {
"location": "import",
"path": "../types",
"id": "src/components/types.ts::ModusSize"
}
}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The size of the rating component"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "'md'"
},
"variant": {
"type": "string",
"attribute": "variant",
"mutable": false,
"complexType": {
"original": "ModusWcRatingVariant",
"resolved": "\"heart\" | \"smiley\" | \"star\" | \"thumb\"",
"references": {
"ModusWcRatingVariant": {
"location": "local",
"path": "/home/runner/work/modus-wc-2.0/modus-wc-2.0/src/components/modus-wc-rating/modus-wc-rating.tsx",
"id": "src/components/modus-wc-rating/modus-wc-rating.tsx::ModusWcRatingVariant"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The variant of the rating scale"
},
"getter": false,
"setter": false,
"reflect": false,
"defaultValue": "'smiley'"
},
"value": {
"type": "number",
"attribute": "value",
"mutable": true,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The current value of the rating"
},
"getter": false,
"setter": false,
"reflect": true,
"defaultValue": "0"
}
};
}
static get events() {
return [{
"method": "ratingChange",
"name": "ratingChange",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Event emitted when the rating changes"
},
"complexType": {
"original": "IRatingChange",
"resolved": "IRatingChange",
"references": {
"IRatingChange": {
"location": "local",
"path": "/home/runner/work/modus-wc-2.0/modus-wc-2.0/src/components/modus-wc-rating/modus-wc-rating.tsx",
"id": "src/components/modus-wc-rating/modus-wc-rating.tsx::IRatingChange"
}
}
}
}];
}
static get elementRef() { return "el"; }
}