@telekom/scale-components
Version:
Scale is the digital design system for Telekom products and experiences.
211 lines (205 loc) • 9.22 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const index = require('./index-a0ea3d79.js');
const floatingUi_dom_esm = require('./floating-ui.dom.esm-1bce2997.js');
const utils = require('./utils-e9c3b953.js');
const statusNote = require('./status-note-dceee5a3.js');
const tooltipCss = ":host{--radius:var(--telekom-radius-small);--background:var(--telekom-color-background-surface-highlight);--color:var(--telekom-color-text-and-icon-white-standard);--font-weight:var(--telekom-typography-font-weight-regular);--font-size:var(--telekom-typography-font-size-body);--line-height:var(--telekom-typography-line-spacing-standard);--spacing:var(--telekom-spacing-composition-space-02)\n var(--telekom-spacing-composition-space-04);--arrow-size:12px;--transition-delay-hide:var(--telekom-motion-duration-instant);--transition-duration-hide:var(--telekom-motion-duration-immediate);--transition-timing-function-hide:var(--telekom-motion-easing-standard);--transition-duration-show:var(--telekom-motion-duration-immediate);--transition-timing-function-show:var(--telekom-motion-easing-standard);--z-index:var(--scl-z-index-70);display:contents;position:relative;box-sizing:border-box}[part='tooltip']{position:absolute;z-index:var(--z-index);top:0;left:0;background:var(--background);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);line-height:var(--line-height);padding:var(--spacing);border-radius:var(--radius);transition-property:opacity;transition-duration:var(--transition-duration-show);transition-timing-function:var(--transition-timing-function-show)}[part='tooltip'][aria-hidden='true']{opacity:0;transition-delay:var(--transition-delay-hide);transition-duration:var(--transition-duration-hide);transition-timing-function:var(--transition-timing-function-hide);pointer-events:none}[part='trigger']{}[part='arrow']{position:absolute;z-index:-1;background:var(--background);width:var(--arrow-size);height:var(--arrow-size);transform:rotate(45deg)}@media screen and (-ms-high-contrast: active){[part='tooltip']{border:1px solid yellow}}";
let id = 0;
const Tooltip = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.tooltipBeforeShow = index.createEvent(this, "scale-before-show", 7);
this.tooltipShow = index.createEvent(this, "scale-show", 7);
this.tooltipBeforeHide = index.createEvent(this, "scale-before-hide", 7);
this.tooltipHide = index.createEvent(this, "scale-hide", 7);
this.componentId = `tooltip-${++id}`;
/** (optional) The content of the Tooltip, supporting text only */
this.content = '';
/** (optional) Position of the Tooltip around the trigger element */
this.placement = 'top';
/** (optional) Disable the tooltip */
this.disabled = false;
/** (optional) Tooltip distance from the target element (related to `placement`) */
this.distance = 10;
/** (optional) How much of the arrow element is "hidden" */
this.arrowOffset = -4;
/** (optional) Padding between the arrow and the edges of the tooltip */
this.arrowPadding = 8;
/** (optional) Set the tooltip to opened by default (will still be closed on closing events) */
this.opened = false;
/** (optional) Set custom trigger event (hover, focus, click) */
this.trigger = 'hover focus';
/** (optional) Switching the flip option of the tooltip on and off */
this.flip = true;
this.mouseOverTooltip = false;
/**
* @see https://floating-ui.com/docs/tutorial#arrow-middleware
*/
this.update = async () => {
if (this.disabled || this.triggerEl == null) {
return;
}
// Position tooltip
const { x, y, placement, middlewareData } = await floatingUi_dom_esm.computePosition(this.triggerEl, this.tooltipEl, {
placement: this.placement,
middleware: [
floatingUi_dom_esm.offset(this.distance),
...(this.flip ? [floatingUi_dom_esm.flip()] : []),
floatingUi_dom_esm.arrow({ element: this.arrowEl, padding: this.arrowPadding }),
floatingUi_dom_esm.shift({ crossAxis: true }),
],
});
Object.assign(this.tooltipEl.style, {
left: `${x}px`,
top: `${y}px`,
});
// Position arrow
const { x: arrowX, y: arrowY } = middlewareData.arrow;
const [side] = placement.split('-');
const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[side];
Object.assign(this.arrowEl.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : '',
right: '',
bottom: '',
[staticSide]: `${this.arrowOffset}px`,
});
};
this.handleBlur = () => {
if (this.hasTrigger('focus')) {
this.hideTooltip();
}
};
this.handleClick = () => {
if (this.hasTrigger('click')) {
this.opened && !this.hasTrigger('focus')
? this.hideTooltip()
: this.showTooltip();
}
};
this.handleFocus = () => {
if (this.hasTrigger('focus')) {
this.showTooltip();
}
};
this.handleKeyDown = (event) => {
if (this.opened && event.key === 'Escape') {
event.stopPropagation();
this.hideTooltip();
}
};
this.handleMouseOver = () => {
if (this.hasTrigger('hover')) {
this.showTooltip();
}
};
this.handleMouseOut = () => {
if (!this.mouseOverTooltip) {
if (this.hasTrigger('hover')) {
this.hideTooltip();
}
}
};
this.handleTooltipMouseOver = () => {
this.mouseOverTooltip = true;
};
this.handleTooltipBlur = () => {
this.mouseOverTooltip = false;
this.handleMouseOut();
};
this.hasTrigger = (triggerType) => {
const triggers = this.trigger.split(' ');
return triggers.includes(triggerType);
};
}
handleOpenChange() {
this.opened ? this.showTooltip() : this.hideTooltip();
}
connectedCallback() {
statusNote.statusNote({ source: this.hostElement, tag: 'beta' });
if (this.hostElement.hasAttribute('open')) {
statusNote.statusNote({
tag: 'deprecated',
message: 'The `open` prop is deprecated in favor of `opened`',
source: this.hostElement,
});
}
const children = Array.from(this.hostElement.children).filter((x) => !x.hasAttribute('slot'));
if (children.length === 0) {
// If not children found to be used as trigger, warn
statusNote.statusNote({
tag: 'warning',
message: 'An element is required, if using text, wrap it in a `<span>`',
type: 'warn',
source: this.hostElement,
});
return;
}
this.triggerEl = children[0];
this.triggerEl.addEventListener('blur', this.handleBlur, true);
this.triggerEl.addEventListener('click', this.handleClick, true);
this.triggerEl.addEventListener('focus', this.handleFocus, true);
this.triggerEl.addEventListener('mouseover', this.handleMouseOver, true);
this.triggerEl.addEventListener('mouseout', this.handleMouseOut, true);
}
disconnectedCallback() {
this.triggerEl.removeEventListener('blur', this.handleBlur, true);
this.triggerEl.removeEventListener('click', this.handleClick, true);
this.triggerEl.removeEventListener('focus', this.handleFocus, true);
this.triggerEl.removeEventListener('mouseover', this.handleMouseOver, true);
this.triggerEl.removeEventListener('mouseout', this.handleMouseOut, true);
}
handleOutsideClick(event) {
if (utils.isClickOutside(event, this.hostElement)) {
this.hideTooltip();
}
}
componentDidUpdate() {
this.update();
if (this.opened) {
this.showTooltip();
}
}
componentDidRender() {
this.update();
}
async showTooltip() {
if (this.opened) {
return;
}
const scaleShow = this.tooltipBeforeShow.emit();
if (scaleShow.defaultPrevented) {
this.opened = false;
return;
}
this.opened = true;
this.update();
}
async hideTooltip() {
if (!this.opened) {
return;
}
const tooltipBeforeHide = this.tooltipBeforeHide.emit();
if (tooltipBeforeHide.defaultPrevented) {
this.opened = true;
return;
}
this.opened = false;
this.update();
}
render() {
return (index.h(index.Host, { onKeyDown: this.handleKeyDown }, this.styles && index.h("style", null, this.styles), index.h("span", { part: "trigger", "aria-describedby": this.componentId }, index.h("slot", null)), !this.disabled && (index.h("div", { part: "tooltip", role: "tooltip", "aria-hidden": this.opened ? 'false' : 'true', ref: (el) => (this.tooltipEl = el), id: this.componentId, onMouseOver: this.handleTooltipMouseOver, onMouseLeave: this.handleTooltipBlur }, index.h("slot", { name: "content" }, this.content), index.h("div", { "aria-hidden": "true", part: "arrow", ref: (el) => (this.arrowEl = el) })))));
}
get hostElement() { return index.getElement(this); }
static get watchers() { return {
"opened": ["handleOpenChange"]
}; }
};
Tooltip.style = tooltipCss;
exports.scale_tooltip = Tooltip;