UNPKG

@exadel/esl

Version:

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

272 lines (271 loc) 9.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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var ESLNote_1; import { ExportNs } from '../../esl-utils/environment/export-ns'; import { ESLBaseTrigger } from '../../esl-trigger/core/esl-base-trigger'; import { ready, attr, prop, boolAttr, memoize, listen } from '../../esl-utils/decorators'; import { ESLTooltip } from '../../esl-tooltip/core'; import { promisifyTimeout, repeatSequence } from '../../esl-utils/async'; import { scrollIntoView } from '../../esl-utils/dom/scroll'; import { ESLMediaQuery } from '../../esl-media-query/core'; let ESLNote = ESLNote_1 = class ESLNote extends ESLBaseTrigger { /** Target observable Toggleable */ get $target() { return ESLTooltip.sharedInstance; } /** Marker to allow footnotes to pick up this note */ get allowFootnotes() { return !this.queryToIgnore.matches; } /** Note index in the scope content */ get index() { return this._index; } set index(value) { this._index = value; this.innerHTML = this.renderedHTML; } /** Note index in the displayed list of footnotes */ get renderedIndex() { return this.allowFootnotes ? `${this._index}` : this.standaloneLabel; } /** Note markup */ get renderedHTML() { const index = this.renderedIndex; if (!this._$footnotes) return index; const footnotesIndexId = `${this._$footnotes.id}-${index}`; return `<a class="esl-note-link" href="#${footnotesIndexId}" tabindex="-1">${index}</a>`; } /** Query to describe conditions to ignore note by footnotes */ get queryToIgnore() { const ignore = this.getClosestRelatedAttr('ignore') || this.ignore; return ESLMediaQuery.for(ignore); } /** The text writing directionality of the element */ get currentDir() { return getComputedStyle(this).direction; } /** The base language of the element */ get currentLang() { const el = this.closest('[lang]'); return el ? el.lang : ''; } /** Checks that the target is in active state */ get isTargetActive() { return this.$target.open && this.$target.activator === this; } connectedCallback() { this.init(); super.connectedCallback(); this._sendResponseToFootnote(); } disconnectedCallback() { var _a; super.disconnectedCallback(); (_a = this._$footnotes) === null || _a === void 0 ? void 0 : _a.unlinkNote(this); this.restore(); } attributeChangedCallback(attrName, oldVal, newVal) { if (!this.connected || oldVal === newVal) return; if (attrName === 'ignore') { this.updateIgnoredQuery(); } } /** Revises the settings for ignoring the note */ updateIgnoredQuery() { if (!this.connected) return; memoize.clear(this, 'queryToIgnore'); this.$$on(this._onIgnoreConditionChange); this._onIgnoreConditionChange(); } /** Gets attribute value from the closest element with group behavior settings */ getClosestRelatedAttr(attrName) { const relatedAttrName = `${this.baseTagName}-${attrName}`; const $closest = this.closest(`[${relatedAttrName}]`); return $closest ? $closest.getAttribute(relatedAttrName) : null; } /** Activates note */ activate() { this.hideTarget(); this.$$fire('esl:show:request'); // TODO: replace timeout with a more reliable mechanism to have time to show content with this note repeatSequence(() => __awaiter(this, void 0, void 0, function* () { yield promisifyTimeout(this.constructor.activateTimeout); yield scrollIntoView(this, { behavior: 'smooth', block: 'center' }); return this.$target.open || this.showTarget(); }), 3); } /** Highlights note */ highlight(enable = true) { this.classList.toggle('highlight', enable); } /** Links note with footnotes */ link(footnotes, index) { this.$$attr('linked', true); this._$footnotes = footnotes; this.index = index; this.tabIndex = 0; this.update(); } /** Unlinks note from footnotes */ unlink() { this.restore(); this.update(); this._sendResponseToFootnote(); } /** Updates note state */ update() { this.$$attr('standalone', !(this.linked && this.allowFootnotes)); } /** Initial initialization of the element during the connection to DOM */ init() { this.html = this.html || this.innerHTML; memoize.clear(this, 'queryToIgnore'); this.index = 0; this.$$attr('linked', false); this.update(); } /** Restores original note content after unlinking */ restore() { this.$$attr('linked', false); this._$footnotes = null; this.index = 0; this.tabIndex = -1; } /** Merge params to pass to the toggleable */ mergeToggleableParams(...params) { const container = this.getClosestRelatedAttr('container') || this.container; const containerEl = container ? this.$$find(container) : undefined; return super.mergeToggleableParams({ initiator: 'note', activator: this, containerEl, html: this.html, dir: this.currentDir, lang: this.currentLang, intersectionMargin: this.intersectionMargin }, ...params); } /** Show target toggleable with passed params */ showTarget(params = {}) { super.showTarget(params); this.highlight(); } /** Actions on breakpoint changing */ _onIgnoreConditionChange() { var _a; this.hideTarget(); this.innerHTML = this.renderedHTML; this.update(); (_a = this._$footnotes) === null || _a === void 0 ? void 0 : _a.update(); } /** Handles footnotes request event */ _onFootnotesReady(e) { if (this.linked) return; this._sendResponseToFootnote(); } /** Handles ESLNote state change */ _onTargetHide() { var _a; if (!this.isTargetActive) (_a = this._$footnotes) === null || _a === void 0 ? void 0 : _a.turnOffHighlight(this); } /** Handles ESLNote state change */ _onBeforeTargetShow() { var _a; if (this.isTargetActive) (_a = this._$footnotes) === null || _a === void 0 ? void 0 : _a.turnOffHighlight(this); } /** Sends the response to footnotes */ _sendResponseToFootnote() { this.$$fire(this.FOOTNOTE_RESPONSE_EVENT); } }; ESLNote.is = 'esl-note'; ESLNote.observedAttributes = ['ignore']; /** Timeout before activating note (to have time to show content with this note) */ ESLNote.activateTimeout = 100; __decorate([ prop('esl:footnotes:request') ], ESLNote.prototype, "FOOTNOTE_REQUEST_EVENT", void 0); __decorate([ prop('esl:footnotes:response') ], ESLNote.prototype, "FOOTNOTE_RESPONSE_EVENT", void 0); __decorate([ attr({ defaultValue: 'not all' }) ], ESLNote.prototype, "ignore", void 0); __decorate([ attr() ], ESLNote.prototype, "html", void 0); __decorate([ attr({ defaultValue: '*' }) ], ESLNote.prototype, "standaloneLabel", void 0); __decorate([ attr({ defaultValue: 'all' }) ], ESLNote.prototype, "trackHover", void 0); __decorate([ attr() ], ESLNote.prototype, "container", void 0); __decorate([ attr({ defaultValue: '0px' }) ], ESLNote.prototype, "intersectionMargin", void 0); __decorate([ boolAttr({ readonly: true }) ], ESLNote.prototype, "linked", void 0); __decorate([ boolAttr({ readonly: true }) ], ESLNote.prototype, "standalone", void 0); __decorate([ memoize() ], ESLNote.prototype, "queryToIgnore", null); __decorate([ ready ], ESLNote.prototype, "connectedCallback", null); __decorate([ ready ], ESLNote.prototype, "disconnectedCallback", null); __decorate([ listen({ event: 'change', target: (el) => el.queryToIgnore }) ], ESLNote.prototype, "_onIgnoreConditionChange", null); __decorate([ listen({ event: (el) => el.FOOTNOTE_REQUEST_EVENT, target: document.body }) ], ESLNote.prototype, "_onFootnotesReady", null); __decorate([ listen({ event: 'esl:hide', target: (that) => that.$target }) ], ESLNote.prototype, "_onTargetHide", null); __decorate([ listen({ event: 'esl:before:show', target: (that) => that.$target }) ], ESLNote.prototype, "_onBeforeTargetShow", null); ESLNote = ESLNote_1 = __decorate([ ExportNs('Note') ], ESLNote); export { ESLNote };