UNPKG

@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
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 };