123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- /*!
- * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
- * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
- * v1.0.0-beta.82
- */
- import { Component, Element, Host, Method, Prop, State, Watch, h } from "@stencil/core";
- import { CSS, ARIA_DESCRIBED_BY } from "./resources";
- import { guid } from "../../utils/guid";
- import { defaultOffsetDistance, createPopper, updatePopper, CSS as PopperCSS } from "../../utils/popper";
- import { queryElementRoots, toAriaBoolean } from "../../utils/dom";
- import TooltipManager from "./TooltipManager";
- const manager = new TooltipManager();
- /**
- * @slot - A slot for adding text.
- */
- export class Tooltip {
- constructor() {
- /**
- * Offset the position of the tooltip away from the reference element.
- * @default 6
- */
- this.offsetDistance = defaultOffsetDistance;
- /**
- * Offset the position of the tooltip along the reference element.
- */
- this.offsetSkidding = 0;
- /**
- * Display and position the component.
- */
- this.open = false;
- /** Describes the type of positioning to use for the overlaid content. If your element is in a fixed container, use the 'fixed' value. */
- this.overlayPositioning = "absolute";
- /**
- * Determines where the component will be positioned relative to the referenceElement.
- * @see [PopperPlacement](https://github.com/Esri/calcite-components/blob/master/src/utils/popper.ts#L25)
- */
- this.placement = "auto";
- this.guid = `calcite-tooltip-${guid()}`;
- // --------------------------------------------------------------------------
- //
- // Private Methods
- //
- // --------------------------------------------------------------------------
- this.setUpReferenceElement = () => {
- this.removeReferences();
- this.effectiveReferenceElement = this.getReferenceElement();
- const { el, referenceElement, effectiveReferenceElement } = this;
- if (referenceElement && !effectiveReferenceElement) {
- console.warn(`${el.tagName}: reference-element id "${referenceElement}" was not found.`, {
- el
- });
- }
- this.addReferences();
- this.createPopper();
- };
- this.getId = () => {
- return this.el.id || this.guid;
- };
- this.addReferences = () => {
- const { effectiveReferenceElement } = this;
- if (!effectiveReferenceElement) {
- return;
- }
- const id = this.getId();
- effectiveReferenceElement.setAttribute(ARIA_DESCRIBED_BY, id);
- manager.registerElement(effectiveReferenceElement, this.el);
- };
- this.removeReferences = () => {
- const { effectiveReferenceElement } = this;
- if (!effectiveReferenceElement) {
- return;
- }
- effectiveReferenceElement.removeAttribute(ARIA_DESCRIBED_BY);
- manager.unregisterElement(effectiveReferenceElement);
- };
- }
- offsetDistanceOffsetHandler() {
- this.reposition();
- }
- offsetSkiddingHandler() {
- this.reposition();
- }
- openHandler() {
- this.reposition();
- }
- placementHandler() {
- this.reposition();
- }
- referenceElementHandler() {
- this.setUpReferenceElement();
- }
- // --------------------------------------------------------------------------
- //
- // Lifecycle
- //
- // --------------------------------------------------------------------------
- componentWillLoad() {
- this.setUpReferenceElement();
- }
- componentDidLoad() {
- this.reposition();
- }
- disconnectedCallback() {
- this.removeReferences();
- this.destroyPopper();
- }
- // --------------------------------------------------------------------------
- //
- // Public Methods
- //
- // --------------------------------------------------------------------------
- /** Updates the position of the component. */
- async reposition() {
- const { popper, el, placement } = this;
- const modifiers = this.getModifiers();
- popper
- ? await updatePopper({
- el,
- modifiers,
- placement,
- popper
- })
- : this.createPopper();
- }
- getReferenceElement() {
- const { referenceElement, el } = this;
- return ((typeof referenceElement === "string"
- ? queryElementRoots(el, { id: referenceElement })
- : referenceElement) || null);
- }
- getModifiers() {
- const { arrowEl, offsetDistance, offsetSkidding } = this;
- const arrowModifier = {
- name: "arrow",
- enabled: true,
- options: {
- element: arrowEl
- }
- };
- const offsetModifier = {
- name: "offset",
- enabled: true,
- options: {
- offset: [offsetSkidding, offsetDistance]
- }
- };
- const eventListenerModifier = {
- name: "eventListeners",
- enabled: this.open
- };
- return [arrowModifier, offsetModifier, eventListenerModifier];
- }
- createPopper() {
- this.destroyPopper();
- const { el, placement, effectiveReferenceElement: referenceEl, overlayPositioning } = this;
- const modifiers = this.getModifiers();
- this.popper = createPopper({
- el,
- modifiers,
- placement,
- overlayPositioning,
- referenceEl
- });
- }
- destroyPopper() {
- const { popper } = this;
- if (popper) {
- popper.destroy();
- }
- this.popper = null;
- }
- // --------------------------------------------------------------------------
- //
- // Render Methods
- //
- // --------------------------------------------------------------------------
- render() {
- const { effectiveReferenceElement, label, open } = this;
- const displayed = effectiveReferenceElement && open;
- const hidden = !displayed;
- return (h(Host, { "aria-hidden": toAriaBoolean(hidden), "aria-label": label, "calcite-hydrated-hidden": hidden, id: this.getId(), role: "tooltip" },
- h("div", { class: {
- [PopperCSS.animation]: true,
- [PopperCSS.animationActive]: displayed
- } },
- h("div", { class: CSS.arrow, ref: (arrowEl) => (this.arrowEl = arrowEl) }),
- h("div", { class: CSS.container },
- h("slot", null)))));
- }
- static get is() { return "calcite-tooltip"; }
- static get encapsulation() { return "shadow"; }
- static get originalStyleUrls() { return {
- "$": ["tooltip.scss"]
- }; }
- static get styleUrls() { return {
- "$": ["tooltip.css"]
- }; }
- static get properties() { return {
- "label": {
- "type": "string",
- "mutable": false,
- "complexType": {
- "original": "string",
- "resolved": "string",
- "references": {}
- },
- "required": true,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "Accessible name for the component"
- },
- "attribute": "label",
- "reflect": false
- },
- "offsetDistance": {
- "type": "number",
- "mutable": false,
- "complexType": {
- "original": "number",
- "resolved": "number",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "default",
- "text": "6"
- }],
- "text": "Offset the position of the tooltip away from the reference element."
- },
- "attribute": "offset-distance",
- "reflect": true,
- "defaultValue": "defaultOffsetDistance"
- },
- "offsetSkidding": {
- "type": "number",
- "mutable": false,
- "complexType": {
- "original": "number",
- "resolved": "number",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "Offset the position of the tooltip along the reference element."
- },
- "attribute": "offset-skidding",
- "reflect": true,
- "defaultValue": "0"
- },
- "open": {
- "type": "boolean",
- "mutable": false,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "Display and position the component."
- },
- "attribute": "open",
- "reflect": true,
- "defaultValue": "false"
- },
- "overlayPositioning": {
- "type": "string",
- "mutable": false,
- "complexType": {
- "original": "OverlayPositioning",
- "resolved": "\"absolute\" | \"fixed\"",
- "references": {
- "OverlayPositioning": {
- "location": "import",
- "path": "../../utils/popper"
- }
- }
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "Describes the type of positioning to use for the overlaid content. If your element is in a fixed container, use the 'fixed' value."
- },
- "attribute": "overlay-positioning",
- "reflect": false,
- "defaultValue": "\"absolute\""
- },
- "placement": {
- "type": "string",
- "mutable": false,
- "complexType": {
- "original": "PopperPlacement",
- "resolved": "Placement | PlacementRtl | VariationRtl",
- "references": {
- "PopperPlacement": {
- "location": "import",
- "path": "../../utils/popper"
- }
- }
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "see",
- "text": "[PopperPlacement](https://github.com/Esri/calcite-components/blob/master/src/utils/popper.ts#L25)"
- }],
- "text": "Determines where the component will be positioned relative to the referenceElement."
- },
- "attribute": "placement",
- "reflect": true,
- "defaultValue": "\"auto\""
- },
- "referenceElement": {
- "type": "string",
- "mutable": false,
- "complexType": {
- "original": "HTMLElement | string",
- "resolved": "HTMLElement | string",
- "references": {
- "HTMLElement": {
- "location": "global"
- }
- }
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "Reference HTMLElement used to position this component according to the placement property. As a convenience, a string ID of the reference element can be used. However, setting this property to use an HTMLElement is preferred so that the component does not need to query the DOM for the referenceElement."
- },
- "attribute": "reference-element",
- "reflect": false
- }
- }; }
- static get states() { return {
- "effectiveReferenceElement": {}
- }; }
- static get methods() { return {
- "reposition": {
- "complexType": {
- "signature": "() => Promise<void>",
- "parameters": [],
- "references": {
- "Promise": {
- "location": "global"
- }
- },
- "return": "Promise<void>"
- },
- "docs": {
- "text": "Updates the position of the component.",
- "tags": []
- }
- }
- }; }
- static get elementRef() { return "el"; }
- static get watchers() { return [{
- "propName": "offsetDistance",
- "methodName": "offsetDistanceOffsetHandler"
- }, {
- "propName": "offsetSkidding",
- "methodName": "offsetSkiddingHandler"
- }, {
- "propName": "open",
- "methodName": "openHandler"
- }, {
- "propName": "placement",
- "methodName": "placementHandler"
- }, {
- "propName": "referenceElement",
- "methodName": "referenceElementHandler"
- }]; }
- }
|