calcite-stepper.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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 { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
  7. const stepperCss = "@-webkit-keyframes in{0%{opacity:0}100%{opacity:1}}@keyframes in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes in-down{0%{opacity:0;-webkit-transform:translate3D(0, -5px, 0);transform:translate3D(0, -5px, 0)}100%{opacity:1;-webkit-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)}}@keyframes in-down{0%{opacity:0;-webkit-transform:translate3D(0, -5px, 0);transform:translate3D(0, -5px, 0)}100%{opacity:1;-webkit-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)}}@-webkit-keyframes in-up{0%{opacity:0;-webkit-transform:translate3D(0, 5px, 0);transform:translate3D(0, 5px, 0)}100%{opacity:1;-webkit-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)}}@keyframes in-up{0%{opacity:0;-webkit-transform:translate3D(0, 5px, 0);transform:translate3D(0, 5px, 0)}100%{opacity:1;-webkit-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)}}@-webkit-keyframes in-scale{0%{opacity:0;-webkit-transform:scale3D(0.95, 0.95, 1);transform:scale3D(0.95, 0.95, 1)}100%{opacity:1;-webkit-transform:scale3D(1, 1, 1);transform:scale3D(1, 1, 1)}}@keyframes in-scale{0%{opacity:0;-webkit-transform:scale3D(0.95, 0.95, 1);transform:scale3D(0.95, 0.95, 1)}100%{opacity:1;-webkit-transform:scale3D(1, 1, 1);transform:scale3D(1, 1, 1)}}:root{--calcite-animation-timing:calc(150ms * var(--calcite-internal-duration-factor));--calcite-internal-duration-factor:var(--calcite-duration-factor, 1);--calcite-internal-animation-timing-fast:calc(100ms * var(--calcite-internal-duration-factor));--calcite-internal-animation-timing-medium:calc(200ms * var(--calcite-internal-duration-factor));--calcite-internal-animation-timing-slow:calc(300ms * var(--calcite-internal-duration-factor))}.calcite-animate{opacity:0;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:var(--calcite-animation-timing);animation-duration:var(--calcite-animation-timing)}.calcite-animate__in{-webkit-animation-name:in;animation-name:in}.calcite-animate__in-down{-webkit-animation-name:in-down;animation-name:in-down}.calcite-animate__in-up{-webkit-animation-name:in-up;animation-name:in-up}.calcite-animate__in-scale{-webkit-animation-name:in-scale;animation-name:in-scale}:root{--calcite-popper-transition:var(--calcite-animation-timing)}:host([hidden]){display:none}:host{position:relative;display:-ms-flexbox;display:flex;width:100%;min-width:100%;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:justify;justify-content:space-between}:host([layout=vertical]){-ms-flex:1 1 auto;flex:1 1 auto;-ms-flex-direction:column;flex-direction:column}:host ::slotted(.calcite-stepper-content){display:-ms-flexbox;display:flex;width:100%;min-width:100%;-ms-flex-direction:column;flex-direction:column;-ms-flex-wrap:wrap;flex-wrap:wrap}";
  8. const Stepper = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
  9. constructor() {
  10. super();
  11. this.__registerHost();
  12. this.__attachShadow();
  13. this.calciteStepperItemChange = createEvent(this, "calciteStepperItemChange", 7);
  14. //--------------------------------------------------------------------------
  15. //
  16. // Public Properties
  17. //
  18. //--------------------------------------------------------------------------
  19. /** optionally display a status icon next to the step title */
  20. this.icon = false;
  21. /** specify the layout of stepper, defaults to horizontal */
  22. this.layout = "horizontal";
  23. /** optionally display the number next to the step title */
  24. this.numbered = false;
  25. /** specify the scale of stepper, defaults to m */
  26. this.scale = "m";
  27. //--------------------------------------------------------------------------
  28. //
  29. // Private State/Props
  30. //
  31. //--------------------------------------------------------------------------
  32. this.itemMap = new Map();
  33. /** list of sorted Stepper items */
  34. this.items = [];
  35. /** list of enabled Stepper items */
  36. this.enabledItems = [];
  37. }
  38. // watch for removal of disabled to register step
  39. contentWatcher() {
  40. if (this.layout === "horizontal") {
  41. if (!this.stepperContentContainer && this.requestedContent) {
  42. this.addHorizontalContentContainer();
  43. }
  44. this.updateContent(this.requestedContent);
  45. }
  46. }
  47. //--------------------------------------------------------------------------
  48. //
  49. // Lifecycle
  50. //
  51. //--------------------------------------------------------------------------
  52. componentDidLoad() {
  53. // if no stepper items are set as active, default to the first one
  54. if (!this.currentPosition) {
  55. this.calciteStepperItemChange.emit({
  56. position: 0
  57. });
  58. }
  59. }
  60. componentWillLoad() {
  61. if (this.layout === "horizontal" && !this.stepperContentContainer) {
  62. this.addHorizontalContentContainer();
  63. }
  64. }
  65. render() {
  66. return h("slot", null);
  67. }
  68. //--------------------------------------------------------------------------
  69. //
  70. // Event Listeners
  71. //
  72. //--------------------------------------------------------------------------
  73. calciteStepperItemKeyEvent(e) {
  74. const item = e.detail.item;
  75. const itemToFocus = e.target;
  76. const isFirstItem = this.itemIndex(itemToFocus) === 0;
  77. const isLastItem = this.itemIndex(itemToFocus) === this.enabledItems.length - 1;
  78. switch (item.key) {
  79. case "ArrowDown":
  80. case "ArrowRight":
  81. if (isLastItem) {
  82. this.focusFirstItem();
  83. }
  84. else {
  85. this.focusNextItem(itemToFocus);
  86. }
  87. break;
  88. case "ArrowUp":
  89. case "ArrowLeft":
  90. if (isFirstItem) {
  91. this.focusLastItem();
  92. }
  93. else {
  94. this.focusPrevItem(itemToFocus);
  95. }
  96. break;
  97. case "Home":
  98. this.focusFirstItem();
  99. break;
  100. case "End":
  101. this.focusLastItem();
  102. break;
  103. }
  104. }
  105. registerItem(event) {
  106. const item = event.target;
  107. const { content, position } = event.detail;
  108. if (content && item.active) {
  109. this.requestedContent = content;
  110. }
  111. this.itemMap.set(item, position);
  112. this.items = this.sortItems();
  113. this.enabledItems = this.filterItems();
  114. }
  115. updateItem(event) {
  116. if (event.detail.content) {
  117. this.requestedContent = event.detail.content;
  118. }
  119. this.currentPosition = event.detail.position;
  120. this.calciteStepperItemChange.emit({
  121. position: this.currentPosition
  122. });
  123. }
  124. //--------------------------------------------------------------------------
  125. //
  126. // Public Methods
  127. //
  128. //--------------------------------------------------------------------------
  129. /** set the next step as active */
  130. async nextStep() {
  131. const enabledStepIndex = this.getEnabledStepIndex(this.currentPosition + 1, "next");
  132. if (typeof enabledStepIndex !== "number") {
  133. return;
  134. }
  135. this.emitChangedItem(enabledStepIndex);
  136. }
  137. /** set the previous step as active */
  138. async prevStep() {
  139. const enabledStepIndex = this.getEnabledStepIndex(this.currentPosition - 1, "previous");
  140. if (typeof enabledStepIndex !== "number") {
  141. return;
  142. }
  143. this.emitChangedItem(enabledStepIndex);
  144. }
  145. /** set the requested step as active */
  146. async goToStep(step) {
  147. const position = step - 1;
  148. if (this.currentPosition !== position) {
  149. this.emitChangedItem(position);
  150. }
  151. }
  152. /** set the first step as active */
  153. async startStep() {
  154. const enabledStepIndex = this.getEnabledStepIndex(0, "next");
  155. if (typeof enabledStepIndex !== "number") {
  156. return;
  157. }
  158. this.emitChangedItem(enabledStepIndex);
  159. }
  160. /** set the last step as active */
  161. async endStep() {
  162. const enabledStepIndex = this.getEnabledStepIndex(this.items.length - 1, "previous");
  163. if (typeof enabledStepIndex !== "number") {
  164. return;
  165. }
  166. this.emitChangedItem(enabledStepIndex);
  167. }
  168. //--------------------------------------------------------------------------
  169. //
  170. // Private Methods
  171. //
  172. //--------------------------------------------------------------------------
  173. getEnabledStepIndex(startIndex, direction = "next") {
  174. var _a;
  175. const { items, currentPosition } = this;
  176. let newIndex = startIndex;
  177. while ((_a = items[newIndex]) === null || _a === void 0 ? void 0 : _a.disabled) {
  178. newIndex = newIndex + (direction === "previous" ? -1 : 1);
  179. }
  180. return newIndex !== currentPosition && newIndex < items.length && newIndex >= 0
  181. ? newIndex
  182. : null;
  183. }
  184. addHorizontalContentContainer() {
  185. this.stepperContentContainer = document.createElement("div");
  186. this.stepperContentContainer.classList.add("calcite-stepper-content");
  187. this.el.insertAdjacentElement("beforeend", this.stepperContentContainer);
  188. }
  189. emitChangedItem(position) {
  190. this.currentPosition = position;
  191. this.calciteStepperItemChange.emit({
  192. position
  193. });
  194. }
  195. focusFirstItem() {
  196. const firstItem = this.enabledItems[0];
  197. this.focusElement(firstItem);
  198. }
  199. focusLastItem() {
  200. const lastItem = this.enabledItems[this.enabledItems.length - 1];
  201. this.focusElement(lastItem);
  202. }
  203. focusNextItem(e) {
  204. const index = this.itemIndex(e);
  205. const nextItem = this.enabledItems[index + 1] || this.enabledItems[0];
  206. this.focusElement(nextItem);
  207. }
  208. focusPrevItem(e) {
  209. const index = this.itemIndex(e);
  210. const prevItem = this.enabledItems[index - 1] || this.enabledItems[this.enabledItems.length - 1];
  211. this.focusElement(prevItem);
  212. }
  213. itemIndex(e) {
  214. return this.enabledItems.indexOf(e);
  215. }
  216. focusElement(item) {
  217. item.focus();
  218. }
  219. sortItems() {
  220. const { itemMap } = this;
  221. return Array.from(itemMap.keys()).sort((a, b) => itemMap.get(a) - itemMap.get(b));
  222. }
  223. filterItems() {
  224. return this.items.filter((item) => !item.disabled);
  225. }
  226. updateContent(content) {
  227. this.stepperContentContainer.innerHTML = "";
  228. this.stepperContentContainer.append(...content);
  229. }
  230. get el() { return this; }
  231. static get watchers() { return {
  232. "requestedContent": ["contentWatcher"]
  233. }; }
  234. static get style() { return stepperCss; }
  235. }, [1, "calcite-stepper", {
  236. "icon": [516],
  237. "layout": [513],
  238. "numbered": [516],
  239. "scale": [513],
  240. "requestedContent": [1040],
  241. "nextStep": [64],
  242. "prevStep": [64],
  243. "goToStep": [64],
  244. "startStep": [64],
  245. "endStep": [64]
  246. }, [[0, "calciteStepperItemKeyEvent", "calciteStepperItemKeyEvent"], [0, "calciteStepperItemRegister", "registerItem"], [0, "calciteStepperItemSelect", "updateItem"]]]);
  247. function defineCustomElement$1() {
  248. if (typeof customElements === "undefined") {
  249. return;
  250. }
  251. const components = ["calcite-stepper"];
  252. components.forEach(tagName => { switch (tagName) {
  253. case "calcite-stepper":
  254. if (!customElements.get(tagName)) {
  255. customElements.define(tagName, Stepper);
  256. }
  257. break;
  258. } });
  259. }
  260. defineCustomElement$1();
  261. const CalciteStepper = Stepper;
  262. const defineCustomElement = defineCustomElement$1;
  263. export { CalciteStepper, defineCustomElement };