icon.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*!
  2. * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
  4. * v1.0.0-beta.82
  5. */
  6. import { Build, Component, Element, h, Host, Prop, State, Watch } from "@stencil/core";
  7. import { CSS } from "./resources";
  8. import { getElementDir, toAriaBoolean } from "../../utils/dom";
  9. import { fetchIcon, scaleToPx } from "./utils";
  10. import { createObserver } from "../../utils/observers";
  11. export class Icon {
  12. constructor() {
  13. //--------------------------------------------------------------------------
  14. //
  15. // Properties
  16. //
  17. //--------------------------------------------------------------------------
  18. /**
  19. * The name of the icon to display. The value of this property must match the icon name from https://esri.github.io/calcite-ui-icons/.
  20. */
  21. this.icon = null;
  22. /**
  23. * When true, the icon will be flipped when the element direction is 'rtl'.
  24. */
  25. this.flipRtl = false;
  26. /**
  27. * Icon scale.
  28. */
  29. this.scale = "m";
  30. this.visible = false;
  31. }
  32. //--------------------------------------------------------------------------
  33. //
  34. // Lifecycle
  35. //
  36. //--------------------------------------------------------------------------
  37. connectedCallback() {
  38. this.waitUntilVisible(() => {
  39. this.visible = true;
  40. this.loadIconPathData();
  41. });
  42. }
  43. disconnectedCallback() {
  44. var _a;
  45. (_a = this.intersectionObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
  46. this.intersectionObserver = null;
  47. }
  48. async componentWillLoad() {
  49. this.loadIconPathData();
  50. }
  51. render() {
  52. const { el, flipRtl, pathData, scale, textLabel } = this;
  53. const dir = getElementDir(el);
  54. const size = scaleToPx[scale];
  55. const semantic = !!textLabel;
  56. const paths = [].concat(pathData || "");
  57. return (h(Host, { "aria-hidden": toAriaBoolean(!semantic), "aria-label": semantic ? textLabel : null, role: semantic ? "img" : null },
  58. h("svg", { class: {
  59. [CSS.flipRtl]: dir === "rtl" && flipRtl,
  60. svg: true
  61. }, fill: "currentColor", height: "100%", viewBox: `0 0 ${size} ${size}`, width: "100%", xmlns: "http://www.w3.org/2000/svg" }, paths.map((path) => typeof path === "string" ? (h("path", { d: path })) : (h("path", { d: path.d, opacity: "opacity" in path ? path.opacity : 1 }))))));
  62. }
  63. //--------------------------------------------------------------------------
  64. //
  65. // Private Methods
  66. //
  67. //--------------------------------------------------------------------------
  68. async loadIconPathData() {
  69. const { icon, scale, visible } = this;
  70. if (!Build.isBrowser || !icon || !visible) {
  71. return;
  72. }
  73. this.pathData = await fetchIcon({ icon, scale });
  74. }
  75. waitUntilVisible(callback) {
  76. this.intersectionObserver = createObserver("intersection", (entries) => {
  77. entries.forEach((entry) => {
  78. if (entry.isIntersecting) {
  79. this.intersectionObserver.disconnect();
  80. this.intersectionObserver = null;
  81. callback();
  82. }
  83. });
  84. }, { rootMargin: "50px" });
  85. if (!this.intersectionObserver) {
  86. callback();
  87. return;
  88. }
  89. this.intersectionObserver.observe(this.el);
  90. }
  91. static get is() { return "calcite-icon"; }
  92. static get encapsulation() { return "shadow"; }
  93. static get originalStyleUrls() { return {
  94. "$": ["icon.scss"]
  95. }; }
  96. static get styleUrls() { return {
  97. "$": ["icon.css"]
  98. }; }
  99. static get assetsDirs() { return ["assets"]; }
  100. static get properties() { return {
  101. "icon": {
  102. "type": "string",
  103. "mutable": false,
  104. "complexType": {
  105. "original": "string",
  106. "resolved": "string",
  107. "references": {}
  108. },
  109. "required": false,
  110. "optional": false,
  111. "docs": {
  112. "tags": [],
  113. "text": "The name of the icon to display. The value of this property must match the icon name from https://esri.github.io/calcite-ui-icons/."
  114. },
  115. "attribute": "icon",
  116. "reflect": true,
  117. "defaultValue": "null"
  118. },
  119. "flipRtl": {
  120. "type": "boolean",
  121. "mutable": false,
  122. "complexType": {
  123. "original": "boolean",
  124. "resolved": "boolean",
  125. "references": {}
  126. },
  127. "required": false,
  128. "optional": false,
  129. "docs": {
  130. "tags": [],
  131. "text": "When true, the icon will be flipped when the element direction is 'rtl'."
  132. },
  133. "attribute": "flip-rtl",
  134. "reflect": true,
  135. "defaultValue": "false"
  136. },
  137. "scale": {
  138. "type": "string",
  139. "mutable": false,
  140. "complexType": {
  141. "original": "Scale",
  142. "resolved": "\"l\" | \"m\" | \"s\"",
  143. "references": {
  144. "Scale": {
  145. "location": "import",
  146. "path": "../interfaces"
  147. }
  148. }
  149. },
  150. "required": false,
  151. "optional": false,
  152. "docs": {
  153. "tags": [],
  154. "text": "Icon scale."
  155. },
  156. "attribute": "scale",
  157. "reflect": true,
  158. "defaultValue": "\"m\""
  159. },
  160. "textLabel": {
  161. "type": "string",
  162. "mutable": false,
  163. "complexType": {
  164. "original": "string",
  165. "resolved": "string",
  166. "references": {}
  167. },
  168. "required": false,
  169. "optional": false,
  170. "docs": {
  171. "tags": [],
  172. "text": "The icon label.\n\nIt is recommended to set this value if your icon is semantic."
  173. },
  174. "attribute": "text-label",
  175. "reflect": false
  176. }
  177. }; }
  178. static get states() { return {
  179. "pathData": {},
  180. "visible": {}
  181. }; }
  182. static get elementRef() { return "el"; }
  183. static get watchers() { return [{
  184. "propName": "icon",
  185. "methodName": "loadIconPathData"
  186. }, {
  187. "propName": "scale",
  188. "methodName": "loadIconPathData"
  189. }]; }
  190. }