icon.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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.97
  5. */
  6. import { Build, h, Host } 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 }, h("svg", { class: {
  58. [CSS.flipRtl]: dir === "rtl" && flipRtl,
  59. svg: true
  60. }, 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 }))))));
  61. }
  62. //--------------------------------------------------------------------------
  63. //
  64. // Private Methods
  65. //
  66. //--------------------------------------------------------------------------
  67. async loadIconPathData() {
  68. const { icon, scale, visible } = this;
  69. if (!Build.isBrowser || !icon || !visible) {
  70. return;
  71. }
  72. this.pathData = await fetchIcon({ icon, scale });
  73. }
  74. waitUntilVisible(callback) {
  75. this.intersectionObserver = createObserver("intersection", (entries) => {
  76. entries.forEach((entry) => {
  77. if (entry.isIntersecting) {
  78. this.intersectionObserver.disconnect();
  79. this.intersectionObserver = null;
  80. callback();
  81. }
  82. });
  83. }, { rootMargin: "50px" });
  84. if (!this.intersectionObserver) {
  85. callback();
  86. return;
  87. }
  88. this.intersectionObserver.observe(this.el);
  89. }
  90. static get is() { return "calcite-icon"; }
  91. static get encapsulation() { return "shadow"; }
  92. static get originalStyleUrls() {
  93. return {
  94. "$": ["icon.scss"]
  95. };
  96. }
  97. static get styleUrls() {
  98. return {
  99. "$": ["icon.css"]
  100. };
  101. }
  102. static get assetsDirs() { return ["assets"]; }
  103. static get properties() {
  104. return {
  105. "icon": {
  106. "type": "string",
  107. "mutable": false,
  108. "complexType": {
  109. "original": "string",
  110. "resolved": "string",
  111. "references": {}
  112. },
  113. "required": false,
  114. "optional": false,
  115. "docs": {
  116. "tags": [],
  117. "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/."
  118. },
  119. "attribute": "icon",
  120. "reflect": true,
  121. "defaultValue": "null"
  122. },
  123. "flipRtl": {
  124. "type": "boolean",
  125. "mutable": false,
  126. "complexType": {
  127. "original": "boolean",
  128. "resolved": "boolean",
  129. "references": {}
  130. },
  131. "required": false,
  132. "optional": false,
  133. "docs": {
  134. "tags": [],
  135. "text": "When true, the icon will be flipped when the element direction is 'rtl'."
  136. },
  137. "attribute": "flip-rtl",
  138. "reflect": true,
  139. "defaultValue": "false"
  140. },
  141. "scale": {
  142. "type": "string",
  143. "mutable": false,
  144. "complexType": {
  145. "original": "Scale",
  146. "resolved": "\"l\" | \"m\" | \"s\"",
  147. "references": {
  148. "Scale": {
  149. "location": "import",
  150. "path": "../interfaces"
  151. }
  152. }
  153. },
  154. "required": false,
  155. "optional": false,
  156. "docs": {
  157. "tags": [],
  158. "text": "Icon scale."
  159. },
  160. "attribute": "scale",
  161. "reflect": true,
  162. "defaultValue": "\"m\""
  163. },
  164. "textLabel": {
  165. "type": "string",
  166. "mutable": false,
  167. "complexType": {
  168. "original": "string",
  169. "resolved": "string",
  170. "references": {}
  171. },
  172. "required": false,
  173. "optional": false,
  174. "docs": {
  175. "tags": [],
  176. "text": "The icon label.\n\nIt is recommended to set this value if your icon is semantic."
  177. },
  178. "attribute": "text-label",
  179. "reflect": false
  180. }
  181. };
  182. }
  183. static get states() {
  184. return {
  185. "pathData": {},
  186. "visible": {}
  187. };
  188. }
  189. static get elementRef() { return "el"; }
  190. static get watchers() {
  191. return [{
  192. "propName": "icon",
  193. "methodName": "loadIconPathData"
  194. }, {
  195. "propName": "scale",
  196. "methodName": "loadIconPathData"
  197. }];
  198. }
  199. }