UNPKG

@limetech/lime-elements

Version:
217 lines (216 loc) • 8.14 kB
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