flow.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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 { Component, Element, Listen, Method, State, h } from "@stencil/core";
  7. import { CSS } from "./resources";
  8. import { createObserver } from "../../utils/observers";
  9. /**
  10. * @slot - A slot for adding `calcite-panel`s to the flow.
  11. */
  12. export class Flow {
  13. constructor() {
  14. this.panelCount = 0;
  15. this.flowDirection = null;
  16. this.panels = [];
  17. this.getFlowDirection = (oldPanelCount, newPanelCount) => {
  18. const allowRetreatingDirection = oldPanelCount > 1;
  19. const allowAdvancingDirection = oldPanelCount && newPanelCount > 1;
  20. if (!allowAdvancingDirection && !allowRetreatingDirection) {
  21. return null;
  22. }
  23. return newPanelCount < oldPanelCount ? "retreating" : "advancing";
  24. };
  25. this.updateFlowProps = () => {
  26. const { panels } = this;
  27. const newPanels = Array.from(this.el.querySelectorAll("calcite-panel"));
  28. const oldPanelCount = panels.length;
  29. const newPanelCount = newPanels.length;
  30. const activePanel = newPanels[newPanelCount - 1];
  31. const previousPanel = newPanels[newPanelCount - 2];
  32. if (newPanelCount && activePanel) {
  33. newPanels.forEach((panelNode) => {
  34. panelNode.showBackButton = newPanelCount > 1;
  35. panelNode.hidden = panelNode !== activePanel;
  36. });
  37. }
  38. if (previousPanel) {
  39. previousPanel.menuOpen = false;
  40. }
  41. this.panels = newPanels;
  42. if (oldPanelCount !== newPanelCount) {
  43. const flowDirection = this.getFlowDirection(oldPanelCount, newPanelCount);
  44. this.panelCount = newPanelCount;
  45. this.flowDirection = flowDirection;
  46. }
  47. };
  48. this.panelItemMutationObserver = createObserver("mutation", this.updateFlowProps);
  49. }
  50. // --------------------------------------------------------------------------
  51. //
  52. // Public Methods
  53. //
  54. // --------------------------------------------------------------------------
  55. /**
  56. * Removes the currently active `calcite-panel`.
  57. */
  58. async back() {
  59. const lastItem = this.el.querySelector("calcite-panel:last-child");
  60. if (!lastItem) {
  61. return;
  62. }
  63. const beforeBack = lastItem.beforeBack
  64. ? lastItem.beforeBack
  65. : () => Promise.resolve();
  66. return beforeBack.call(lastItem).then(() => {
  67. lastItem.remove();
  68. return lastItem;
  69. });
  70. }
  71. // --------------------------------------------------------------------------
  72. //
  73. // Lifecycle
  74. //
  75. // --------------------------------------------------------------------------
  76. connectedCallback() {
  77. var _a;
  78. (_a = this.panelItemMutationObserver) === null || _a === void 0 ? void 0 : _a.observe(this.el, { childList: true, subtree: true });
  79. this.updateFlowProps();
  80. }
  81. disconnectedCallback() {
  82. var _a;
  83. (_a = this.panelItemMutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
  84. }
  85. // --------------------------------------------------------------------------
  86. //
  87. // Private Methods
  88. //
  89. // --------------------------------------------------------------------------
  90. handleCalcitePanelBackClick() {
  91. this.back();
  92. }
  93. // --------------------------------------------------------------------------
  94. //
  95. // Render Methods
  96. //
  97. // --------------------------------------------------------------------------
  98. render() {
  99. const { flowDirection, panelCount } = this;
  100. const frameDirectionClasses = {
  101. [CSS.frame]: true,
  102. [CSS.frameAdvancing]: flowDirection === "advancing",
  103. [CSS.frameRetreating]: flowDirection === "retreating"
  104. };
  105. return (h("div", { class: frameDirectionClasses, key: panelCount },
  106. h("slot", null)));
  107. }
  108. static get is() { return "calcite-flow"; }
  109. static get encapsulation() { return "shadow"; }
  110. static get originalStyleUrls() { return {
  111. "$": ["flow.scss"]
  112. }; }
  113. static get styleUrls() { return {
  114. "$": ["flow.css"]
  115. }; }
  116. static get states() { return {
  117. "panelCount": {},
  118. "flowDirection": {},
  119. "panels": {}
  120. }; }
  121. static get methods() { return {
  122. "back": {
  123. "complexType": {
  124. "signature": "() => Promise<HTMLCalcitePanelElement>",
  125. "parameters": [],
  126. "references": {
  127. "Promise": {
  128. "location": "global"
  129. },
  130. "HTMLCalcitePanelElement": {
  131. "location": "global"
  132. }
  133. },
  134. "return": "Promise<HTMLCalcitePanelElement>"
  135. },
  136. "docs": {
  137. "text": "Removes the currently active `calcite-panel`.",
  138. "tags": []
  139. }
  140. }
  141. }; }
  142. static get elementRef() { return "el"; }
  143. static get listeners() { return [{
  144. "name": "calcitePanelBackClick",
  145. "method": "handleCalcitePanelBackClick",
  146. "target": undefined,
  147. "capture": false,
  148. "passive": false
  149. }]; }
  150. }