@telekom/scale-components
Version:
Scale is the digital design system for Telekom products and experiences.
113 lines (110 loc) • 3.59 kB
JavaScript
;
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const hasShadowDom = (el) => {
return !!el.shadowRoot && !!el.attachShadow;
};
// eg isPseudoClassSupported(':focus-visible') // true for chrome, false for safari
const isPseudoClassSupported = (pseudoClass) => {
// Get the document stylesheet1
let ss = document.styleSheets[0];
// Create a stylesheet if one doesn't exist
if (!ss) {
const el = document.createElement('style');
document.head.appendChild(el);
ss = document.styleSheets[0];
document.head.removeChild(el);
}
// Test the pseudo-class by trying to style with it
function testPseudo() {
try {
if (!/^:/.test(pseudoClass)) {
pseudoClass = ':' + pseudoClass;
}
ss.insertRule('html' + pseudoClass + '{}', 0);
ss.deleteRule(0);
return true;
}
catch (e) {
return false;
}
}
// Run the test
return testPseudo();
};
/**
* Call `emit` on component events twice.
* One for the legacy camel-cased event, one for the new kebab-cased.
* e.g. for the event `scaleChange` it will do `instance.scaleChange.emit()` and `instance.scaleChangeLegacy.emit()`.
* It expects both `scaleChange` and `scaleChangeLegacy` event-decorated properties to exist on the component.
*
* @param instance {ComponentInterface} - The component instance, aka `this`
* @param eventKey {string} - The event property, e.g. `scaleChange`
* @param detail {any} - The custom event `detail`
* @returns {CustomEvent[]} - The events emitted
*/
function emitEvent(instance, eventKey, detail) {
const legacyKey = eventKey + 'Legacy';
const emitted = [];
if (typeof instance[legacyKey] !== 'undefined') {
// Emit legacy camel case event, e.g. `scaleClose`
emitted.push(instance[legacyKey].emit(detail));
}
// Emit now-standard kebab-case event, e.g. `scale-close`
emitted.push(instance[eventKey].emit(detail));
// Return both
return emitted;
}
function isClickOutside(event, host) {
let target = event.target;
const hasShadow = target.shadowRoot != null;
const composedPath = hasShadow ? event.composedPath() : [];
do {
if (target === host) {
return false;
}
if (hasShadow) {
// @ts-ignore
target = composedPath.shift();
}
else {
target = target.parentNode;
}
} while (target);
return true;
}
const isScaleIcon = (el) => {
if (el == null || el.nodeType !== 1) {
return false;
}
return el.nodeName.toUpperCase().substring(0, 10) === 'SCALE-ICON';
};
/** Creating global ids for different component helper-texts */
let id = 0;
function generateUniqueId() {
return id++;
}
/**
* Useful for waiting for animations to finish before doing something.
*
* @param el {HTMLElement | ShadowRoot} - The element to call `getAnimations` on
* @returns {Promise} - Resolves when all animations are finished
*/
const animationsFinished = (el) => {
return Promise.all(el.getAnimations({ subtree: true }).map((x) => x.finished));
};
exports.animationsFinished = animationsFinished;
exports.emitEvent = emitEvent;
exports.generateUniqueId = generateUniqueId;
exports.hasShadowDom = hasShadowDom;
exports.isClickOutside = isClickOutside;
exports.isPseudoClassSupported = isPseudoClassSupported;
exports.isScaleIcon = isScaleIcon;