@exadel/esl
Version:
Exadel Smart Library (ESL) is the lightweight custom elements library that provide a set of super-flexible components
140 lines (139 loc) • 4.99 kB
JavaScript
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;
};
import { ESLBaseElement } from '../../../esl-base-element/core';
import { format } from '../../../esl-utils/misc/format';
import { rafDecorator } from '../../../esl-utils/async/raf';
import { attr, boolAttr, decorate, listen, memoize } from '../../../esl-utils/decorators';
/**
* ESLSelectRenderer component
* @author Alexey Stsefanovich (ala'n)
*
* Auxiliary inner custom element to render {@link ESLSelect} inline field
*/
export class ESLSelectRenderer extends ESLBaseElement {
/** Internal container */
get $container() {
const $container = document.createElement('div');
$container.className = 'esl-select-text-container';
$container.appendChild(this.$text);
$container.appendChild(this.$rest);
return $container;
}
/** Inner remove button */
get $remove() {
const $remove = document.createElement('button');
$remove.type = 'button';
$remove.setAttribute('aria-label', 'Clear');
$remove.className = 'esl-select-clear-btn icon-nav-close-menu';
return $remove;
}
/** Inner text element */
get $text() {
const $text = document.createElement('span');
$text.className = 'esl-select-text';
return $text;
}
/** Inner rest label element */
get $rest() {
const $rest = document.createElement('span');
$rest.className = 'esl-select-text';
return $rest;
}
/** ESLSelect owner */
get owner() {
if (!this.parentElement || !this.parentElement.matches('esl-select'))
return null;
return this.parentElement;
}
connectedCallback() {
super.connectedCallback();
this.appendChild(this.$container);
this.appendChild(this.$remove);
Promise.resolve().then(() => this.render());
}
disconnectedCallback() {
super.disconnectedCallback();
this.removeChild(this.$container);
this.removeChild(this.$remove);
}
/** Rerender component with markers */
render() {
if (!this.owner)
return;
const selected = this.owner.selectedOptions;
this.hasValue = !!selected.length;
this.toggleAttribute('multiple', this.owner.multiple);
this.applyItems(selected.map((item) => item.text));
}
/** Render item with a visible items limit */
apply(items, limit) {
const length = items.length;
const rest = length - limit;
const options = { rest, length, limit };
this.$text.textContent = items.slice(0, limit).join(', ');
if (rest > 0) {
this.$rest.textContent = format(this.moreLabelFormat || '', options);
}
else {
this.$rest.textContent = '';
}
}
/** Render items using adaptive algorithm */
applyItems(items) {
let size = 0;
do {
this.apply(items, ++size); // Render with extended limit while it not fits to the container
} while (size <= items.length && this.$container.scrollWidth <= this.$container.clientWidth);
this.apply(items, size - 1); // Render last limit that fits
}
/** Handle clear button click */
_onClear(e) {
if (!this.owner)
return;
this.owner.setAllSelected(false);
e.stopPropagation();
e.preventDefault();
}
_onResize() {
this.render();
}
}
ESLSelectRenderer.is = 'esl-select-renderer';
__decorate([
attr()
], ESLSelectRenderer.prototype, "emptyText", void 0);
__decorate([
attr()
], ESLSelectRenderer.prototype, "moreLabelFormat", void 0);
__decorate([
boolAttr()
], ESLSelectRenderer.prototype, "hasValue", void 0);
__decorate([
memoize()
], ESLSelectRenderer.prototype, "$container", null);
__decorate([
memoize()
], ESLSelectRenderer.prototype, "$remove", null);
__decorate([
memoize()
], ESLSelectRenderer.prototype, "$text", null);
__decorate([
memoize()
], ESLSelectRenderer.prototype, "$rest", null);
__decorate([
listen({
event: 'esl:change:value',
target: (el) => el.owner
})
], ESLSelectRenderer.prototype, "render", null);
__decorate([
listen({ event: 'click', selector: '.esl-select-clear-btn' })
], ESLSelectRenderer.prototype, "_onClear", null);
__decorate([
listen({ event: 'resize', target: window }),
decorate(rafDecorator)
], ESLSelectRenderer.prototype, "_onResize", null);