split-button.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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 { h } from "@stencil/core";
  7. import { CSS } from "./resources";
  8. import { updateHostInteraction } from "../../utils/interactive";
  9. /**
  10. * @slot - A slot for adding `calcite-dropdown` content.
  11. */
  12. export class SplitButton {
  13. constructor() {
  14. /** Specifies the appearance style of the component. */
  15. this.appearance = "solid";
  16. /** Specifies the color of the component. */
  17. this.color = "blue";
  18. /** When `true`, interaction is prevented and the component is displayed with lower opacity. */
  19. this.disabled = false;
  20. /**
  21. * When `true`, the component is active.
  22. *
  23. * @internal
  24. */
  25. this.active = false;
  26. /** Specifies the icon used for the dropdown menu. */
  27. this.dropdownIconType = "chevron";
  28. /**
  29. When `true`, a busy indicator is displayed on the primary button.
  30. */
  31. this.loading = false;
  32. /**
  33. * Determines the type of positioning to use for the overlaid content.
  34. *
  35. * Using `"absolute"` will work for most cases. The component will be positioned inside of overflowing parent containers and will affect the container's layout.
  36. *
  37. * `"fixed"` should be used to escape an overflowing parent container, or when the reference element's `position` CSS property is `"fixed"`.
  38. *
  39. */
  40. this.overlayPositioning = "absolute";
  41. /** Specifies the size of the component. */
  42. this.scale = "m";
  43. /** Specifies the width of the component. */
  44. this.width = "auto";
  45. this.calciteSplitButtonPrimaryClickHandler = (event) => this.calciteSplitButtonPrimaryClick.emit(event);
  46. this.calciteSplitButtonSecondaryClickHandler = (event) => this.calciteSplitButtonSecondaryClick.emit(event);
  47. }
  48. handleDisabledChange(value) {
  49. if (!value) {
  50. this.active = false;
  51. }
  52. }
  53. activeHandler() {
  54. if (this.disabled) {
  55. this.active = false;
  56. }
  57. }
  58. //--------------------------------------------------------------------------
  59. //
  60. // Lifecycle
  61. //
  62. //--------------------------------------------------------------------------
  63. componentDidRender() {
  64. updateHostInteraction(this);
  65. }
  66. render() {
  67. const widthClasses = {
  68. [CSS.container]: true,
  69. [CSS.widthAuto]: this.width === "auto",
  70. [CSS.widthHalf]: this.width === "half",
  71. [CSS.widthFull]: this.width === "full"
  72. };
  73. const buttonWidth = this.width === "auto" ? "auto" : "full";
  74. return (h("div", { class: widthClasses }, h("calcite-button", { appearance: this.appearance, color: this.color, disabled: this.disabled, "icon-end": this.primaryIconEnd ? this.primaryIconEnd : null, "icon-start": this.primaryIconStart ? this.primaryIconStart : null, iconFlipRtl: this.primaryIconFlipRtl ? this.primaryIconFlipRtl : null, label: this.primaryLabel, loading: this.loading, onClick: this.calciteSplitButtonPrimaryClickHandler, scale: this.scale, splitChild: "primary", type: "button", width: buttonWidth }, this.primaryText), h("div", { class: CSS.dividerContainer }, h("div", { class: CSS.divider })), h("calcite-dropdown", { active: this.active, disabled: this.disabled, onClick: this.calciteSplitButtonSecondaryClickHandler, overlayPositioning: this.overlayPositioning, placement: "bottom-end", scale: this.scale, width: this.scale }, h("calcite-button", { appearance: this.appearance, color: this.color, disabled: this.disabled, "icon-start": this.dropdownIcon, label: this.dropdownLabel, scale: this.scale, slot: "dropdown-trigger", splitChild: "secondary", type: "button" }), h("slot", null))));
  75. }
  76. get dropdownIcon() {
  77. return this.dropdownIconType === "chevron"
  78. ? "chevronDown"
  79. : this.dropdownIconType === "caret"
  80. ? "caretDown"
  81. : this.dropdownIconType === "ellipsis"
  82. ? "ellipsis"
  83. : "handle-vertical";
  84. }
  85. static get is() { return "calcite-split-button"; }
  86. static get encapsulation() { return "shadow"; }
  87. static get originalStyleUrls() {
  88. return {
  89. "$": ["split-button.scss"]
  90. };
  91. }
  92. static get styleUrls() {
  93. return {
  94. "$": ["split-button.css"]
  95. };
  96. }
  97. static get properties() {
  98. return {
  99. "appearance": {
  100. "type": "string",
  101. "mutable": false,
  102. "complexType": {
  103. "original": "ButtonAppearance",
  104. "resolved": "\"clear\" | \"minimal\" | \"outline\" | \"solid\" | \"transparent\"",
  105. "references": {
  106. "ButtonAppearance": {
  107. "location": "import",
  108. "path": "../button/interfaces"
  109. }
  110. }
  111. },
  112. "required": false,
  113. "optional": false,
  114. "docs": {
  115. "tags": [],
  116. "text": "Specifies the appearance style of the component."
  117. },
  118. "attribute": "appearance",
  119. "reflect": true,
  120. "defaultValue": "\"solid\""
  121. },
  122. "color": {
  123. "type": "string",
  124. "mutable": false,
  125. "complexType": {
  126. "original": "ButtonColor",
  127. "resolved": "\"blue\" | \"inverse\" | \"neutral\" | \"red\"",
  128. "references": {
  129. "ButtonColor": {
  130. "location": "import",
  131. "path": "../button/interfaces"
  132. }
  133. }
  134. },
  135. "required": false,
  136. "optional": false,
  137. "docs": {
  138. "tags": [],
  139. "text": "Specifies the color of the component."
  140. },
  141. "attribute": "color",
  142. "reflect": true,
  143. "defaultValue": "\"blue\""
  144. },
  145. "disabled": {
  146. "type": "boolean",
  147. "mutable": false,
  148. "complexType": {
  149. "original": "boolean",
  150. "resolved": "boolean",
  151. "references": {}
  152. },
  153. "required": false,
  154. "optional": false,
  155. "docs": {
  156. "tags": [],
  157. "text": "When `true`, interaction is prevented and the component is displayed with lower opacity."
  158. },
  159. "attribute": "disabled",
  160. "reflect": true,
  161. "defaultValue": "false"
  162. },
  163. "active": {
  164. "type": "boolean",
  165. "mutable": true,
  166. "complexType": {
  167. "original": "boolean",
  168. "resolved": "boolean",
  169. "references": {}
  170. },
  171. "required": false,
  172. "optional": false,
  173. "docs": {
  174. "tags": [{
  175. "name": "internal",
  176. "text": undefined
  177. }],
  178. "text": "When `true`, the component is active."
  179. },
  180. "attribute": "active",
  181. "reflect": true,
  182. "defaultValue": "false"
  183. },
  184. "dropdownIconType": {
  185. "type": "string",
  186. "mutable": false,
  187. "complexType": {
  188. "original": "DropdownIconType",
  189. "resolved": "\"caret\" | \"chevron\" | \"ellipsis\" | \"overflow\"",
  190. "references": {
  191. "DropdownIconType": {
  192. "location": "import",
  193. "path": "../button/interfaces"
  194. }
  195. }
  196. },
  197. "required": false,
  198. "optional": false,
  199. "docs": {
  200. "tags": [],
  201. "text": "Specifies the icon used for the dropdown menu."
  202. },
  203. "attribute": "dropdown-icon-type",
  204. "reflect": true,
  205. "defaultValue": "\"chevron\""
  206. },
  207. "dropdownLabel": {
  208. "type": "string",
  209. "mutable": false,
  210. "complexType": {
  211. "original": "string",
  212. "resolved": "string",
  213. "references": {}
  214. },
  215. "required": false,
  216. "optional": true,
  217. "docs": {
  218. "tags": [],
  219. "text": "Accessible name for the dropdown menu."
  220. },
  221. "attribute": "dropdown-label",
  222. "reflect": true
  223. },
  224. "loading": {
  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`, a busy indicator is displayed on the primary button."
  237. },
  238. "attribute": "loading",
  239. "reflect": true,
  240. "defaultValue": "false"
  241. },
  242. "overlayPositioning": {
  243. "type": "string",
  244. "mutable": false,
  245. "complexType": {
  246. "original": "OverlayPositioning",
  247. "resolved": "\"absolute\" | \"fixed\"",
  248. "references": {
  249. "OverlayPositioning": {
  250. "location": "import",
  251. "path": "../../utils/floating-ui"
  252. }
  253. }
  254. },
  255. "required": false,
  256. "optional": false,
  257. "docs": {
  258. "tags": [],
  259. "text": "Determines the type of positioning to use for the overlaid content.\n\nUsing `\"absolute\"` will work for most cases. The component will be positioned inside of overflowing parent containers and will affect the container's layout.\n\n`\"fixed\"` should be used to escape an overflowing parent container, or when the reference element's `position` CSS property is `\"fixed\"`."
  260. },
  261. "attribute": "overlay-positioning",
  262. "reflect": true,
  263. "defaultValue": "\"absolute\""
  264. },
  265. "primaryIconEnd": {
  266. "type": "string",
  267. "mutable": false,
  268. "complexType": {
  269. "original": "string",
  270. "resolved": "string",
  271. "references": {}
  272. },
  273. "required": false,
  274. "optional": true,
  275. "docs": {
  276. "tags": [],
  277. "text": "Specifies an icon to display at the end of the primary button."
  278. },
  279. "attribute": "primary-icon-end",
  280. "reflect": true
  281. },
  282. "primaryIconFlipRtl": {
  283. "type": "string",
  284. "mutable": false,
  285. "complexType": {
  286. "original": "FlipContext",
  287. "resolved": "\"both\" | \"end\" | \"start\"",
  288. "references": {
  289. "FlipContext": {
  290. "location": "import",
  291. "path": "../interfaces"
  292. }
  293. }
  294. },
  295. "required": false,
  296. "optional": true,
  297. "docs": {
  298. "tags": [],
  299. "text": "When `true`, the primary button icon will be flipped when the element direction is right-to-left (`\"rtl\"`)."
  300. },
  301. "attribute": "primary-icon-flip-rtl",
  302. "reflect": true
  303. },
  304. "primaryIconStart": {
  305. "type": "string",
  306. "mutable": false,
  307. "complexType": {
  308. "original": "string",
  309. "resolved": "string",
  310. "references": {}
  311. },
  312. "required": false,
  313. "optional": true,
  314. "docs": {
  315. "tags": [],
  316. "text": "Specifies an icon to display at the start of the primary button."
  317. },
  318. "attribute": "primary-icon-start",
  319. "reflect": true
  320. },
  321. "primaryLabel": {
  322. "type": "string",
  323. "mutable": false,
  324. "complexType": {
  325. "original": "string",
  326. "resolved": "string",
  327. "references": {}
  328. },
  329. "required": false,
  330. "optional": true,
  331. "docs": {
  332. "tags": [],
  333. "text": "Accessible name for the primary button."
  334. },
  335. "attribute": "primary-label",
  336. "reflect": true
  337. },
  338. "primaryText": {
  339. "type": "string",
  340. "mutable": false,
  341. "complexType": {
  342. "original": "string",
  343. "resolved": "string",
  344. "references": {}
  345. },
  346. "required": false,
  347. "optional": false,
  348. "docs": {
  349. "tags": [],
  350. "text": "Text displayed in the primary button."
  351. },
  352. "attribute": "primary-text",
  353. "reflect": true
  354. },
  355. "scale": {
  356. "type": "string",
  357. "mutable": false,
  358. "complexType": {
  359. "original": "Scale",
  360. "resolved": "\"l\" | \"m\" | \"s\"",
  361. "references": {
  362. "Scale": {
  363. "location": "import",
  364. "path": "../interfaces"
  365. }
  366. }
  367. },
  368. "required": false,
  369. "optional": false,
  370. "docs": {
  371. "tags": [],
  372. "text": "Specifies the size of the component."
  373. },
  374. "attribute": "scale",
  375. "reflect": true,
  376. "defaultValue": "\"m\""
  377. },
  378. "width": {
  379. "type": "string",
  380. "mutable": false,
  381. "complexType": {
  382. "original": "Width",
  383. "resolved": "\"auto\" | \"full\" | \"half\"",
  384. "references": {
  385. "Width": {
  386. "location": "import",
  387. "path": "../interfaces"
  388. }
  389. }
  390. },
  391. "required": false,
  392. "optional": false,
  393. "docs": {
  394. "tags": [],
  395. "text": "Specifies the width of the component."
  396. },
  397. "attribute": "width",
  398. "reflect": true,
  399. "defaultValue": "\"auto\""
  400. }
  401. };
  402. }
  403. static get events() {
  404. return [{
  405. "method": "calciteSplitButtonPrimaryClick",
  406. "name": "calciteSplitButtonPrimaryClick",
  407. "bubbles": true,
  408. "cancelable": false,
  409. "composed": true,
  410. "docs": {
  411. "tags": [],
  412. "text": "Fires when the primary button is clicked.\n\n**Note:** The event payload is deprecated, use separate mouse event listeners to get info about click."
  413. },
  414. "complexType": {
  415. "original": "DeprecatedEventPayload",
  416. "resolved": "any",
  417. "references": {
  418. "DeprecatedEventPayload": {
  419. "location": "import",
  420. "path": "../interfaces"
  421. }
  422. }
  423. }
  424. }, {
  425. "method": "calciteSplitButtonSecondaryClick",
  426. "name": "calciteSplitButtonSecondaryClick",
  427. "bubbles": true,
  428. "cancelable": false,
  429. "composed": true,
  430. "docs": {
  431. "tags": [],
  432. "text": "Fires when the dropdown menu is clicked.\n\n**Note:** The event payload is deprecated, use separate mouse event listeners to get info about click."
  433. },
  434. "complexType": {
  435. "original": "DeprecatedEventPayload",
  436. "resolved": "any",
  437. "references": {
  438. "DeprecatedEventPayload": {
  439. "location": "import",
  440. "path": "../interfaces"
  441. }
  442. }
  443. }
  444. }];
  445. }
  446. static get elementRef() { return "el"; }
  447. static get watchers() {
  448. return [{
  449. "propName": "disabled",
  450. "methodName": "handleDisabledChange"
  451. }, {
  452. "propName": "active",
  453. "methodName": "activeHandler"
  454. }];
  455. }
  456. }