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.

303 lines 11.5 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 { registerComponent } from '../common/definitions/register.js'; import { EventEmitterMixin } from '../common/mixins/event-emitter.js'; import { FormAssociatedMixin } from '../common/mixins/forms/associated.js'; import { createFormValueState, defaultNumberTransformers, } from '../common/mixins/forms/form-value.js'; import { asNumber, clamp, formatString, isEmpty, isLTR, numberOfDecimals, roundPrecise, } 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}`; } set max(value) { this._max = this.hasProjectedSymbols ? this.ratingSymbols.length : Math.max(0, value); if (this._max < this.value) { this.value = this._max; } } get max() { return this._max; } set step(value) { this._step = this.single ? 1 : clamp(value, 0.001, 1); } get step() { return this._step; } set value(number) { const value = this.hasUpdated ? clamp(asNumber(number), 0, this.max) : Math.max(asNumber(number), 0); this._formValue.setValueAndFormState(value); this._validate(); } get value() { return this._formValue.value; } set single(value) { this._single = Boolean(value); if (this._single) { this.step = 1; this.value = Math.ceil(this.value); } } get single() { return this._single; } constructor() { super(); this._max = 5; this._step = 1; this._single = false; this.hoverValue = -1; this.hoverState = false; this.hoverPreview = false; this.readOnly = false; this.allowReset = false; this._formValue = createFormValueState(this, { initialValue: 0, transformers: defaultNumberTransformers, }); 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)); } async firstUpdated() { await this.updateComplete; this._formValue.setValueAndFormState(clamp(this.value, 0, this.max)); this._pristine = true; } 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); } } handlePointerMove({ 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); return clamp(value, this.step, this.max); } round(value) { return roundPrecise(Math.ceil(value / this.step) * this.step, numberOfDecimals(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() { const ltr = isLTR(this); const partFull = '[part="symbol full"]'; const partEmpty = '[part="symbol empty"]'; for (const [i, symbol] of this.ratingSymbols.entries()) { const full = symbol.renderRoot.querySelector(partFull); const empty = symbol.renderRoot.querySelector(partEmpty); 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} @pointerenter=${hoverActive ? this.handleHoverEnabled : nothing} @pointerleave=${hoverActive ? this.handleHoverDisabled : nothing} @pointermove=${hoverActive ? this.handlePointerMove : nothing} > <slot name="symbol" @slotchange=${this.handleSlotChange}> ${guard(props, () => this.hasProjectedSymbols ? this.clipProjected() : this.renderSymbols())} </slot> </div> <label part="value-label" ?hidden=${isEmpty(this.valueLabel)}> <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", null); __decorate([ property({ type: Number }) ], IgcRatingComponent.prototype, "step", null); __decorate([ property() ], IgcRatingComponent.prototype, "label", void 0); __decorate([ property({ attribute: 'value-format' }) ], IgcRatingComponent.prototype, "valueFormat", void 0); __decorate([ property({ type: Number }) ], IgcRatingComponent.prototype, "value", null); __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, reflect: true }) ], IgcRatingComponent.prototype, "single", null); __decorate([ property({ type: Boolean, reflect: true, attribute: 'allow-reset' }) ], IgcRatingComponent.prototype, "allowReset", void 0); IgcRatingComponent = IgcRatingComponent_1 = __decorate([ themes(all) ], IgcRatingComponent); export default IgcRatingComponent; //# sourceMappingURL=rating.js.map