/*! * 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.97 */ import { h, Host } from "@stencil/core"; import { focusElement, getElementDir } from "../../utils/dom"; import { CSS_UTILITY } from "../../utils/resources"; import { updateHostInteraction } from "../../utils/interactive"; /** Any attributes placed on component will propagate to the rendered child */ /** Passing a 'href' will render an anchor link, instead of a span. Role will be set to link, or link, depending on this. */ /** It is the consumers responsibility to add aria information, rel, target, for links, and any link attributes for form submission */ /** @slot - A slot for adding text. */ export class Link { constructor() { //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- /** When `true`, interaction is prevented and the component is displayed with lower opacity. */ this.disabled = false; /** * Prompts the user to save the linked URL instead of navigating to it. Can be used with or without a value: * Without a value, the browser will suggest a filename/extension * See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download. */ this.download = false; this.childElClickHandler = (event) => { if (!event.isTrusted) { // click was invoked internally, we stop it here event.stopPropagation(); } }; //-------------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------------- this.storeTagRef = (el) => { this.childEl = el; }; } //-------------------------------------------------------------------------- // // Lifecycle // //-------------------------------------------------------------------------- componentDidRender() { updateHostInteraction(this); } render() { const { download, el } = this; const dir = getElementDir(el); const childElType = this.href ? "a" : "span"; const iconStartEl = (h("calcite-icon", { class: "calcite-link--icon icon-start", flipRtl: this.iconFlipRtl === "start" || this.iconFlipRtl === "both", icon: this.iconStart, scale: "s" })); const iconEndEl = (h("calcite-icon", { class: "calcite-link--icon icon-end", flipRtl: this.iconFlipRtl === "end" || this.iconFlipRtl === "both", icon: this.iconEnd, scale: "s" })); const Tag = childElType; const role = childElType === "span" ? "link" : null; const tabIndex = childElType === "span" ? 0 : null; return (h(Host, { role: "presentation" }, h(Tag, { class: { [CSS_UTILITY.rtl]: dir === "rtl" }, /* When the 'download' property of type 'boolean | string' is set to true, the value is "". This works around that issue for now. */ download: Tag === "a" && (download === "" || download) ? download : null, href: Tag === "a" && this.href, onClick: this.childElClickHandler, ref: this.storeTagRef, rel: Tag === "a" && this.rel, role: role, tabIndex: tabIndex, target: Tag === "a" && this.target }, this.iconStart ? iconStartEl : null, h("slot", null), this.iconEnd ? iconEndEl : null))); } //-------------------------------------------------------------------------- // // Events // //-------------------------------------------------------------------------- clickHandler(event) { // forwards the click() to the internal link for non user-initiated events if (!event.isTrusted) { this.childEl.click(); } } //-------------------------------------------------------------------------- // // Public Methods // //-------------------------------------------------------------------------- /** Sets focus on the component. */ async setFocus() { focusElement(this.childEl); } static get is() { return "calcite-link"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["link.scss"] }; } static get styleUrls() { return { "$": ["link.css"] }; } static get properties() { return { "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "When `true`, interaction is prevented and the component is displayed with lower opacity." }, "attribute": "disabled", "reflect": true, "defaultValue": "false" }, "download": { "type": "any", "mutable": false, "complexType": { "original": "string | boolean", "resolved": "boolean | string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Prompts the user to save the linked URL instead of navigating to it. Can be used with or without a value:\nWithout a value, the browser will suggest a filename/extension\nSee https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download." }, "attribute": "download", "reflect": true, "defaultValue": "false" }, "href": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Specifies the URL of the linked resource, which can be set as an absolute or relative path." }, "attribute": "href", "reflect": true }, "iconEnd": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Specifies an icon to display at the end of the component." }, "attribute": "icon-end", "reflect": true }, "iconFlipRtl": { "type": "string", "mutable": false, "complexType": { "original": "FlipContext", "resolved": "\"both\" | \"end\" | \"start\"", "references": { "FlipContext": { "location": "import", "path": "../interfaces" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "When `true`, the icon will be flipped when the element direction is right-to-left (`\"rtl\"`)." }, "attribute": "icon-flip-rtl", "reflect": true }, "iconStart": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Specifies an icon to display at the start of the component." }, "attribute": "icon-start", "reflect": true }, "rel": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Specifies the relationship to the linked document defined in `href`." }, "attribute": "rel", "reflect": false }, "target": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Specifies the frame or window to open the linked document." }, "attribute": "target", "reflect": false } }; } static get methods() { return { "setFocus": { "complexType": { "signature": "() => Promise", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise" }, "docs": { "text": "Sets focus on the component.", "tags": [] } } }; } static get elementRef() { return "el"; } static get listeners() { return [{ "name": "click", "method": "clickHandler", "target": undefined, "capture": false, "passive": false }]; } }