q2-tecton-elements 1.9.6 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/cjs/{icons-077ed9b7.js → icons-fa5f4367.js} +22 -22
  2. package/dist/cjs/index-14348270.js +557 -0
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/q2-avatar.cjs.entry.js +1 -1
  5. package/dist/cjs/q2-btn_2.cjs.entry.js +7 -6
  6. package/dist/cjs/q2-calendar.cjs.entry.js +2 -2
  7. package/dist/cjs/q2-carousel-pane.cjs.entry.js +1 -1
  8. package/dist/cjs/q2-carousel.cjs.entry.js +1 -1
  9. package/dist/cjs/q2-checkbox-group.cjs.entry.js +2 -2
  10. package/dist/cjs/q2-checkbox.cjs.entry.js +1 -1
  11. package/dist/cjs/q2-dropdown-item.cjs.entry.js +1 -1
  12. package/dist/cjs/q2-dropdown.cjs.entry.js +2 -2
  13. package/dist/cjs/q2-editable-field.cjs.entry.js +1 -1
  14. package/dist/cjs/q2-icon.cjs.entry.js +23 -10
  15. package/dist/cjs/q2-input.cjs.entry.js +18 -5
  16. package/dist/cjs/q2-loc.cjs.entry.js +1 -1
  17. package/dist/cjs/q2-optgroup.cjs.entry.js +1 -1
  18. package/dist/cjs/q2-option.cjs.entry.js +43 -5
  19. package/dist/cjs/q2-radio-group.cjs.entry.js +1 -1
  20. package/dist/cjs/q2-radio.cjs.entry.js +1 -1
  21. package/dist/cjs/q2-section.cjs.entry.js +1 -1
  22. package/dist/cjs/q2-select.cjs.entry.js +104 -62
  23. package/dist/cjs/q2-stepper-pane.cjs.entry.js +27 -0
  24. package/dist/cjs/q2-stepper.cjs.entry.js +187 -0
  25. package/dist/cjs/q2-tab-container.cjs.entry.js +12 -464
  26. package/dist/cjs/q2-tecton-elements.cjs.js +1 -1
  27. package/dist/cjs/q2-textarea.cjs.entry.js +1 -1
  28. package/dist/collection/collection-manifest.json +2 -0
  29. package/dist/collection/components/q2-btn/index.js +6 -5
  30. package/dist/collection/components/q2-calendar/styles.css +18 -0
  31. package/dist/collection/components/q2-checkbox-group/styles.css +12 -2
  32. package/dist/collection/components/q2-dropdown/styles.css +18 -0
  33. package/dist/collection/components/q2-icon/icons.js +22 -22
  34. package/dist/collection/components/q2-icon/index.js +41 -9
  35. package/dist/collection/components/q2-icon/styles.css +33 -42
  36. package/dist/collection/components/q2-input/formatting/phone.js +8 -0
  37. package/dist/collection/components/q2-input/index.js +8 -3
  38. package/dist/collection/components/q2-input/styles.css +20 -125
  39. package/dist/collection/components/q2-option/index.js +104 -8
  40. package/dist/collection/components/q2-option/styles.css +31 -37
  41. package/dist/collection/components/q2-select/index.js +106 -62
  42. package/dist/collection/components/q2-select/styles.css +18 -0
  43. package/dist/collection/components/q2-stepper/index.js +283 -0
  44. package/dist/collection/components/q2-stepper/styles.css +253 -0
  45. package/dist/collection/components/q2-stepper-pane/index.js +76 -0
  46. package/dist/collection/components/q2-stepper-pane/styles.css +70 -0
  47. package/dist/collection/components/q2-tab-container/index.js +2 -9
  48. package/dist/collection/utils/index.js +23 -2
  49. package/dist/esm/{icons-5506a72c.js → icons-17612675.js} +22 -22
  50. package/dist/esm/index-da24669a.js +548 -0
  51. package/dist/esm/loader.js +1 -1
  52. package/dist/esm/q2-avatar.entry.js +1 -1
  53. package/dist/esm/q2-btn_2.entry.js +7 -6
  54. package/dist/esm/q2-calendar.entry.js +2 -2
  55. package/dist/esm/q2-carousel-pane.entry.js +1 -1
  56. package/dist/esm/q2-carousel.entry.js +1 -1
  57. package/dist/esm/q2-checkbox-group.entry.js +2 -2
  58. package/dist/esm/q2-checkbox.entry.js +1 -1
  59. package/dist/esm/q2-dropdown-item.entry.js +1 -1
  60. package/dist/esm/q2-dropdown.entry.js +2 -2
  61. package/dist/esm/q2-editable-field.entry.js +1 -1
  62. package/dist/esm/q2-icon.entry.js +23 -10
  63. package/dist/esm/q2-input.entry.js +18 -5
  64. package/dist/esm/q2-loc.entry.js +1 -1
  65. package/dist/esm/q2-optgroup.entry.js +1 -1
  66. package/dist/esm/q2-option.entry.js +44 -6
  67. package/dist/esm/q2-radio-group.entry.js +1 -1
  68. package/dist/esm/q2-radio.entry.js +1 -1
  69. package/dist/esm/q2-section.entry.js +1 -1
  70. package/dist/esm/q2-select.entry.js +104 -62
  71. package/dist/esm/q2-stepper-pane.entry.js +23 -0
  72. package/dist/esm/q2-stepper.entry.js +183 -0
  73. package/dist/esm/q2-tab-container.entry.js +2 -454
  74. package/dist/esm/q2-tecton-elements.js +1 -1
  75. package/dist/esm/q2-textarea.entry.js +1 -1
  76. package/dist/q2-tecton-elements/{p-f1ec7948.entry.js → p-2a28baa9.entry.js} +1 -1
  77. package/dist/q2-tecton-elements/p-2c2a5d58.entry.js +1 -0
  78. package/dist/q2-tecton-elements/{p-93799868.entry.js → p-2f2bbed9.entry.js} +3 -3
  79. package/dist/q2-tecton-elements/p-37d281b7.entry.js +1 -0
  80. package/dist/q2-tecton-elements/{p-dfe693e9.entry.js → p-3f2590c0.entry.js} +1 -1
  81. package/dist/q2-tecton-elements/p-4d283b84.entry.js +1 -0
  82. package/dist/q2-tecton-elements/p-5289f040.entry.js +1 -0
  83. package/dist/q2-tecton-elements/{p-f6d2fa2f.entry.js → p-576509e6.entry.js} +1 -1
  84. package/dist/q2-tecton-elements/{p-c6d4933e.entry.js → p-64eef8d1.entry.js} +1 -1
  85. package/dist/q2-tecton-elements/{p-89ae4f7b.entry.js → p-65894494.entry.js} +1 -1
  86. package/dist/q2-tecton-elements/p-6ed006a7.entry.js +1 -0
  87. package/dist/q2-tecton-elements/p-6f570344.js +1 -0
  88. package/dist/q2-tecton-elements/{p-0c23d50a.entry.js → p-7520656d.entry.js} +1 -1
  89. package/dist/q2-tecton-elements/p-7c06467f.entry.js +1 -0
  90. package/dist/q2-tecton-elements/{p-ccb8126f.entry.js → p-82b24667.entry.js} +1 -1
  91. package/dist/q2-tecton-elements/{p-ec245511.entry.js → p-86116f5c.entry.js} +1 -1
  92. package/dist/q2-tecton-elements/{p-ed433950.entry.js → p-891ca6f8.entry.js} +1 -1
  93. package/dist/q2-tecton-elements/p-8b4f6d3f.entry.js +1 -0
  94. package/dist/q2-tecton-elements/{p-0e9e5b53.entry.js → p-9b420e22.entry.js} +1 -1
  95. package/dist/q2-tecton-elements/p-aaa55918.js +1 -0
  96. package/dist/q2-tecton-elements/{p-915ce8d8.entry.js → p-c14e0622.entry.js} +1 -1
  97. package/dist/q2-tecton-elements/p-c92e3bc2.entry.js +1 -0
  98. package/dist/q2-tecton-elements/{p-7a952b02.entry.js → p-d0d605dc.entry.js} +1 -1
  99. package/dist/q2-tecton-elements/p-e3a27b97.entry.js +1 -0
  100. package/dist/q2-tecton-elements/{p-72f9686c.entry.js → p-ebee91e2.entry.js} +1 -1
  101. package/dist/q2-tecton-elements/q2-tecton-elements.esm.js +1 -1
  102. package/dist/types/components/q2-icon/index.d.ts +1 -0
  103. package/dist/types/components/q2-input/formatting/phone.d.ts +8 -0
  104. package/dist/types/components/q2-option/index.d.ts +9 -2
  105. package/dist/types/components/q2-select/index.d.ts +4 -1
  106. package/dist/types/components/q2-stepper/index.d.ts +33 -0
  107. package/dist/types/components/q2-stepper-pane/index.d.ts +9 -0
  108. package/dist/types/components.d.ts +46 -0
  109. package/dist/types/global.d.ts +1 -0
  110. package/dist/types/utils/index.d.ts +5 -2
  111. package/dist/types/workspace/workspace/{_tecton-production_release_1.9.x → tecton-production_release_1.10.x}/packages/q2-tecton-elements/.stencil/test/helpers.d.ts +0 -0
  112. package/package.json +2 -2
  113. package/dist/cjs/index-2dcb1a72.js +0 -99
  114. package/dist/esm/index-f3de8cee.js +0 -91
  115. package/dist/q2-tecton-elements/p-031a8f06.js +0 -1
  116. package/dist/q2-tecton-elements/p-044827e2.entry.js +0 -1
  117. package/dist/q2-tecton-elements/p-0feefe56.js +0 -1
  118. package/dist/q2-tecton-elements/p-1022a1c6.entry.js +0 -1
  119. package/dist/q2-tecton-elements/p-12f6dc10.entry.js +0 -1
  120. package/dist/q2-tecton-elements/p-5da60194.entry.js +0 -1
  121. package/dist/q2-tecton-elements/p-b0cb8867.entry.js +0 -1
  122. package/dist/q2-tecton-elements/p-d93abdce.entry.js +0 -1
  123. package/dist/q2-tecton-elements/p-e5e8eac3.entry.js +0 -1
@@ -19,7 +19,6 @@ export class Q2Select {
19
19
  lastPressedAt: new Date()
20
20
  };
21
21
  this.guid = createGuid();
22
- this.dropdownId = `q2-select-dropdown-${this.guid}`;
23
22
  this.onMutationObserved = () => {
24
23
  const slotContainer = this.hostElement.querySelector('.custom-display-content');
25
24
  const displaySlot = this.hostElement.shadowRoot.querySelector('slot[name="q2-select-display"]');
@@ -170,7 +169,13 @@ export class Q2Select {
170
169
  }
171
170
  getDefaultActiveIndex() {
172
171
  const firstSelected = this.optionElements.findIndex(element => element.selected);
173
- return firstSelected > -1 ? firstSelected : 0;
172
+ if (firstSelected > -1)
173
+ return firstSelected;
174
+ const firstEnabled = this.optionElements.findIndex(element => !element.hidden);
175
+ if (firstEnabled > -1)
176
+ return firstEnabled;
177
+ else
178
+ return 0;
174
179
  }
175
180
  setActiveOption() {
176
181
  if (!this.dropdownOpen) {
@@ -187,9 +192,9 @@ export class Q2Select {
187
192
  });
188
193
  }
189
194
  setFocusedOption() {
190
- const ele = this.optionElements[this.activeIndex].shadowRoot.querySelector('div');
191
- ele.dispatchEvent(new FocusEvent('focus'));
192
- ele.focus();
195
+ const option = this.optionElements[this.activeIndex];
196
+ option.dispatchEvent(new FocusEvent('focus'));
197
+ option.focus();
193
198
  }
194
199
  calculateMultiSelectSelectedDisplay() {
195
200
  if (this.selectedOptions.length === 1) {
@@ -218,7 +223,7 @@ export class Q2Select {
218
223
  get minPopHeight() {
219
224
  const { minRows } = this;
220
225
  const firstOption = this.hostElement.querySelector('q2-option:not([hidden])');
221
- const minHeight = window.getComputedStyle(firstOption.shadowRoot.querySelector('.q2-option-container')).minHeight;
226
+ const minHeight = window.getComputedStyle(firstOption).minHeight;
222
227
  return minRows * parseInt(minHeight);
223
228
  }
224
229
  get selectedDisplay() {
@@ -285,7 +290,7 @@ export class Q2Select {
285
290
  }
286
291
  scrollToActiveOption() {
287
292
  const activeOption = this.optionElements[this.activeIndex];
288
- activeOption && activeOption.scrollIntoView({ block: 'nearest' });
293
+ activeOption === null || activeOption === void 0 ? void 0 : activeOption.scrollIntoView({ block: 'nearest' });
289
294
  }
290
295
  openDropdownWithoutActiveElement() {
291
296
  this.activeIndex = undefined;
@@ -334,17 +339,13 @@ export class Q2Select {
334
339
  adjustActiveOptionAndScroll(numToAdd) {
335
340
  this.activeIndex += numToAdd;
336
341
  this.setActiveOption();
337
- if (!this.searchable) {
338
- this.setFocusedOption();
339
- }
342
+ this.setFocusedOption();
340
343
  this.scrollToActiveOption();
341
344
  }
342
345
  setDefaultActiveElement() {
343
346
  this.activeIndex = this.getDefaultActiveIndex();
344
347
  this.setActiveOption();
345
- if (!this.searchable) {
346
- this.setFocusedOption();
347
- }
348
+ this.setFocusedOption();
348
349
  }
349
350
  focusInput() {
350
351
  const input = this.hostElement.shadowRoot.querySelector('q2-input');
@@ -421,19 +422,34 @@ export class Q2Select {
421
422
  if (this.searchable && event.target === this.hostElement && !this.hostElement.oninput) {
422
423
  const options = this.optionElements;
423
424
  const query = event.detail.query.trim().toLowerCase();
425
+ let matchedCount = 0;
424
426
  options.forEach(option => {
425
427
  if (query === '') {
426
428
  option.style.display = '';
427
429
  }
428
430
  else {
429
- let { display = '', innerText = '' } = option;
430
- let matched = display.toLowerCase().includes(query) ||
431
+ const { display = '', innerText = '' } = option;
432
+ const matched = display.toLowerCase().includes(query) ||
431
433
  innerText.toLowerCase().includes(query);
432
- option.style.display = matched ? '' : 'none';
434
+ option.hidden = !matched;
435
+ if (matched)
436
+ matchedCount++;
433
437
  }
434
438
  });
439
+ let statusMessageLocString = query
440
+ ? 'tecton.element.select.searchable.results'
441
+ : 'tecton.element.select.allOptions';
442
+ const count = query ? matchedCount : options.length;
443
+ this.setStatusMessage(loc(statusMessageLocString, [count]));
435
444
  }
436
445
  }
446
+ setStatusMessage(message) {
447
+ clearTimeout(this.statusMessageTimer);
448
+ this.statusMessage = '';
449
+ this.statusMessageTimer = setTimeout(() => {
450
+ this.statusMessage = message;
451
+ }, 1000);
452
+ }
437
453
  clickHandler(event) {
438
454
  const target = event.target;
439
455
  if (target.localName !== 'q2-option' || target.disabled) {
@@ -442,86 +458,113 @@ export class Q2Select {
442
458
  this.selectOption(target.value);
443
459
  }
444
460
  keydownHandler(event) {
445
- if (event.key === 'Enter' && this.dropdownOpen) {
446
- event.preventDefault();
447
- const newOption = this.hostElement.querySelector(`[option-id="${this.activeOptionId}"]`);
448
- newOption && !newOption.disabled && this.selectOption(newOption.value);
449
- }
450
- else if (['ArrowUp', 'Up'].includes(event.key)) {
451
- event.preventDefault();
452
- if (this.dropdownOpen) {
453
- if (this.activeIndex > 0) {
461
+ event.stopPropagation();
462
+ const { dropdownOpen, activeIndex, searchable, multiple, optionElements } = this;
463
+ const { key, shiftKey } = event;
464
+ switch (key) {
465
+ case 'Enter':
466
+ if (!dropdownOpen)
467
+ break;
468
+ event.preventDefault();
469
+ const newOption = this.hostElement.querySelector(`[option-id="${this.activeOptionId}"]`);
470
+ if (newOption === null || newOption === void 0 ? void 0 : newOption.disabled)
471
+ break;
472
+ this.selectOption(newOption.value);
473
+ break;
474
+ case 'ArrowUp':
475
+ event.preventDefault();
476
+ if (!dropdownOpen) {
477
+ this.openDropdownWithActiveElement(this.getDefaultActiveIndex());
478
+ break;
479
+ }
480
+ if (activeIndex > 0) {
454
481
  const nextIndex = this.getNextVisibleIndex(-1);
455
482
  if (nextIndex > -1) {
456
- this.adjustActiveOptionAndScroll(nextIndex - this.activeIndex);
483
+ this.adjustActiveOptionAndScroll(nextIndex - activeIndex);
457
484
  }
458
485
  }
459
- else if (this.activeIndex !== 0) {
486
+ else if (activeIndex !== 0) {
460
487
  this.setDefaultActiveElement();
461
488
  }
462
- }
463
- else {
464
- this.openDropdownWithActiveElement(this.getDefaultActiveIndex());
465
- }
466
- }
467
- else if (['ArrowDown', 'Down'].includes(event.key)) {
468
- event.preventDefault();
469
- if (this.dropdownOpen) {
470
- if (this.activeIndex < this.optionElements.length - 1) {
489
+ break;
490
+ case 'ArrowDown':
491
+ event.preventDefault();
492
+ if (!dropdownOpen) {
493
+ this.openDropdownWithActiveElement(this.getDefaultActiveIndex());
494
+ break;
495
+ }
496
+ if (activeIndex < optionElements.length - 1) {
471
497
  const nextIndex = this.getNextVisibleIndex(1);
472
498
  if (nextIndex > -1) {
473
499
  this.adjustActiveOptionAndScroll(nextIndex - this.activeIndex);
474
500
  }
475
501
  }
476
- else if (!this.activeIndex) {
502
+ else if (!activeIndex) {
477
503
  this.setDefaultActiveElement();
478
504
  }
479
- }
480
- else {
481
- this.openDropdownWithActiveElement(this.getDefaultActiveIndex());
482
- }
483
- }
484
- else if (['Escape', 'Esc'].includes(event.key)) {
485
- this.closeDropdown();
486
- this.focusInput();
487
- }
488
- else if (event.key === 'Tab') {
489
- if (this.dropdownOpen && this.searchable && event.shiftKey) {
505
+ break;
506
+ case 'Home':
507
+ if (!dropdownOpen)
508
+ break;
490
509
  event.preventDefault();
510
+ this.adjustActiveOptionAndScroll(0);
511
+ break;
512
+ case 'End':
513
+ if (!dropdownOpen)
514
+ break;
515
+ event.preventDefault();
516
+ this.adjustActiveOptionAndScroll(optionElements.length - 1);
517
+ break;
518
+ case 'Escape':
519
+ this.closeDropdown();
491
520
  this.focusInput();
492
- }
493
- else {
494
- this.dropdownOpen && !this.multiple && event.preventDefault();
495
- }
496
- }
497
- else if (!this.searchable && event.key.match(/^[a-zA-Z0-9]$/)) {
498
- // search in non-searchable select: alpha-numeric only
499
- this.searchAndFocus(event.key);
521
+ break;
522
+ case 'Tab':
523
+ if (!dropdownOpen)
524
+ break;
525
+ if ((searchable && shiftKey) || !multiple) {
526
+ event.preventDefault();
527
+ }
528
+ if (searchable && shiftKey) {
529
+ this.focusInput();
530
+ }
531
+ break;
532
+ default:
533
+ if (searchable)
534
+ break;
535
+ if (!key.match(/^[A-Za-z0-9]$/))
536
+ break;
537
+ // search in non-searchable select: alpha-numeric only
538
+ this.searchAndFocus(key);
539
+ break;
500
540
  }
501
541
  }
502
542
  render() {
503
543
  return (h("click-elsewhere", { class: this.wrapperClasses, onChange: this.clickedElsewhere },
544
+ h("div", { "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage),
504
545
  h("q2-input", { ref: el => (this.inputField = el), class: "q2-select-input", label: (this.label && loc(this.label)) || '', value: this.selectedDisplay, errors: (Array.isArray(this.errors) &&
505
546
  this.errors.length > 0 &&
506
547
  this.errors.map(error => loc(error))) ||
507
548
  (this.invalid && ['tecton.element.select.invalid']) ||
508
- [], disabled: this.disabled, optional: this.optional, hideLabel: this.hideLabel, ariaExpanded: this.dropdownOpen, ariaOwns: this.dropdownId, ariaHaspopup: "listbox", role: this.searchable ? 'combobox' : null, pseudo: !this.searchable, "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: this.inputChangeHandler }),
549
+ [], disabled: this.disabled, optional: this.optional, hideLabel: this.hideLabel, ariaExpanded: this.dropdownOpen, ariaOwns: "dropdown", ariaHaspopup: "listbox", role: this.searchable ? 'combobox' : null, pseudo: !this.searchable, "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: this.inputChangeHandler }),
509
550
  h("div", { class: "custom-display-content", hidden: !this.hasCustomDisplay || !!this.searchText, onClick: this.onCustomDisplayClick },
510
551
  h("slot", { name: "q2-select-display" })),
511
552
  this.optionsDropdown()));
512
553
  }
513
554
  optionsDropdown() {
514
555
  const dropDirection = this.privatePopDirection === 'up' ? 'dropup' : '';
515
- return (h("div", { class: `q2-select-dropdown q2-element-dropdown ${dropDirection}`, ref: el => (this.dropdownContainer = el), role: "menu" },
556
+ return (h("div", { class: `q2-select-dropdown q2-element-dropdown ${dropDirection}`, ref: el => (this.dropdownContainer = el) },
516
557
  this.multiple ? this.visibilityToggle() : '',
517
- h("div", { class: "q2-select-options", id: this.dropdownId },
558
+ h("div", { class: "q2-select-options", id: "dropdown", role: "listbox" },
518
559
  h("slot", null))));
519
560
  }
520
561
  visibilityToggle() {
521
562
  return (h("div", { class: "multi-select-header" },
522
563
  loc('tecton.element.select.multiHeader.showing'),
523
- h("q2-btn", { class: `option-toggle show-all-options${this.onlyShowingSelected ? '' : ' selected'}`, badge: true, "test-id": "allOptionsButton", onClick: this.showAllOptions, onKeyDown: this.showAllOptionTabKeyDown }, loc('tecton.element.select.multiHeader.all')),
524
- h("q2-btn", { class: `option-toggle show-selected-options${this.onlyShowingSelected ? ' selected' : ''}`, disabled: this.selectedOptions.length === 0, badge: true, "test-id": "selectedOptionsButton", onClick: this.showSelectedOptions, onKeyDown: this.showSelectedOptionTabKeyDown }, loc('tecton.element.select.multiHeader.selected', [this.selectedOptionsCount]))));
564
+ h("q2-btn", { class: `option-toggle show-all-options${this.onlyShowingSelected ? '' : ' selected'}`, badge: true, "aria-selected": !this.onlyShowingSelected || undefined, "test-id": "allOptionsButton", onClick: this.showAllOptions, onKeyDown: this.showAllOptionTabKeyDown, label: loc('tecton.element.select.multiHeader.allAriaLabel'), "hide-label": true }, loc('tecton.element.select.multiHeader.all')),
565
+ h("q2-btn", { class: `option-toggle show-selected-options${this.onlyShowingSelected ? ' selected' : ''}`, "aria-selected": this.onlyShowingSelected || undefined, disabled: this.selectedOptions.length === 0, badge: true, "test-id": "selectedOptionsButton", onClick: this.showSelectedOptions, onKeyDown: this.showSelectedOptionTabKeyDown, label: loc('tecton.element.select.multiHeader.selectedAriaLabel', [
566
+ this.selectedOptionsCount
567
+ ]), "hide-label": true }, loc('tecton.element.select.multiHeader.selected', [this.selectedOptionsCount]))));
525
568
  }
526
569
  static get is() { return "q2-select"; }
527
570
  static get encapsulation() { return "shadow"; }
@@ -782,7 +825,8 @@ export class Q2Select {
782
825
  "activeOptionId": {},
783
826
  "searchText": {},
784
827
  "hasCustomDisplay": {},
785
- "inputFocused": {}
828
+ "inputFocused": {},
829
+ "statusMessage": {}
786
830
  }; }
787
831
  static get events() { return [{
788
832
  "method": "change",
@@ -80,6 +80,24 @@ button {
80
80
  visibility: hidden;
81
81
  transition: opacity var(--app-tween-1);
82
82
  border-radius: var(--tct-dropdown-element-br, 0);
83
+ --comp-scrollbar-size: var(--tct-scrollbar-size, var(--app-scale-1x, 5px));
84
+ --comp-scrollbar-border-radius: var(--tct-scrollbar-border-radius, var(--app-border-radius-1, 3px));
85
+ --comp-scrollbar-color: var(--tct-scrollbar-color, var(--t-a11y-gray-color, #747474));
86
+ scrollbar-width: thin;
87
+ scrollbar-color: var(--comp-scrollbar-color) transparent;
88
+ }
89
+ .q2-element-dropdown::-webkit-scrollbar {
90
+ width: var(--comp-scrollbar-size);
91
+ height: var(--comp-scrollbar-size);
92
+ margin: 5px;
93
+ }
94
+ .q2-element-dropdown::-webkit-scrollbar-thumb {
95
+ background: var(--comp-scrollbar-color);
96
+ border-radius: var(--comp-scrollbar-border-radius);
97
+ }
98
+ .q2-element-dropdown::-webkit-scrollbar-track {
99
+ background: transparent;
100
+ border-radius: var(--comp-scrollbar-border-radius);
83
101
  }
84
102
 
85
103
  .q2-element-dropdown.sizable {
@@ -0,0 +1,283 @@
1
+ import { Component, Prop, h, Element, State, Watch, Listen, Event, Fragment } from '@stencil/core';
2
+ import { loc, addSmoothScrollPolyfill } from 'src/utils';
3
+ addSmoothScrollPolyfill();
4
+ export class Q2Stepper {
5
+ constructor() {
6
+ this.currentStep = 1;
7
+ this.scrollEnabled = false;
8
+ this.showScrollLeft = false;
9
+ this.showScrollRight = false;
10
+ this.scheduledAfterRender = [];
11
+ ////////// EVENT HANDLERS ////////
12
+ this.onSlotChange = () => {
13
+ this.checkForPanes();
14
+ this.checkScrollState();
15
+ };
16
+ this.onScrollBtnClick = (direction) => {
17
+ const scrollAmount = Math.floor(this.listElement.clientWidth / 2);
18
+ this.listElement.scrollBy({
19
+ left: direction === 'left' ? -scrollAmount : scrollAmount,
20
+ behavior: 'smooth'
21
+ });
22
+ };
23
+ this.onStepClick = (event, selectedStep) => {
24
+ event.stopPropagation();
25
+ const { currentStep, stepCount, lastEnabledStep } = this;
26
+ if (selectedStep > lastEnabledStep || selectedStep === currentStep)
27
+ return;
28
+ this.change.emit({
29
+ selectedStep,
30
+ lastEnabledStep,
31
+ currentStep,
32
+ stepCount
33
+ });
34
+ };
35
+ this.onStepKeyDown = (event, stepNumber) => {
36
+ const { lastEnabledStep, stepCount } = this;
37
+ const { key } = event;
38
+ let selectedStep;
39
+ switch (key) {
40
+ case 'ArrowLeft':
41
+ event.preventDefault();
42
+ selectedStep = Math.max(stepNumber - 1, 0);
43
+ break;
44
+ case 'ArrowRight':
45
+ event.preventDefault();
46
+ selectedStep = Math.min(stepNumber + 1, stepCount);
47
+ break;
48
+ case 'Home':
49
+ event.preventDefault();
50
+ selectedStep = 1;
51
+ break;
52
+ case 'End':
53
+ event.preventDefault();
54
+ selectedStep = lastEnabledStep;
55
+ break;
56
+ }
57
+ if (!selectedStep)
58
+ return;
59
+ this.focusStep(selectedStep, true);
60
+ };
61
+ this.checkForPanes = () => {
62
+ const { allPanes } = this;
63
+ if (!allPanes.length)
64
+ return;
65
+ this.stepCount = allPanes.length;
66
+ };
67
+ this.checkScrollState = () => {
68
+ const { scrollLeft, scrollWidth, clientWidth } = this.listElement;
69
+ this.scrollEnabled = scrollWidth > clientWidth;
70
+ this.showScrollLeft = !!scrollLeft;
71
+ this.showScrollRight = scrollWidth !== scrollLeft + clientWidth;
72
+ };
73
+ }
74
+ ////////// LIFECYCLE HOOKS ////////
75
+ componentWillLoad() {
76
+ if (!this.lastEnabledStep)
77
+ this.lastEnabledStep = this.currentStep || 1;
78
+ this.resizeObserver = new ResizeObserver(() => this.checkScrollState());
79
+ this.checkForPanes();
80
+ }
81
+ componentDidLoad() {
82
+ this.resizeObserver.observe(this.listElement);
83
+ this.checkScrollState();
84
+ setTimeout(() => this.showStep(this.currentStep || 1), 0);
85
+ }
86
+ componentDidRender() {
87
+ this.scheduledAfterRender.forEach(fn => fn());
88
+ this.scheduledAfterRender = [];
89
+ }
90
+ disconnectedCallback() {
91
+ this.resizeObserver.disconnect();
92
+ }
93
+ ////////// WATCHER METHODS ////////
94
+ currentStepChanged(stepNumber) {
95
+ this.showStep(stepNumber);
96
+ }
97
+ ////////// HOST EVENTS ////////
98
+ defaultChangeHandler(event) {
99
+ const { hostElement } = this;
100
+ if (event.target === hostElement &&
101
+ !hostElement.getAttribute('onchange') &&
102
+ !!event.detail) {
103
+ this.currentStep = event.detail.selectedStep;
104
+ }
105
+ }
106
+ ////////// GETTER METHODS ////////
107
+ get allPanes() {
108
+ return this.hostElement.querySelectorAll('q2-stepper-pane');
109
+ }
110
+ ////////// HELPER METHODS ////////
111
+ showStep(stepNumber) {
112
+ if (stepNumber > this.lastEnabledStep) {
113
+ const { currentStep, stepCount } = this;
114
+ this.lastEnabledStep = stepNumber;
115
+ this.change.emit({
116
+ selectedStep: null,
117
+ lastEnabledStep: stepNumber,
118
+ currentStep,
119
+ stepCount
120
+ });
121
+ }
122
+ this.scheduledAfterRender.push(this.resizeIframe);
123
+ this.showStepPane(stepNumber);
124
+ this.focusStep(stepNumber, this.scrollEnabled);
125
+ }
126
+ resizeIframe() {
127
+ var _a;
128
+ return (_a = window === null || window === void 0 ? void 0 : window.TectonElements) === null || _a === void 0 ? void 0 : _a.resizeIframe();
129
+ }
130
+ showStepPane(stepNumber) {
131
+ this.allPanes.forEach((pane, index) => {
132
+ pane.isActive = stepNumber === index + 1;
133
+ });
134
+ }
135
+ focusStep(stepNumber, scrollIntoView) {
136
+ var _a;
137
+ const stepListItem = this.listElement.children[stepNumber - 1];
138
+ const isActive = document.activeElement === this.hostElement;
139
+ if (!stepListItem)
140
+ return;
141
+ if (isActive) {
142
+ (_a = stepListItem.firstElementChild) === null || _a === void 0 ? void 0 : _a.focus();
143
+ }
144
+ if (scrollIntoView) {
145
+ const left = stepListItem.offsetLeft - this.listElement.clientWidth / 2;
146
+ this.listElement.scrollTo({
147
+ left,
148
+ behavior: 'smooth'
149
+ });
150
+ }
151
+ }
152
+ ////////// RENDER METHODS ////////
153
+ renderStepBtn(stepIndex) {
154
+ var _a;
155
+ const { allPanes, stepCount, currentStep, lastEnabledStep } = this;
156
+ const { id, label, description } = (_a = allPanes === null || allPanes === void 0 ? void 0 : allPanes[stepIndex]) !== null && _a !== void 0 ? _a : {};
157
+ const stepNumber = stepIndex + 1;
158
+ const isCurrentStep = stepNumber === currentStep;
159
+ const labelId = label && `label-${id}`;
160
+ const descriptionId = label && description && `description-${id}`;
161
+ const btnLabel = !label && loc('tecton.element.stepper.number', [`${stepNumber}`, `${stepCount}`]);
162
+ return (h("li", { role: "presentation" },
163
+ h("button", { class: "step-btn", type: "button", "aria-labelledby": labelId, "aria-describedBy": descriptionId, "aria-label": btnLabel, "aria-selected": isCurrentStep, "aria-controls": id, "aria-disabled": stepNumber > lastEnabledStep ? 'true' : null, role: "tab", tabIndex: isCurrentStep ? 0 : -1, onKeyDown: ev => this.onStepKeyDown(ev, stepNumber), onClick: ev => this.onStepClick(ev, stepNumber) },
164
+ h("div", { class: "step-bubble" }, stepNumber),
165
+ label && (h(Fragment, null,
166
+ h("div", { class: "step-label", id: labelId }, loc(label)),
167
+ description && (h("div", { class: "step-description", id: descriptionId }, loc(description)))))),
168
+ stepIndex ? h("hr", null) : ''));
169
+ }
170
+ render() {
171
+ const { stepCount, scrollEnabled, showScrollLeft, showScrollRight } = this;
172
+ const containerClasses = ['step-container'];
173
+ if (scrollEnabled)
174
+ containerClasses.push('has-scroll');
175
+ return (h(Fragment, null,
176
+ h("div", { class: containerClasses.join(' ') },
177
+ scrollEnabled && (h(Fragment, null,
178
+ h("div", { class: "gradient-left", hidden: !showScrollLeft }),
179
+ h("div", { class: "gradient-right", hidden: !showScrollRight }),
180
+ h("q2-btn", { class: "btn-left", hidden: !this.showScrollLeft, onClick: () => this.onScrollBtnClick('left') },
181
+ h("q2-icon", { type: "chevron-left" })),
182
+ h("q2-btn", { class: "btn-right", hidden: !this.showScrollRight, onClick: () => this.onScrollBtnClick('right') },
183
+ h("q2-icon", { type: "chevron-right" })))),
184
+ h("ul", { onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))),
185
+ h("div", null,
186
+ h("slot", { onSlotchange: () => this.onSlotChange() }))));
187
+ }
188
+ static get is() { return "q2-stepper"; }
189
+ static get encapsulation() { return "shadow"; }
190
+ static get originalStyleUrls() { return {
191
+ "$": ["styles.scss"]
192
+ }; }
193
+ static get styleUrls() { return {
194
+ "$": ["styles.css"]
195
+ }; }
196
+ static get properties() { return {
197
+ "currentStep": {
198
+ "type": "number",
199
+ "mutable": true,
200
+ "complexType": {
201
+ "original": "number",
202
+ "resolved": "number",
203
+ "references": {}
204
+ },
205
+ "required": false,
206
+ "optional": false,
207
+ "docs": {
208
+ "tags": [],
209
+ "text": ""
210
+ },
211
+ "attribute": "current-step",
212
+ "reflect": true,
213
+ "defaultValue": "1"
214
+ },
215
+ "stepCount": {
216
+ "type": "number",
217
+ "mutable": true,
218
+ "complexType": {
219
+ "original": "number",
220
+ "resolved": "number",
221
+ "references": {}
222
+ },
223
+ "required": false,
224
+ "optional": false,
225
+ "docs": {
226
+ "tags": [],
227
+ "text": ""
228
+ },
229
+ "attribute": "step-count",
230
+ "reflect": false
231
+ },
232
+ "lastEnabledStep": {
233
+ "type": "number",
234
+ "mutable": true,
235
+ "complexType": {
236
+ "original": "number",
237
+ "resolved": "number",
238
+ "references": {}
239
+ },
240
+ "required": false,
241
+ "optional": false,
242
+ "docs": {
243
+ "tags": [],
244
+ "text": ""
245
+ },
246
+ "attribute": "last-enabled-step",
247
+ "reflect": false
248
+ }
249
+ }; }
250
+ static get states() { return {
251
+ "scrollEnabled": {},
252
+ "showScrollLeft": {},
253
+ "showScrollRight": {}
254
+ }; }
255
+ static get events() { return [{
256
+ "method": "change",
257
+ "name": "change",
258
+ "bubbles": true,
259
+ "cancelable": true,
260
+ "composed": true,
261
+ "docs": {
262
+ "tags": [],
263
+ "text": ""
264
+ },
265
+ "complexType": {
266
+ "original": "any",
267
+ "resolved": "any",
268
+ "references": {}
269
+ }
270
+ }]; }
271
+ static get elementRef() { return "hostElement"; }
272
+ static get watchers() { return [{
273
+ "propName": "currentStep",
274
+ "methodName": "currentStepChanged"
275
+ }]; }
276
+ static get listeners() { return [{
277
+ "name": "change",
278
+ "method": "defaultChangeHandler",
279
+ "target": undefined,
280
+ "capture": false,
281
+ "passive": false
282
+ }]; }
283
+ }