@limetech/lime-elements
Version:
217 lines (216 loc) • 8.14 kB
JavaScript
import { h } from '@stencil/core';
import { createRandomString } from '../../util/random-string';
import { getOwnerElement } from './get-owner-element';
import { TooltipTimer } from './tooltip-timer';
const DEFAULT_MAX_LENGTH = 50;
/**
* A tooltip can be used to display a descriptive text for any element.
* The displayed content must be a brief and supplemental string of text,
* identifying the element or describing its function for the user,
* helping them better understand unfamiliar objects that aren't described
* directly in the UI.
*
* ## Interaction
* The tooltip appears after a slight delay, when the element is hovered;
* and disappears as soon as the cursor leaves the element.
* Therefore, users cannot interact with the tip, but if the trigger element
* itself is interactive, it will remain interactible even with a tooltip bound
* to it.
*
* :::note
* In order to display the tooltip, the tooltip element and its trigger element
* must be within the same document or document fragment (the same shadowRoot).
* Often, it's easiest to just place them next to each other like in the example
* below, but if you need to, you can place them differently.
*
* ```html
* <limel-button icon="search" id="tooltip-example" />
* <limel-tooltip label="Search" elementId="tooltip-example" />
* ```
* :::
*
* ## Usage
* - Keep in mind that tooltips can be distracting, and can be perceived as an interruption.
* Use them only when they add significant value.
* - A good tip is concise, helpful, and informative.
* Don't explain the obvious or simply repeat what is already on the screen.
* When used correctly, supplemental info of a tooltip helps to [declutter the UI](/#/DesignGuidelines/decluttering.md/).
* - If the tip is essential to the primary tasks that the user is performing,
* such as warnings or important notes, include the information directly in the
* interface instead.
* - When a component offers a helper text (e.g. [Input field](/#/component/limel-input-field/)),
* use that, not a tooltip.
* - Make sure to use the tooltip on an element that users naturally and
* effortlessly recognize can be hovered.
*
* @exampleComponent limel-example-tooltip-basic
* @exampleComponent limel-example-tooltip-max-character
* @exampleComponent limel-example-tooltip-composite
*/
export class Tooltip {
constructor() {
this.showTooltip = () => {
this.tooltipTimer.showAfterDelay();
};
this.hideTooltip = () => {
this.tooltipTimer.hide();
};
this.elementId = undefined;
this.label = undefined;
this.helperLabel = undefined;
this.maxlength = DEFAULT_MAX_LENGTH;
this.openDirection = 'top';
this.open = undefined;
this.portalId = createRandomString();
this.tooltipId = createRandomString();
this.tooltipTimer = new TooltipTimer(() => (this.open = true), () => (this.open = false));
}
connectedCallback() {
this.ownerElement = getOwnerElement(this.elementId, this.host);
this.setOwnerAriaLabel();
this.addListeners();
}
disconnectedCallback() {
this.removeListeners();
}
render() {
const tooltipZIndex = getComputedStyle(this.host).getPropertyValue('--tooltip-z-index');
return (h("div", { class: "trigger-anchor" }, h("limel-portal", { openDirection: this.openDirection, visible: this.open, containerId: this.portalId, containerStyle: {
'z-index': tooltipZIndex,
'pointer-events': 'none',
}, anchor: this.ownerElement }, h("limel-tooltip-content", { label: this.label, helperLabel: this.helperLabel, maxlength: this.maxlength, role: "tooltip", "aria-hidden": !this.open, id: this.tooltipId }))));
}
setOwnerAriaLabel() {
var _a;
(_a = this.ownerElement) === null || _a === void 0 ? void 0 : _a.setAttribute('aria-describedby', this.tooltipId);
}
addListeners() {
var _a, _b, _c, _d;
(_a = this.ownerElement) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseover', this.showTooltip);
(_b = this.ownerElement) === null || _b === void 0 ? void 0 : _b.addEventListener('mouseout', this.hideTooltip);
(_c = this.ownerElement) === null || _c === void 0 ? void 0 : _c.addEventListener('focus', this.showTooltip);
(_d = this.ownerElement) === null || _d === void 0 ? void 0 : _d.addEventListener('blur', this.hideTooltip);
}
removeListeners() {
var _a, _b, _c, _d;
(_a = this.ownerElement) === null || _a === void 0 ? void 0 : _a.removeEventListener('mouseover', this.showTooltip);
(_b = this.ownerElement) === null || _b === void 0 ? void 0 : _b.removeEventListener('mouseout', this.hideTooltip);
(_c = this.ownerElement) === null || _c === void 0 ? void 0 : _c.removeEventListener('focus', this.showTooltip);
(_d = this.ownerElement) === null || _d === void 0 ? void 0 : _d.removeEventListener('blur', this.hideTooltip);
}
static get is() { return "limel-tooltip"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["tooltip.scss"]
};
}
static get styleUrls() {
return {
"$": ["tooltip.css"]
};
}
static get properties() {
return {
"elementId": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": true,
"optional": false,
"docs": {
"tags": [],
"text": "ID of the owner element that the tooltip should describe.\nMust be a child within the same document fragment as the tooltip element\nitself."
},
"attribute": "element-id",
"reflect": true
},
"label": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": true,
"optional": false,
"docs": {
"tags": [],
"text": "Short descriptive text of the owner element."
},
"attribute": "label",
"reflect": true
},
"helperLabel": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Additional helper text for the element.\nExample usage can be a keyboard shortcut to activate the function of the\nowner element."
},
"attribute": "helper-label",
"reflect": true
},
"maxlength": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The maximum amount of characters before rendering 'label' and\n'helperLabel' in two rows."
},
"attribute": "maxlength",
"reflect": true,
"defaultValue": "DEFAULT_MAX_LENGTH"
},
"openDirection": {
"type": "string",
"mutable": false,
"complexType": {
"original": "OpenDirection",
"resolved": "\"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
"references": {
"OpenDirection": {
"location": "import",
"path": "../menu/menu.types"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Decides the tooltip's location in relation to its trigger."
},
"attribute": "open-direction",
"reflect": true,
"defaultValue": "'top'"
}
};
}
static get states() {
return {
"open": {}
};
}
static get elementRef() { return "host"; }
}
//# sourceMappingURL=tooltip.js.map