UNPKG

igniteui-webcomponents

Version:

Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.

298 lines 11.4 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var IgcRatingComponent_1; import { LitElement, html, nothing } from 'lit'; import { property, query, queryAssignedElements, queryAssignedNodes, state, } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; import { themes } from '../../theming/theming-decorator.js'; import { addKeybindings, arrowDown, arrowLeft, arrowRight, arrowUp, endKey, homeKey, } from '../common/controllers/key-bindings.js'; import { watch } from '../common/decorators/watch.js'; import { registerComponent } from '../common/definitions/register.js'; import { EventEmitterMixin } from '../common/mixins/event-emitter.js'; import { FormAssociatedMixin } from '../common/mixins/form-associated.js'; import { clamp, formatString, isLTR } from '../common/util.js'; import IgcIconComponent from '../icon/icon.js'; import IgcRatingSymbolComponent from './rating-symbol.js'; import { styles } from './themes/rating.base.css.js'; import { styles as shared } from './themes/shared/rating.common.css.js'; import { all } from './themes/themes.js'; let IgcRatingComponent = IgcRatingComponent_1 = class IgcRatingComponent extends FormAssociatedMixin(EventEmitterMixin(LitElement)) { static register() { registerComponent(IgcRatingComponent_1, IgcIconComponent, IgcRatingSymbolComponent); } get isInteractive() { return !(this.readOnly || this.disabled); } get hasProjectedSymbols() { return this.ratingSymbols.length > 0; } get valueText() { const value = this.round(this.value); return this.valueFormat ? formatString(this.valueFormat, value, this.max) : `${value} of ${this.max}`; } handleMaxChange() { this.max = this.hasProjectedSymbols ? this.ratingSymbols.length : Math.max(0, this.max); if (this.max < this.value) { this.value = this.max; } } handleValueChange() { this.value = clamp(Number.isNaN(this.value) ? 0 : this.value, 0, this.max); this.setFormValue(`${this.value}`, `${this.value}`); this.updateValidity(); this.setInvalidState(); } handlePrecisionChange() { this.step = !this.single ? clamp(this.step, 0.001, 1) : 1; } handleSelectionChange() { if (this.single) { this.step = 1; this.value = Math.ceil(this.value); } } constructor() { super(); this.hoverValue = -1; this.hoverState = false; this.max = 5; this.step = 1; this.value = 0; this.hoverPreview = false; this.readOnly = false; this.single = false; this.allowReset = false; addKeybindings(this, { skip: () => !this.isInteractive, bindingDefaults: { preventDefault: true }, }) .set(arrowUp, () => this.emitValueUpdate(this.value + this.step)) .set(arrowRight, () => this.emitValueUpdate(isLTR(this) ? this.value + this.step : this.value - this.step)) .set(arrowDown, () => this.emitValueUpdate(this.value - this.step)) .set(arrowLeft, () => this.emitValueUpdate(isLTR(this) ? this.value - this.step : this.value + this.step)) .set(homeKey, () => this.emitValueUpdate(this.step)) .set(endKey, () => this.emitValueUpdate(this.max)); } handleClick({ clientX }) { const value = this.calcNewValue(clientX); const sameValue = this.value === value; if (this.allowReset && sameValue) { this.emitValueUpdate(0); } else if (!sameValue) { this.emitValueUpdate(value); } } handleMouseMove({ clientX }) { const value = this.calcNewValue(clientX); if (this.hoverValue !== value) { this.hoverValue = value; this.emitEvent('igcHover', { detail: this.hoverValue }); } } emitValueUpdate(value) { this.value = clamp(value, 0, this.max); if (value === this.value) { this.emitEvent('igcChange', { detail: this.value }); } } handleSlotChange() { if (this.hasProjectedSymbols) { this.max = this.ratingSymbols.length; this.requestUpdate(); } } handleHoverEnabled() { this.hoverState = true; } handleHoverDisabled() { this.hoverState = false; } calcNewValue(x) { const { width, left, right } = this.container.getBoundingClientRect(); const percent = isLTR(this) ? (x - left) / width : (right - x) / width; const value = this.round(this.max * percent + this.step / 2); return clamp(value, this.step, this.max); } getPrecision(num) { const [_, decimal] = num.toString().split('.'); return decimal ? decimal.length : 0; } round(value) { return Number((Math.round(value / this.step) * this.step).toFixed(this.getPrecision(this.step))); } clipSymbol(index, isLTR = true) { const value = this.hoverState ? this.hoverValue : this.value; const progress = index + 1 - value; const exclusive = progress === 0 || this.value === index + 1 ? 0 : 1; const selection = this.single ? exclusive : progress; const activate = (p) => clamp(p * 100, 0, 100); const forward = `inset(0 ${activate(isLTR ? selection : 1 - selection)}% 0 0)`; const backward = `inset(0 0 0 ${activate(isLTR ? 1 - selection : selection)}%)`; return { backward: isLTR ? backward : forward, forward: isLTR ? forward : backward, }; } stepUp(n = 1) { this.value += this.round(n * this.step); } stepDown(n = 1) { this.value -= this.round(n * this.step); } *renderSymbols() { const ltr = isLTR(this); for (let i = 0; i < this.max; i++) { const { forward, backward } = this.clipSymbol(i, ltr); yield html `<igc-rating-symbol exportparts="symbol, full, empty"> <igc-icon collection="default" name="star_filled" style=${styleMap({ clipPath: forward })} ></igc-icon> <igc-icon collection="default" name="star_outlined" style=${styleMap({ clipPath: backward })} slot="empty" ></igc-icon> </igc-rating-symbol>`; } } clipProjected() { if (this.hasProjectedSymbols) { const ltr = isLTR(this); this.ratingSymbols.forEach((symbol, i) => { const full = symbol.shadowRoot?.querySelector('[part="symbol full"]'); const empty = symbol.shadowRoot?.querySelector('[part="symbol empty"]'); const { forward, backward } = this.clipSymbol(i, ltr); if (full) { full.style.clipPath = forward; } if (empty) { empty.style.clipPath = backward; } }); } } render() { const props = [ this.value, this.hoverValue, this.max, this.step, this.single, this.hoverState, this.ratingSymbols, ]; const hoverActive = this.hoverPreview && this.isInteractive; return html ` <label part="label" id="rating-label" ?hidden=${!this.label} >${this.label}</label > <div part="base" role="slider" tabindex=${ifDefined(this.disabled ? undefined : 0)} aria-labelledby="rating-label" aria-valuemin="0" aria-valuenow=${this.value} aria-valuemax=${this.max} aria-valuetext=${this.valueText} > <div aria-hidden="true" part="symbols" @click=${this.isInteractive ? this.handleClick : nothing} @mouseenter=${hoverActive ? this.handleHoverEnabled : nothing} @mouseleave=${hoverActive ? this.handleHoverDisabled : nothing} @mousemove=${hoverActive ? this.handleMouseMove : nothing} > <slot name="symbol" @slotchange=${this.handleSlotChange}> ${guard(props, () => { this.clipProjected(); return this.renderSymbols(); })} </slot> </div> <label part="value-label" ?hidden=${this.valueLabel.length === 0}> <slot name="value-label"></slot> </label> </div> `; } }; IgcRatingComponent.tagName = 'igc-rating'; IgcRatingComponent.styles = [styles, shared]; __decorate([ queryAssignedElements({ selector: IgcRatingSymbolComponent.tagName, slot: 'symbol', }) ], IgcRatingComponent.prototype, "ratingSymbols", void 0); __decorate([ query('[part="symbols"]', true) ], IgcRatingComponent.prototype, "container", void 0); __decorate([ queryAssignedNodes({ slot: 'value-label', flatten: true }) ], IgcRatingComponent.prototype, "valueLabel", void 0); __decorate([ state() ], IgcRatingComponent.prototype, "hoverValue", void 0); __decorate([ state() ], IgcRatingComponent.prototype, "hoverState", void 0); __decorate([ property({ type: Number }) ], IgcRatingComponent.prototype, "max", void 0); __decorate([ property({ type: Number }) ], IgcRatingComponent.prototype, "step", void 0); __decorate([ property() ], IgcRatingComponent.prototype, "label", void 0); __decorate([ property({ attribute: 'value-format' }) ], IgcRatingComponent.prototype, "valueFormat", void 0); __decorate([ property({ type: Number }) ], IgcRatingComponent.prototype, "value", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'hover-preview' }) ], IgcRatingComponent.prototype, "hoverPreview", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'readonly' }) ], IgcRatingComponent.prototype, "readOnly", void 0); __decorate([ property({ type: Boolean }) ], IgcRatingComponent.prototype, "single", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'allow-reset' }) ], IgcRatingComponent.prototype, "allowReset", void 0); __decorate([ watch('max') ], IgcRatingComponent.prototype, "handleMaxChange", null); __decorate([ watch('value') ], IgcRatingComponent.prototype, "handleValueChange", null); __decorate([ watch('step') ], IgcRatingComponent.prototype, "handlePrecisionChange", null); __decorate([ watch('single') ], IgcRatingComponent.prototype, "handleSelectionChange", null); IgcRatingComponent = IgcRatingComponent_1 = __decorate([ themes(all) ], IgcRatingComponent); export default IgcRatingComponent; //# sourceMappingURL=rating.js.map