action.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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 { Host, h, forceUpdate } from "@stencil/core";
  7. import { CSS, TEXT, SLOTS } from "./resources";
  8. import { createObserver } from "../../utils/observers";
  9. import { updateHostInteraction } from "../../utils/interactive";
  10. import { toAriaBoolean } from "../../utils/dom";
  11. /**
  12. * @slot - A slot for adding a `calcite-icon`.
  13. */
  14. export class Action {
  15. constructor() {
  16. // --------------------------------------------------------------------------
  17. //
  18. // Properties
  19. //
  20. // --------------------------------------------------------------------------
  21. /**
  22. * When `true`, the component is highlighted.
  23. */
  24. this.active = false;
  25. /** Specifies the appearance of the component. */
  26. this.appearance = "solid";
  27. /**
  28. * When `true`, the side padding of the component is reduced. Compact mode is used internally by components, e.g. `calcite-block-section`.
  29. */
  30. this.compact = false;
  31. /**
  32. * When `true`, interaction is prevented and the component is displayed with lower opacity.
  33. */
  34. this.disabled = false;
  35. /**
  36. * When `true`, indicates unread changes.
  37. */
  38. this.indicator = false;
  39. /**
  40. * Specifies the text label to display while loading.
  41. *
  42. * @default "Loading"
  43. */
  44. this.intlLoading = TEXT.loading;
  45. /**
  46. * When `true`, a busy indicator is displayed.
  47. */
  48. this.loading = false;
  49. /**
  50. * Specifies the size of the component.
  51. */
  52. this.scale = "m";
  53. /**
  54. * Indicates whether the text is displayed.
  55. */
  56. this.textEnabled = false;
  57. this.mutationObserver = createObserver("mutation", () => forceUpdate(this));
  58. // --------------------------------------------------------------------------
  59. //
  60. // Private Methods
  61. //
  62. // --------------------------------------------------------------------------
  63. this.handleTooltipSlotChange = (event) => {
  64. const tooltips = event.target
  65. .assignedElements({
  66. flatten: true
  67. })
  68. .filter((el) => el === null || el === void 0 ? void 0 : el.matches("calcite-tooltip"));
  69. const tooltip = tooltips[0];
  70. if (tooltip) {
  71. tooltip.referenceElement = this.buttonEl;
  72. }
  73. };
  74. this.calciteActionClickHandler = () => {
  75. if (!this.disabled) {
  76. this.calciteActionClick.emit();
  77. }
  78. };
  79. }
  80. // --------------------------------------------------------------------------
  81. //
  82. // Lifecycle
  83. //
  84. // --------------------------------------------------------------------------
  85. connectedCallback() {
  86. var _a;
  87. (_a = this.mutationObserver) === null || _a === void 0 ? void 0 : _a.observe(this.el, { childList: true, subtree: true });
  88. }
  89. disconnectedCallback() {
  90. var _a;
  91. (_a = this.mutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
  92. }
  93. componentDidRender() {
  94. updateHostInteraction(this);
  95. }
  96. // --------------------------------------------------------------------------
  97. //
  98. // Methods
  99. //
  100. // --------------------------------------------------------------------------
  101. /** Sets focus on the component. */
  102. async setFocus() {
  103. var _a;
  104. (_a = this.buttonEl) === null || _a === void 0 ? void 0 : _a.focus();
  105. }
  106. // --------------------------------------------------------------------------
  107. //
  108. // Render Methods
  109. //
  110. // --------------------------------------------------------------------------
  111. renderTextContainer() {
  112. const { text, textEnabled } = this;
  113. const textContainerClasses = {
  114. [CSS.textContainer]: true,
  115. [CSS.textContainerVisible]: textEnabled
  116. };
  117. return text ? (h("div", { class: textContainerClasses, key: "text-container" }, text)) : null;
  118. }
  119. renderIconContainer() {
  120. var _a;
  121. const { loading, icon, scale, el, intlLoading } = this;
  122. const iconScale = scale === "l" ? "m" : "s";
  123. const loaderScale = scale === "l" ? "l" : "m";
  124. const calciteLoaderNode = loading ? (h("calcite-loader", { active: true, inline: true, label: intlLoading, scale: loaderScale })) : null;
  125. const calciteIconNode = icon ? h("calcite-icon", { icon: icon, scale: iconScale }) : null;
  126. const iconNode = calciteLoaderNode || calciteIconNode;
  127. const hasIconToDisplay = iconNode || ((_a = el.children) === null || _a === void 0 ? void 0 : _a.length);
  128. const slotContainerNode = (h("div", { class: {
  129. [CSS.slotContainer]: true,
  130. [CSS.slotContainerHidden]: loading
  131. } }, h("slot", null)));
  132. return hasIconToDisplay ? (h("div", { "aria-hidden": "true", class: CSS.iconContainer, key: "icon-container" }, iconNode, slotContainerNode)) : null;
  133. }
  134. render() {
  135. const { compact, disabled, loading, textEnabled, label, text } = this;
  136. const ariaLabel = label || text;
  137. const buttonClasses = {
  138. [CSS.button]: true,
  139. [CSS.buttonTextVisible]: textEnabled,
  140. [CSS.buttonCompact]: compact
  141. };
  142. return (h(Host, { onClick: this.calciteActionClickHandler }, h("button", { "aria-busy": toAriaBoolean(loading), "aria-disabled": toAriaBoolean(disabled), "aria-label": ariaLabel, class: buttonClasses, disabled: disabled, ref: (buttonEl) => (this.buttonEl = buttonEl) }, this.renderIconContainer(), this.renderTextContainer()), h("slot", { name: SLOTS.tooltip, onSlotchange: this.handleTooltipSlotChange })));
  143. }
  144. static get is() { return "calcite-action"; }
  145. static get encapsulation() { return "shadow"; }
  146. static get originalStyleUrls() {
  147. return {
  148. "$": ["action.scss"]
  149. };
  150. }
  151. static get styleUrls() {
  152. return {
  153. "$": ["action.css"]
  154. };
  155. }
  156. static get properties() {
  157. return {
  158. "active": {
  159. "type": "boolean",
  160. "mutable": false,
  161. "complexType": {
  162. "original": "boolean",
  163. "resolved": "boolean",
  164. "references": {}
  165. },
  166. "required": false,
  167. "optional": false,
  168. "docs": {
  169. "tags": [],
  170. "text": "When `true`, the component is highlighted."
  171. },
  172. "attribute": "active",
  173. "reflect": true,
  174. "defaultValue": "false"
  175. },
  176. "alignment": {
  177. "type": "string",
  178. "mutable": false,
  179. "complexType": {
  180. "original": "Alignment",
  181. "resolved": "\"center\" | \"end\" | \"start\"",
  182. "references": {
  183. "Alignment": {
  184. "location": "import",
  185. "path": "../interfaces"
  186. }
  187. }
  188. },
  189. "required": false,
  190. "optional": true,
  191. "docs": {
  192. "tags": [],
  193. "text": "Specifies the horizontal alignment of button elements with text content."
  194. },
  195. "attribute": "alignment",
  196. "reflect": true
  197. },
  198. "appearance": {
  199. "type": "string",
  200. "mutable": false,
  201. "complexType": {
  202. "original": "Extract<\"solid\" | \"clear\", Appearance>",
  203. "resolved": "\"clear\" | \"solid\"",
  204. "references": {
  205. "Extract": {
  206. "location": "global"
  207. },
  208. "Appearance": {
  209. "location": "import",
  210. "path": "../interfaces"
  211. }
  212. }
  213. },
  214. "required": false,
  215. "optional": false,
  216. "docs": {
  217. "tags": [],
  218. "text": "Specifies the appearance of the component."
  219. },
  220. "attribute": "appearance",
  221. "reflect": true,
  222. "defaultValue": "\"solid\""
  223. },
  224. "compact": {
  225. "type": "boolean",
  226. "mutable": false,
  227. "complexType": {
  228. "original": "boolean",
  229. "resolved": "boolean",
  230. "references": {}
  231. },
  232. "required": false,
  233. "optional": false,
  234. "docs": {
  235. "tags": [],
  236. "text": "When `true`, the side padding of the component is reduced. Compact mode is used internally by components, e.g. `calcite-block-section`."
  237. },
  238. "attribute": "compact",
  239. "reflect": true,
  240. "defaultValue": "false"
  241. },
  242. "disabled": {
  243. "type": "boolean",
  244. "mutable": false,
  245. "complexType": {
  246. "original": "boolean",
  247. "resolved": "boolean",
  248. "references": {}
  249. },
  250. "required": false,
  251. "optional": false,
  252. "docs": {
  253. "tags": [],
  254. "text": "When `true`, interaction is prevented and the component is displayed with lower opacity."
  255. },
  256. "attribute": "disabled",
  257. "reflect": true,
  258. "defaultValue": "false"
  259. },
  260. "icon": {
  261. "type": "string",
  262. "mutable": false,
  263. "complexType": {
  264. "original": "string",
  265. "resolved": "string",
  266. "references": {}
  267. },
  268. "required": false,
  269. "optional": true,
  270. "docs": {
  271. "tags": [],
  272. "text": "Specifies an icon to display."
  273. },
  274. "attribute": "icon",
  275. "reflect": false
  276. },
  277. "indicator": {
  278. "type": "boolean",
  279. "mutable": false,
  280. "complexType": {
  281. "original": "boolean",
  282. "resolved": "boolean",
  283. "references": {}
  284. },
  285. "required": false,
  286. "optional": false,
  287. "docs": {
  288. "tags": [],
  289. "text": "When `true`, indicates unread changes."
  290. },
  291. "attribute": "indicator",
  292. "reflect": true,
  293. "defaultValue": "false"
  294. },
  295. "intlLoading": {
  296. "type": "string",
  297. "mutable": false,
  298. "complexType": {
  299. "original": "string",
  300. "resolved": "string",
  301. "references": {}
  302. },
  303. "required": false,
  304. "optional": true,
  305. "docs": {
  306. "tags": [{
  307. "name": "default",
  308. "text": "\"Loading\""
  309. }],
  310. "text": "Specifies the text label to display while loading."
  311. },
  312. "attribute": "intl-loading",
  313. "reflect": false,
  314. "defaultValue": "TEXT.loading"
  315. },
  316. "label": {
  317. "type": "string",
  318. "mutable": false,
  319. "complexType": {
  320. "original": "string",
  321. "resolved": "string",
  322. "references": {}
  323. },
  324. "required": false,
  325. "optional": true,
  326. "docs": {
  327. "tags": [],
  328. "text": "Specifies the label of the component. If no label is provided, the label inherits what's provided for the `text` prop."
  329. },
  330. "attribute": "label",
  331. "reflect": false
  332. },
  333. "loading": {
  334. "type": "boolean",
  335. "mutable": false,
  336. "complexType": {
  337. "original": "boolean",
  338. "resolved": "boolean",
  339. "references": {}
  340. },
  341. "required": false,
  342. "optional": false,
  343. "docs": {
  344. "tags": [],
  345. "text": "When `true`, a busy indicator is displayed."
  346. },
  347. "attribute": "loading",
  348. "reflect": true,
  349. "defaultValue": "false"
  350. },
  351. "scale": {
  352. "type": "string",
  353. "mutable": false,
  354. "complexType": {
  355. "original": "Scale",
  356. "resolved": "\"l\" | \"m\" | \"s\"",
  357. "references": {
  358. "Scale": {
  359. "location": "import",
  360. "path": "../interfaces"
  361. }
  362. }
  363. },
  364. "required": false,
  365. "optional": false,
  366. "docs": {
  367. "tags": [],
  368. "text": "Specifies the size of the component."
  369. },
  370. "attribute": "scale",
  371. "reflect": true,
  372. "defaultValue": "\"m\""
  373. },
  374. "text": {
  375. "type": "string",
  376. "mutable": false,
  377. "complexType": {
  378. "original": "string",
  379. "resolved": "string",
  380. "references": {}
  381. },
  382. "required": true,
  383. "optional": false,
  384. "docs": {
  385. "tags": [],
  386. "text": "Specifies text that accompanies the icon."
  387. },
  388. "attribute": "text",
  389. "reflect": false
  390. },
  391. "textEnabled": {
  392. "type": "boolean",
  393. "mutable": false,
  394. "complexType": {
  395. "original": "boolean",
  396. "resolved": "boolean",
  397. "references": {}
  398. },
  399. "required": false,
  400. "optional": false,
  401. "docs": {
  402. "tags": [],
  403. "text": "Indicates whether the text is displayed."
  404. },
  405. "attribute": "text-enabled",
  406. "reflect": true,
  407. "defaultValue": "false"
  408. }
  409. };
  410. }
  411. static get events() {
  412. return [{
  413. "method": "calciteActionClick",
  414. "name": "calciteActionClick",
  415. "bubbles": true,
  416. "cancelable": false,
  417. "composed": true,
  418. "docs": {
  419. "tags": [{
  420. "name": "deprecated",
  421. "text": "use `onClick` instead."
  422. }],
  423. "text": "Emits when the component has been clicked."
  424. },
  425. "complexType": {
  426. "original": "void",
  427. "resolved": "void",
  428. "references": {}
  429. }
  430. }];
  431. }
  432. static get methods() {
  433. return {
  434. "setFocus": {
  435. "complexType": {
  436. "signature": "() => Promise<void>",
  437. "parameters": [],
  438. "references": {
  439. "Promise": {
  440. "location": "global"
  441. }
  442. },
  443. "return": "Promise<void>"
  444. },
  445. "docs": {
  446. "text": "Sets focus on the component.",
  447. "tags": []
  448. }
  449. }
  450. };
  451. }
  452. static get elementRef() { return "el"; }
  453. }