UNPKG

@exadel/esl

Version:

Exadel Smart Library (ESL) is the lightweight custom elements library that provide a set of super-flexible components

134 lines (133 loc) 5.75 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 ESLMediaRuleList_1; import { ExportNs } from '../../esl-utils/environment/export-ns'; import { parseObjectSafe } from '../../esl-utils/misc/format'; import { deepMerge, isEqual } from '../../esl-utils/misc/object'; import { SyntheticEventTarget } from '../../esl-utils/dom/events'; import { ESLMediaRule } from './esl-media-rule'; // keep a named guard for strict narrowing const isDefinedRule = (rule) => !!rule; /** A custom event dispatched by {@link ESLMediaRuleList} instances */ export class ESLMediaRuleListEvent extends Event { constructor(current, previous) { super(ESLMediaRuleListEvent.TYPE); Object.assign(this, { current, previous }); } } ESLMediaRuleListEvent.TYPE = 'change'; // Singleton empty rule list placeholder let empty; /** * ESLMediaRuleList - {@link ESLMediaRule} observable collection * @author Yuliya Adamskaya, Alexey Stsefanovich (ala'n) * * Represents observable object that wraps environment to value mapping */ let ESLMediaRuleList = ESLMediaRuleList_1 = class ESLMediaRuleList extends SyntheticEventTarget { /** @returns empty {@link ESLMediaRuleList} instance */ static empty() { if (!empty) empty = new ESLMediaRuleList_1([]); return empty; } static parse(query, ...common) { const parser = typeof common[common.length - 1] === 'function' ? common.pop() : String; const mask = common.pop(); if (typeof mask !== 'string' || query.includes('=>') || !query.includes('|')) { return ESLMediaRuleList_1.parseQuery(query, parser); } return ESLMediaRuleList_1.parseTuple(mask, query, parser); } static parseQuery(query, parser = String) { const rules = query.split('|') .map((lex) => ESLMediaRule.parse(lex, parser)) .filter(isDefinedRule); return new ESLMediaRuleList_1(rules); } static parseTuple(mask, values, parser = String) { const queries = mask.split('|'); const valueList = values.split('|'); while (valueList.length < queries.length && valueList.length !== 0) valueList.push(valueList[valueList.length - 1]); if (valueList.length !== queries.length) throw new TypeError(`tuple "${values}" doesn't correspond to mask "${mask}"`); const rules = queries.map((query, i) => ESLMediaRule.create(valueList[i], query, parser)); const validRules = rules.filter(isDefinedRule); return new ESLMediaRuleList_1(validRules); } constructor(rules) { super(); this._rules = rules; this._onMatchChanged = this._onMatchChanged.bind(this); } addEventListener(type, callback = type) { super.addEventListener(type, callback); if (this.getEventListeners('change').length > 1) return; this._value = this.computedValue; this.rules.forEach((rule) => rule.addEventListener(this._onMatchChanged)); } removeEventListener(type, callback = type) { super.removeEventListener(type, callback); if (this.hasEventListener()) return; delete this._value; this.rules.forEach((rule) => rule.removeEventListener(this._onMatchChanged)); } /** Array of {@link ESLMediaRule}s that forms the current {@link ESLMediaRuleList} */ get rules() { return this._rules; } /** All active {@link ESLMediaRule}s */ get active() { return this.rules.filter((rule) => rule.matches); } /** Value of the last of active rules */ get activeValue() { var _a; return (_a = this.active.pop()) === null || _a === void 0 ? void 0 : _a.payload; } /** All active rule values */ get activeValues() { return this.active.map((rule) => rule.payload); } /** * Current value of {@link ESLMediaRuleList} object * Uses cache if current object is under observation */ get value() { if (!this.hasEventListener()) return this.computedValue; return Object.hasOwnProperty.call(this, '_value') ? this._value : this.computedValue; } /** Always computed value of the current {@link ESLMediaRuleList} object */ get computedValue() { return deepMerge(undefined, ...this.activeValues); } /** Handles inner rules state change */ _onMatchChanged() { const curValue = this.value; const newValue = this.computedValue; if (isEqual(curValue, newValue)) return; this._value = newValue; this.dispatchEvent(new ESLMediaRuleListEvent(newValue, curValue)); } /** @returns serialized {@link ESLMediaRuleList} object representation*/ toString() { return this.rules.join(' | '); } }; /** String value parser (default) */ ESLMediaRuleList.STRING_PARSER = String; /** Object value parser. Uses {@link parseObjectSafe} to parse value */ ESLMediaRuleList.OBJECT_PARSER = (val) => parseObjectSafe(val, () => console.warn(`[ESL]: Cannot parse object value "${val}"`)); ESLMediaRuleList = ESLMediaRuleList_1 = __decorate([ ExportNs('MediaRuleList') ], ESLMediaRuleList); export { ESLMediaRuleList };