@exadel/esl
Version:
Exadel Smart Library (ESL) is the lightweight custom elements library that provide a set of super-flexible components
116 lines (115 loc) • 4.91 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;
};
var ESLMatchHeightMixin_1;
import { ESLMixinElement } from '../../esl-mixin-element/core';
import { attr, listen, decorate, bind } from '../../esl-utils/decorators';
import { afterNextRender, throttle } from '../../esl-utils/async';
import { ESLResizeObserverTarget } from '../../esl-event-listener/core';
import { ExportNs } from '../../esl-utils/environment/export-ns';
/** Parse order attribute value to array of the matching selector strings */
const parseMatchers = (v) => (v || '').split('|').map((s) => s.trim()).concat('*');
/**
* ESLMatchHeight - mixin element to equalize heights of child elements within a container
* @author Feoktyst Shovchko, Alexey Stsefanovich (ala'n)
*
* Use example:
* ```html
* <div esl-match-height="selector"
* esl-match-height-order="selectorTopPriority | selectorSecondPriority">
* ... div.selector * n
* </div>
* ```
*/
let ESLMatchHeightMixin = ESLMatchHeightMixin_1 = class ESLMatchHeightMixin extends ESLMixinElement {
/** List of HTMLElements to normalize height */
get $elements() {
return Array.from(this.$host.querySelectorAll(this.selector || ESLMatchHeightMixin_1.DEFAULT_SELECTOR));
}
connectedCallback() {
super.connectedCallback();
afterNextRender(() => this.update());
}
disconnectedCallback() {
this.clear();
super.disconnectedCallback();
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === ESLMatchHeightMixin_1.is && oldValue)
this.clear(Array.from(this.$host.querySelectorAll(oldValue)));
super.attributeChangedCallback(name, oldValue, newValue);
this.update();
}
/** Starts elements normalization */
update() {
this.clear();
this.resize(this.$elements);
}
onResize() {
this.update();
}
onFontsLoaded() {
this.update();
}
/** Compares two {@link MatchItem} objects */
compare(a, b) {
if (a.order === b.order)
return a.top - b.top;
return (a.order - b.order) * Number.POSITIVE_INFINITY;
}
/** Creates a wrapper object based on the passed element */
toMatchItem($el) {
const { top, height } = $el.getBoundingClientRect();
const order = this.orders.findIndex((sel) => $el.matches(sel));
return { $el, order, top, height };
}
/** Resets height values */
clear($els = this.$elements) {
$els.forEach(($el) => $el.style.height = '');
}
/** Update height values for passed elements */
resize($els = this.$elements) {
if ($els.length < 2)
return;
const items = $els.map(this.toMatchItem).sort(this.compare);
const index = items.findIndex((item) => Math.abs(this.compare(item, items[0])) > 1);
const group = items.slice(0, index > 0 ? index : items.length);
if (group.length > 1) {
const maxHeight = Math.max(...group.map((item) => item.height));
group.forEach((item) => item.$el.style.height = `${maxHeight}px`);
}
this.resize(items.slice(group.length).map((item) => item.$el));
}
};
ESLMatchHeightMixin.is = 'esl-match-height';
ESLMatchHeightMixin.observedAttributes = ['esl-match-height-order'];
/** Default selector for child elements to normalize */
ESLMatchHeightMixin.DEFAULT_SELECTOR = '[match-height]';
__decorate([
attr({ defaultValue: ESLMatchHeightMixin.DEFAULT_SELECTOR, name: ESLMatchHeightMixin.is })
], ESLMatchHeightMixin.prototype, "selector", void 0);
__decorate([
attr({ defaultValue: ['*'], name: 'esl-match-height-order', parser: parseMatchers })
], ESLMatchHeightMixin.prototype, "orders", void 0);
__decorate([
decorate(throttle, 200)
], ESLMatchHeightMixin.prototype, "update", null);
__decorate([
listen({ event: 'resize', target: ESLResizeObserverTarget.for })
], ESLMatchHeightMixin.prototype, "onResize", null);
__decorate([
listen({ event: 'loadingdone', target: document.fonts })
], ESLMatchHeightMixin.prototype, "onFontsLoaded", null);
__decorate([
bind
], ESLMatchHeightMixin.prototype, "compare", null);
__decorate([
bind
], ESLMatchHeightMixin.prototype, "toMatchItem", null);
ESLMatchHeightMixin = ESLMatchHeightMixin_1 = __decorate([
ExportNs('MatchHeight')
], ESLMatchHeightMixin);
export { ESLMatchHeightMixin };