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