q2-tecton-elements 1.69.1 → 1.70.0

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 (273) hide show
  1. package/dist/bundle-report.json +2246 -355
  2. package/dist/cjs/click-elsewhere_3.cjs.entry.js +2 -2
  3. package/dist/cjs/{index-D2LFCsNP.js → index-SpDCZABA.js} +2 -2
  4. package/dist/cjs/loader.cjs.js +1 -1
  5. package/dist/cjs/q2-action-group_2.cjs.entry.js +1 -1
  6. package/dist/cjs/q2-action-sheet.cjs.entry.js +2 -2
  7. package/dist/cjs/q2-badge_2.cjs.entry.js +11 -4
  8. package/dist/cjs/q2-btn_2.cjs.entry.js +6 -2
  9. package/dist/cjs/q2-calendar.cjs.entry.js +5 -3
  10. package/dist/cjs/q2-card-image.cjs.entry.js +8 -6
  11. package/dist/cjs/q2-card.cjs.entry.js +2 -2
  12. package/dist/cjs/q2-carousel-pane.cjs.entry.js +1 -1
  13. package/dist/cjs/q2-carousel.cjs.entry.js +1 -1
  14. package/dist/cjs/q2-chart-area.cjs.entry.js +1 -1
  15. package/dist/cjs/q2-chart-bar.cjs.entry.js +1 -1
  16. package/dist/cjs/q2-chart-donut.cjs.entry.js +2 -2
  17. package/dist/cjs/q2-checkbox-group.cjs.entry.js +1 -1
  18. package/dist/cjs/q2-checkbox_2.cjs.entry.js +4 -3
  19. package/dist/cjs/q2-context.cjs.entry.js +1 -1
  20. package/dist/cjs/q2-currency.cjs.entry.js +1 -1
  21. package/dist/cjs/q2-data-table.cjs.entry.js +6 -3
  22. package/dist/cjs/q2-detail.cjs.entry.js +2 -2
  23. package/dist/cjs/q2-dropdown-item.cjs.entry.js +1 -1
  24. package/dist/cjs/q2-dropdown.cjs.entry.js +3 -3
  25. package/dist/cjs/q2-editable-field.cjs.entry.js +12 -4
  26. package/dist/cjs/q2-file-picker.cjs.entry.js +1 -1
  27. package/dist/cjs/q2-icon.cjs.entry.js +1 -1
  28. package/dist/cjs/q2-item.cjs.entry.js +2 -2
  29. package/dist/cjs/q2-legend.cjs.entry.js +1 -1
  30. package/dist/cjs/q2-link_2.cjs.entry.js +2 -2
  31. package/dist/cjs/q2-loc.cjs.entry.js +20 -2
  32. package/dist/cjs/q2-message.cjs.entry.js +1 -1
  33. package/dist/cjs/q2-meter.cjs.entry.js +2 -2
  34. package/dist/cjs/q2-modal.cjs.entry.js +3 -3
  35. package/dist/cjs/q2-month-picker.cjs.entry.js +1 -1
  36. package/dist/cjs/q2-optgroup.cjs.entry.js +1 -1
  37. package/dist/cjs/q2-option.cjs.entry.js +1 -1
  38. package/dist/cjs/q2-otp.cjs.entry.js +1 -1
  39. package/dist/cjs/q2-pagination.cjs.entry.js +1 -1
  40. package/dist/cjs/q2-pill.cjs.entry.js +1 -1
  41. package/dist/cjs/q2-radio-group.cjs.entry.js +1 -1
  42. package/dist/cjs/q2-radio.cjs.entry.js +1 -1
  43. package/dist/cjs/q2-relative-time.cjs.entry.js +1 -1
  44. package/dist/cjs/q2-search.cjs.entry.js +101 -12
  45. package/dist/cjs/q2-section.cjs.entry.js +2 -2
  46. package/dist/cjs/q2-select.cjs.entry.js +36 -6
  47. package/dist/cjs/q2-stepper-pane.cjs.entry.js +1 -1
  48. package/dist/cjs/q2-stepper-vertical.cjs.entry.js +24 -18
  49. package/dist/cjs/q2-stepper.cjs.entry.js +5 -4
  50. package/dist/cjs/q2-surface.cjs.entry.js +95 -0
  51. package/dist/cjs/q2-tab-container.cjs.entry.js +2 -2
  52. package/dist/cjs/q2-tab-pane.cjs.entry.js +1 -1
  53. package/dist/cjs/q2-tecton-elements.cjs.js +1 -1
  54. package/dist/cjs/q2-textarea.cjs.entry.js +1 -1
  55. package/dist/cjs/q2-toast.cjs.entry.js +1 -1
  56. package/dist/cjs/q2-tooltip.cjs.entry.js +1 -1
  57. package/dist/cjs/tecton-tab-pane.cjs.entry.js +2 -2
  58. package/dist/collection/collection-manifest.json +1 -0
  59. package/dist/collection/components/q2-action-sheet/q2-action-sheet.css +1 -1
  60. package/dist/collection/components/q2-btn/q2-btn.css +32 -17
  61. package/dist/collection/components/q2-btn/q2-btn.js +6 -1
  62. package/dist/collection/components/q2-calendar/q2-calendar.js +24 -2
  63. package/dist/collection/components/q2-calendar/test/q2-calendar-test.vr.js +4 -0
  64. package/dist/collection/components/q2-card/q2-card.css +2 -2
  65. package/dist/collection/components/q2-card-image/q2-card-image.css +3 -0
  66. package/dist/collection/components/q2-card-image/q2-card-image.js +25 -23
  67. package/dist/collection/components/q2-chart-area/q2-chart-area.css +4 -0
  68. package/dist/collection/components/q2-chart-bar/q2-chart-bar.css +4 -0
  69. package/dist/collection/components/q2-chart-donut/q2-chart-donut.css +1 -1
  70. package/dist/collection/components/q2-checkbox/q2-checkbox.js +2 -1
  71. package/dist/collection/components/q2-currency/q2-currency.css +1 -1
  72. package/dist/collection/components/q2-data-table/q2-data-table.js +5 -2
  73. package/dist/collection/components/q2-detail/q2-detail.css +12 -12
  74. package/dist/collection/components/q2-dropdown/q2-dropdown.js +2 -2
  75. package/dist/collection/components/q2-editable-field/q2-editable-field.js +11 -3
  76. package/dist/collection/components/q2-input/q2-input.css +11 -1
  77. package/dist/collection/components/q2-input/q2-input.js +29 -2
  78. package/dist/collection/components/q2-input/test/q2-input-test.vr.js +8 -0
  79. package/dist/collection/components/q2-item/q2-item.css +10 -5
  80. package/dist/collection/components/q2-item/test/q2-item-test.vr.js +132 -0
  81. package/dist/collection/components/q2-legend/q2-legend.css +2 -2
  82. package/dist/collection/components/q2-list/q2-list.css +1 -1
  83. package/dist/collection/components/q2-loc/q2-loc.js +42 -1
  84. package/dist/collection/components/q2-message/q2-message.css +4 -0
  85. package/dist/collection/components/q2-meter/q2-meter.css +3 -3
  86. package/dist/collection/components/q2-modal/q2-modal.css +1 -1
  87. package/dist/collection/components/q2-modal/q2-modal.js +2 -2
  88. package/dist/collection/components/q2-otp/q2-otp.css +33 -0
  89. package/dist/collection/components/q2-otp/test/q2-otp-test.vr.js +83 -0
  90. package/dist/collection/components/q2-popover/q2-popover.css +2 -1
  91. package/dist/collection/components/q2-radio/q2-radio.css +2 -0
  92. package/dist/collection/components/q2-search/q2-search.css +30 -0
  93. package/dist/collection/components/q2-search/q2-search.js +99 -10
  94. package/dist/collection/components/q2-search/test/q2-search-test.vr.js +145 -0
  95. package/dist/collection/components/q2-section/q2-section.css +1 -1
  96. package/dist/collection/components/q2-select/q2-select.css +4 -2
  97. package/dist/collection/components/q2-select/q2-select.js +54 -4
  98. package/dist/collection/components/q2-select/test/q2-select-test.vr.js +5 -0
  99. package/dist/collection/components/q2-stepper/q2-stepper.css +2 -2
  100. package/dist/collection/components/q2-stepper/q2-stepper.js +3 -2
  101. package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.css +2 -2
  102. package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.js +22 -16
  103. package/dist/collection/components/q2-surface/q2-surface.css +348 -0
  104. package/dist/collection/components/q2-surface/q2-surface.js +381 -0
  105. package/dist/collection/components/q2-surface/test/q2-surface-test.vr.js +108 -0
  106. package/dist/collection/components/q2-tab-container/q2-tab-container.js +1 -1
  107. package/dist/collection/components/q2-tab-pane/q2-tab-pane.js +1 -1
  108. package/dist/collection/components/q2-tag/q2-tag.js +1 -1
  109. package/dist/collection/components/q2-toast/q2-toast.js +3 -1
  110. package/dist/collection/components/tecton-tab-pane/tecton-tab-pane.js +2 -2
  111. package/dist/collection/utils/index.js +2 -2
  112. package/dist/components/index.js +12 -10
  113. package/dist/components/index2.js +3 -3
  114. package/dist/components/q2-action-sheet.js +1 -1
  115. package/dist/components/q2-btn2.js +5 -1
  116. package/dist/components/q2-calendar.js +294 -290
  117. package/dist/components/q2-card-image.js +9 -6
  118. package/dist/components/q2-card.js +14 -14
  119. package/dist/components/q2-chart-donut.js +1 -1
  120. package/dist/components/q2-checkbox2.js +12 -12
  121. package/dist/components/q2-currency.js +1 -1
  122. package/dist/components/q2-data-table.js +4 -4
  123. package/dist/components/q2-detail.js +1 -1
  124. package/dist/components/q2-dropdown.js +8 -8
  125. package/dist/components/q2-editable-field.js +15 -5
  126. package/dist/components/q2-input2.js +46 -26
  127. package/dist/components/q2-item2.js +1 -1
  128. package/dist/components/q2-legend2.js +51 -51
  129. package/dist/components/q2-list2.js +1 -1
  130. package/dist/components/q2-loc.js +23 -8
  131. package/dist/components/q2-meter.js +10 -10
  132. package/dist/components/q2-modal.js +54 -54
  133. package/dist/components/q2-popover2.js +1 -1
  134. package/dist/components/q2-search.js +106 -51
  135. package/dist/components/q2-section.js +1 -1
  136. package/dist/components/q2-select2.js +25 -9
  137. package/dist/components/q2-stepper-vertical.js +72 -63
  138. package/dist/components/q2-stepper.js +73 -71
  139. package/dist/components/q2-surface.d.ts +11 -0
  140. package/dist/components/q2-surface.js +109 -0
  141. package/dist/components/q2-tab-container.js +12 -12
  142. package/dist/components/q2-tab-pane.js +6 -6
  143. package/dist/components/q2-tag2.js +5 -5
  144. package/dist/components/tecton-tab-pane.js +10 -10
  145. package/dist/esm/click-elsewhere_3.entry.js +2 -2
  146. package/dist/esm/{index-Bx4m6N0g.js → index-Cps4jSQM.js} +2 -2
  147. package/dist/esm/loader.js +1 -1
  148. package/dist/esm/q2-action-group_2.entry.js +1 -1
  149. package/dist/esm/q2-action-sheet.entry.js +2 -2
  150. package/dist/esm/q2-badge_2.entry.js +11 -4
  151. package/dist/esm/q2-btn_2.entry.js +6 -2
  152. package/dist/esm/q2-calendar.entry.js +5 -3
  153. package/dist/esm/q2-card-image.entry.js +8 -6
  154. package/dist/esm/q2-card.entry.js +2 -2
  155. package/dist/esm/q2-carousel-pane.entry.js +1 -1
  156. package/dist/esm/q2-carousel.entry.js +1 -1
  157. package/dist/esm/q2-chart-area.entry.js +1 -1
  158. package/dist/esm/q2-chart-bar.entry.js +1 -1
  159. package/dist/esm/q2-chart-donut.entry.js +2 -2
  160. package/dist/esm/q2-checkbox-group.entry.js +1 -1
  161. package/dist/esm/q2-checkbox_2.entry.js +4 -3
  162. package/dist/esm/q2-context.entry.js +1 -1
  163. package/dist/esm/q2-currency.entry.js +1 -1
  164. package/dist/esm/q2-data-table.entry.js +6 -3
  165. package/dist/esm/q2-detail.entry.js +2 -2
  166. package/dist/esm/q2-dropdown-item.entry.js +1 -1
  167. package/dist/esm/q2-dropdown.entry.js +3 -3
  168. package/dist/esm/q2-editable-field.entry.js +12 -4
  169. package/dist/esm/q2-file-picker.entry.js +1 -1
  170. package/dist/esm/q2-icon.entry.js +1 -1
  171. package/dist/esm/q2-item.entry.js +2 -2
  172. package/dist/esm/q2-legend.entry.js +1 -1
  173. package/dist/esm/q2-link_2.entry.js +2 -2
  174. package/dist/esm/q2-loc.entry.js +20 -2
  175. package/dist/esm/q2-message.entry.js +1 -1
  176. package/dist/esm/q2-meter.entry.js +2 -2
  177. package/dist/esm/q2-modal.entry.js +3 -3
  178. package/dist/esm/q2-month-picker.entry.js +1 -1
  179. package/dist/esm/q2-optgroup.entry.js +1 -1
  180. package/dist/esm/q2-option.entry.js +1 -1
  181. package/dist/esm/q2-otp.entry.js +1 -1
  182. package/dist/esm/q2-pagination.entry.js +1 -1
  183. package/dist/esm/q2-pill.entry.js +1 -1
  184. package/dist/esm/q2-radio-group.entry.js +1 -1
  185. package/dist/esm/q2-radio.entry.js +1 -1
  186. package/dist/esm/q2-relative-time.entry.js +1 -1
  187. package/dist/esm/q2-search.entry.js +101 -12
  188. package/dist/esm/q2-section.entry.js +2 -2
  189. package/dist/esm/q2-select.entry.js +36 -6
  190. package/dist/esm/q2-stepper-pane.entry.js +1 -1
  191. package/dist/esm/q2-stepper-vertical.entry.js +24 -18
  192. package/dist/esm/q2-stepper.entry.js +5 -4
  193. package/dist/esm/q2-surface.entry.js +93 -0
  194. package/dist/esm/q2-tab-container.entry.js +2 -2
  195. package/dist/esm/q2-tab-pane.entry.js +1 -1
  196. package/dist/esm/q2-tecton-elements.js +1 -1
  197. package/dist/esm/q2-textarea.entry.js +1 -1
  198. package/dist/esm/q2-toast.entry.js +1 -1
  199. package/dist/esm/q2-tooltip.entry.js +1 -1
  200. package/dist/esm/tecton-tab-pane.entry.js +2 -2
  201. package/dist/q2-tecton-elements/click-elsewhere_3.entry.js +2 -2
  202. package/dist/q2-tecton-elements/{index-Bx4m6N0g.js → index-Cps4jSQM.js} +3 -3
  203. package/dist/q2-tecton-elements/q2-action-group_2.entry.js +1 -1
  204. package/dist/q2-tecton-elements/q2-action-sheet.entry.js +2 -2
  205. package/dist/q2-tecton-elements/q2-badge_2.entry.js +51 -32
  206. package/dist/q2-tecton-elements/q2-btn_2.entry.js +6 -2
  207. package/dist/q2-tecton-elements/q2-calendar.entry.js +7 -4
  208. package/dist/q2-tecton-elements/q2-card-image.entry.js +65 -62
  209. package/dist/q2-tecton-elements/q2-card.entry.js +2 -2
  210. package/dist/q2-tecton-elements/q2-carousel-pane.entry.js +1 -1
  211. package/dist/q2-tecton-elements/q2-carousel.entry.js +1 -1
  212. package/dist/q2-tecton-elements/q2-chart-area.entry.js +54 -54
  213. package/dist/q2-tecton-elements/q2-chart-bar.entry.js +3 -3
  214. package/dist/q2-tecton-elements/q2-chart-donut.entry.js +7 -7
  215. package/dist/q2-tecton-elements/q2-checkbox-group.entry.js +1 -1
  216. package/dist/q2-tecton-elements/q2-checkbox_2.entry.js +18 -18
  217. package/dist/q2-tecton-elements/q2-context.entry.js +1 -1
  218. package/dist/q2-tecton-elements/q2-currency.entry.js +1 -1
  219. package/dist/q2-tecton-elements/q2-data-table.entry.js +50 -50
  220. package/dist/q2-tecton-elements/q2-detail.entry.js +2 -2
  221. package/dist/q2-tecton-elements/q2-dropdown-item.entry.js +1 -1
  222. package/dist/q2-tecton-elements/q2-dropdown.entry.js +16 -16
  223. package/dist/q2-tecton-elements/q2-editable-field.entry.js +15 -8
  224. package/dist/q2-tecton-elements/q2-file-picker.entry.js +1 -1
  225. package/dist/q2-tecton-elements/q2-icon.entry.js +1 -1
  226. package/dist/q2-tecton-elements/q2-item.entry.js +2 -2
  227. package/dist/q2-tecton-elements/q2-legend.entry.js +1 -1
  228. package/dist/q2-tecton-elements/q2-link_2.entry.js +2 -2
  229. package/dist/q2-tecton-elements/q2-loc.entry.js +20 -6
  230. package/dist/q2-tecton-elements/q2-message.entry.js +1 -1
  231. package/dist/q2-tecton-elements/q2-meter.entry.js +2 -2
  232. package/dist/q2-tecton-elements/q2-modal.entry.js +55 -55
  233. package/dist/q2-tecton-elements/q2-month-picker.entry.js +1 -1
  234. package/dist/q2-tecton-elements/q2-optgroup.entry.js +1 -1
  235. package/dist/q2-tecton-elements/q2-option.entry.js +7 -7
  236. package/dist/q2-tecton-elements/q2-otp.entry.js +1 -1
  237. package/dist/q2-tecton-elements/q2-pagination.entry.js +1 -1
  238. package/dist/q2-tecton-elements/q2-pill.entry.js +1 -1
  239. package/dist/q2-tecton-elements/q2-radio-group.entry.js +1 -1
  240. package/dist/q2-tecton-elements/q2-radio.entry.js +1 -1
  241. package/dist/q2-tecton-elements/q2-relative-time.entry.js +1 -1
  242. package/dist/q2-tecton-elements/q2-search.entry.js +108 -53
  243. package/dist/q2-tecton-elements/q2-section.entry.js +2 -2
  244. package/dist/q2-tecton-elements/q2-select.entry.js +25 -10
  245. package/dist/q2-tecton-elements/q2-stepper-pane.entry.js +1 -1
  246. package/dist/q2-tecton-elements/q2-stepper-vertical.entry.js +75 -66
  247. package/dist/q2-tecton-elements/q2-stepper.entry.js +47 -45
  248. package/dist/q2-tecton-elements/q2-surface.entry.js +89 -0
  249. package/dist/q2-tecton-elements/q2-tab-container.entry.js +13 -13
  250. package/dist/q2-tecton-elements/q2-tab-pane.entry.js +2 -2
  251. package/dist/q2-tecton-elements/q2-tecton-elements.esm.js +1 -1
  252. package/dist/q2-tecton-elements/q2-textarea.entry.js +1 -1
  253. package/dist/q2-tecton-elements/q2-toast.entry.js +5 -5
  254. package/dist/q2-tecton-elements/q2-tooltip.entry.js +8 -8
  255. package/dist/q2-tecton-elements/tecton-tab-pane.entry.js +6 -6
  256. package/dist/types/components/q2-calendar/q2-calendar.d.ts +2 -0
  257. package/dist/types/components/q2-card-image/q2-card-image.d.ts +5 -5
  258. package/dist/types/components/q2-editable-field/q2-editable-field.d.ts +1 -0
  259. package/dist/types/components/q2-input/q2-input.d.ts +3 -0
  260. package/dist/types/components/q2-item/test/q2-item-test.vr.d.ts +1 -0
  261. package/dist/types/components/q2-loc/q2-loc.d.ts +6 -0
  262. package/dist/types/components/q2-modal/q2-modal.d.ts +1 -1
  263. package/dist/types/components/q2-otp/test/q2-otp-test.vr.d.ts +1 -0
  264. package/dist/types/components/q2-search/q2-search.d.ts +7 -0
  265. package/dist/types/components/q2-search/test/q2-search-test.vr.d.ts +1 -0
  266. package/dist/types/components/q2-select/q2-select.d.ts +4 -0
  267. package/dist/types/components/q2-stepper-vertical/q2-stepper-vertical.d.ts +2 -1
  268. package/dist/types/components/q2-surface/q2-surface.d.ts +54 -0
  269. package/dist/types/components/q2-surface/test/q2-surface-test.vr.d.ts +1 -0
  270. package/dist/types/components/q2-toast/q2-toast.d.ts +3 -1
  271. package/dist/types/components.d.ts +259 -13
  272. package/dist/types/utils/index.d.ts +3 -1
  273. package/package.json +4 -3
@@ -83,6 +83,7 @@ export class Q2Search {
83
83
  */
84
84
  this.showSelectedToggle = false;
85
85
  this.clearAll = () => {
86
+ this.clearSelectedDisplay();
86
87
  const { multiple } = this;
87
88
  this.value = '';
88
89
  this.selectedOptions = [];
@@ -101,7 +102,7 @@ export class Q2Search {
101
102
  this.tctInput.emit({ query: '' });
102
103
  };
103
104
  this.handleSelectionChanges = (detail) => {
104
- var _a, _b, _c, _d, _e, _f, _g;
105
+ var _a, _b, _c, _d, _e;
105
106
  const { multiple } = this;
106
107
  if (multiple) {
107
108
  const values = (_a = detail.values) !== null && _a !== void 0 ? _a : [];
@@ -123,6 +124,10 @@ export class Q2Search {
123
124
  // Re-clicking the already-selected single-select option closes the popover
124
125
  // with no state change and no `tctChange`.
125
126
  if (value === this.value && value !== '') {
127
+ const reSelected = this.optionElements.find(o => o.value === value);
128
+ this.searchText = this.optionDisplayText(reSelected, value);
129
+ this.isShowingSelectionDisplay = true;
130
+ this.checkSelectedDisplay();
126
131
  // Focus before close so the focus event fires while open===true, which
127
132
  // causes onFocus to skip openDropdown (it's already open at that point).
128
133
  (_d = this.innerInputField) === null || _d === void 0 ? void 0 : _d.focus();
@@ -131,12 +136,13 @@ export class Q2Search {
131
136
  }
132
137
  this.value = value;
133
138
  const selected = this.optionElements.find(o => o.value === value);
134
- const display = (selected === null || selected === void 0 ? void 0 : selected.display) ? loc(selected.display) : (_f = (_e = selected === null || selected === void 0 ? void 0 : selected.textContent) === null || _e === void 0 ? void 0 : _e.trim()) !== null && _f !== void 0 ? _f : value;
139
+ const display = this.optionDisplayText(selected, value);
135
140
  this.searchText = display;
136
141
  this.isShowingSelectionDisplay = true;
142
+ this.checkSelectedDisplay();
137
143
  // Focus before close: the focus event fires while open===true so onFocus's
138
144
  // openDropdown call is a no-op, then closeDropdown brings us to closed+focused.
139
- (_g = this.innerInputField) === null || _g === void 0 ? void 0 : _g.focus();
145
+ (_e = this.innerInputField) === null || _e === void 0 ? void 0 : _e.focus();
140
146
  this.closeDropdown();
141
147
  this.tctChange.emit({
142
148
  value,
@@ -154,6 +160,8 @@ export class Q2Search {
154
160
  this.inputInputHandler = (event) => {
155
161
  event.stopPropagation();
156
162
  const next = event.detail.value;
163
+ if (this.isShowingSelectionDisplay)
164
+ this.clearSelectedDisplay();
157
165
  // Preserve `value` while the user types — they're searching, not deselecting.
158
166
  // `handleSelectionChanges` updates value if they pick a different option,
159
167
  // and `revertToSelectedDisplay` restores the display on blur.
@@ -208,6 +216,17 @@ export class Q2Search {
208
216
  event.stopPropagation();
209
217
  this.handleSelectionChanges(event.detail);
210
218
  };
219
+ this.onSelectedDisplayMousedown = (event) => {
220
+ var _a;
221
+ event.preventDefault();
222
+ event.stopPropagation();
223
+ this.isShowingSelectionDisplay = false;
224
+ this.clearSelectedDisplay();
225
+ if (this.value)
226
+ (_a = this.innerInputField) === null || _a === void 0 ? void 0 : _a.select();
227
+ if (!this.open)
228
+ this.openDropdown();
229
+ };
211
230
  this.onViewportResize = () => {
212
231
  if (!this.open || !this.popoverAlignment)
213
232
  return;
@@ -261,10 +280,14 @@ export class Q2Search {
261
280
  if (target && ((_c = this.popoverElement) === null || _c === void 0 ? void 0 : _c.contains(target)))
262
281
  return;
263
282
  this.inputFocused = true;
264
- if (this.isShowingSelectionDisplay) {
283
+ // Only switch away from the selection display when the user actively re-engages the
284
+ // field (popover is closed). During the post-selection focus that closes the popover,
285
+ // `open` is still true — clearing here would immediately discard the rich display.
286
+ if (this.isShowingSelectionDisplay && !this.open) {
265
287
  // Clear the flag before mutating searchText so the filter watcher runs against the
266
288
  // new query, not the stale "showing a selection" guard.
267
289
  this.isShowingSelectionDisplay = false;
290
+ this.clearSelectedDisplay();
268
291
  if (this.multiple) {
269
292
  // Multi-select always opens to a fresh search after a selection.
270
293
  this.searchText = '';
@@ -361,6 +384,7 @@ export class Q2Search {
361
384
  * Does not emit `tctChange`.
362
385
  */
363
386
  async reset() {
387
+ this.clearSelectedDisplay();
364
388
  this.value = '';
365
389
  this.selectedOptions = [];
366
390
  this.searchText = '';
@@ -477,6 +501,11 @@ export class Q2Search {
477
501
  return count > 1 ? `+${count - 1}` : null;
478
502
  return `${count}`;
479
503
  }
504
+ get firstSelectedOptionElement() {
505
+ var _a, _b;
506
+ const v = this.multiple ? (_a = this.selectedOptions) === null || _a === void 0 ? void 0 : _a[0] : this.value;
507
+ return v ? (_b = this.optionElements.find(o => o.value === v)) !== null && _b !== void 0 ? _b : null : null;
508
+ }
480
509
  get innerInputContainer() {
481
510
  var _a, _b, _c;
482
511
  return (_c = (_b = (_a = this.inputField) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('.input-container')) !== null && _c !== void 0 ? _c : null;
@@ -513,6 +542,9 @@ export class Q2Search {
513
542
  const rowHeight = Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
514
543
  return this.minRows * rowHeight;
515
544
  }
545
+ get selectedDisplaySlot() {
546
+ return this.hostElement.querySelector('[slot="_selected-display"]');
547
+ }
516
548
  get visibleOptionElements() {
517
549
  return this.optionElements.filter(opt => !opt.hidden);
518
550
  }
@@ -546,12 +578,50 @@ export class Q2Search {
546
578
  const { multilineOptions } = this;
547
579
  this.optionElements.forEach(option => (option.multiline = multilineOptions));
548
580
  }
581
+ checkSelectedDisplay() {
582
+ var _a;
583
+ const { multilineOptions, isShowingSelectionDisplay, value, multiple, selectedOptions, firstSelectedOptionElement, } = this;
584
+ const hasNoValue = multiple ? !(selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.length) : !value;
585
+ if (!multilineOptions || !isShowingSelectionDisplay || hasNoValue)
586
+ return this.clearSelectedDisplay();
587
+ if (!firstSelectedOptionElement || firstSelectedOptionElement.display)
588
+ return this.clearSelectedDisplay();
589
+ const child = firstSelectedOptionElement.firstElementChild;
590
+ if (!child)
591
+ return this.clearSelectedDisplay();
592
+ const selectionClone = child.cloneNode(true);
593
+ selectionClone.querySelectorAll('[hide-on-select]').forEach(el => el.remove());
594
+ let namedSlot = this.selectedDisplaySlot;
595
+ if (namedSlot) {
596
+ if (((_a = namedSlot.firstElementChild) === null || _a === void 0 ? void 0 : _a.outerHTML) !== selectionClone.outerHTML) {
597
+ namedSlot.replaceChildren(selectionClone);
598
+ }
599
+ }
600
+ else {
601
+ namedSlot = document.createElement('div');
602
+ namedSlot.slot = '_selected-display';
603
+ // Prevent the non-focusable overlay from blurring the hidden input when clicked.
604
+ // Same pattern used by q2-input's clear button (onMouseDown preventDefault).
605
+ namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
606
+ namedSlot.appendChild(selectionClone);
607
+ this.hostElement.appendChild(namedSlot);
608
+ }
609
+ return namedSlot;
610
+ }
549
611
  checkSelectedOptions() {
550
612
  const { multiple, selectedOptions, value } = this;
551
613
  this.optionElements.forEach(option => {
552
614
  option.selected = multiple ? selectedOptions.includes(option.value) : option.value === value;
553
615
  });
554
616
  }
617
+ clearSelectedDisplay() {
618
+ const slot = this.selectedDisplaySlot;
619
+ if (slot) {
620
+ slot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
621
+ slot.remove();
622
+ }
623
+ return null;
624
+ }
555
625
  closeDropdown() {
556
626
  if (!this.open)
557
627
  return;
@@ -578,8 +648,16 @@ export class Q2Search {
578
648
  this.open = true;
579
649
  this.tctOpen.emit();
580
650
  }
651
+ optionDisplayText(option, fallback = '') {
652
+ var _a, _b;
653
+ if (option === null || option === void 0 ? void 0 : option.display)
654
+ return loc(option.display);
655
+ if (this.multilineOptions)
656
+ return '';
657
+ return (_b = (_a = option === null || option === void 0 ? void 0 : option.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : fallback;
658
+ }
581
659
  revertToSelectedDisplay() {
582
- var _a, _b, _c, _d, _e;
660
+ var _a, _b, _c;
583
661
  if (this.multiple) {
584
662
  // Preserve an in-progress query — user blurred without selecting and may resume.
585
663
  if (this.searchText)
@@ -593,7 +671,7 @@ export class Q2Search {
593
671
  // re-populated yet) — leave the query alone rather than blanking it.
594
672
  if (!selected)
595
673
  return;
596
- const display = selected.display ? loc(selected.display) : (_c = (_b = selected.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '';
674
+ const display = this.optionDisplayText(selected);
597
675
  this.searchText = display;
598
676
  this.isShowingSelectionDisplay = true;
599
677
  return;
@@ -606,10 +684,16 @@ export class Q2Search {
606
684
  // Same guard: don't clobber an in-progress query when the matching option isn't in the DOM.
607
685
  if (!selected)
608
686
  return;
609
- const display = selected.display ? loc(selected.display) : (_e = (_d = selected.textContent) === null || _d === void 0 ? void 0 : _d.trim()) !== null && _e !== void 0 ? _e : '';
687
+ const display = selected.display
688
+ ? loc(selected.display)
689
+ : this.multilineOptions
690
+ ? ''
691
+ : (_c = (_b = selected.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '';
610
692
  this.isShowingSelectionDisplay = true;
611
- if (this.searchText === display)
693
+ if (this.searchText === display) {
694
+ this.checkSelectedDisplay();
612
695
  return;
696
+ }
613
697
  this.searchText = display;
614
698
  }
615
699
  setCustomLabel() {
@@ -644,6 +728,11 @@ export class Q2Search {
644
728
  }
645
729
  // #endregion
646
730
  // #region Render Methods
731
+ renderCustomDisplay() {
732
+ if (!this.checkSelectedDisplay())
733
+ return null;
734
+ return (h("slot", { name: "_selected-display", slot: "custom-display" }));
735
+ }
647
736
  renderEmpty() {
648
737
  if (this.hasEmptySlot) {
649
738
  return h("slot", { name: "empty" });
@@ -673,9 +762,9 @@ export class Q2Search {
673
762
  return (h("q2-popover", { ref: el => (this.popoverElement = el), controlElement: (_a = this.innerInputContainer) !== null && _a !== void 0 ? _a : undefined, open: this.open, maxHeight: this.popoverMaxHeight, minHeight: this.popoverMinHeight, align: useBlock ? undefined : this.popoverAlignment, block: useBlock }, h("div", { class: "popover-content", "data-loading": this.loading ? 'true' : 'false', "aria-busy": this.loading ? 'true' : null }, h("div", { class: "popover-top-container", hidden: !this.hasPopoverTop && !(this.multiple && this.showSelectedToggle), tabindex: "-1" }, h("slot", { name: "popover-top" }), !this.loading && this.renderMultiSelectHeader()), h("q2-option-list", { ref: el => (this.optionList = el), type: "listbox", id: this.optionListId, label: loc(this.listLabel), multiple: this.multiple, selectedOptions: this.structuredSelectedOptions, showSelected: this.showSelected, customSearch: true, hidden: this.loading, onChange: (e) => e.stopPropagation(), onTctChange: this.onOptionListChange }, h("slot", null)), showEmpty && this.renderEmpty(), h("div", { class: "popover-bottom-container", hidden: !this.hasPopoverBottom, tabindex: "-1" }, h("slot", { name: "popover-bottom" })), this.loading && (h("div", { class: "loading-overlay", "aria-hidden": "true" }, h("q2-loading", { type: "spinner" }))))));
674
763
  }
675
764
  render() {
676
- return (h(Fragment, { key: '918ec8192e1dca668611c06f30f002413d87abca' }, h("div", { key: 'a6b81bd23e5d7224986175fc02b21e2fd1433f04', "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage), h("click-elsewhere", { key: '7f83f9b669917b5430aedca1595aee0837edd4da', class: this.wrapperClasses, role: "presentation", onChange: this.onClickElsewhere }, h("q2-input", { key: '7d8de986679460091123baa023a791dcdaecc58a', ref: el => (this.inputField = el), class: "q2-search-input", label: (this.label && loc(this.label)) || '', value: this.searchText, iconLeft: "search", clearable: this.clearable && !this.loading && !!this.searchText, disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder ? loc(this.placeholder) : undefined, hideLabel: this.hideLabel, errors: (Array.isArray(this.errors) && this.errors.length > 0 && this.errors.map(e => loc(e))) ||
765
+ return (h(Fragment, { key: '0686476c153375c6c3cca61cdeaf1267c5ca6b20' }, h("div", { key: 'f5ed583b8da30b2222dd4a466a37e1c10b589fa7', "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage), h("click-elsewhere", { key: 'f1172a06706ea799f6020d21610004450e051d9a', class: this.wrapperClasses, role: "presentation", onChange: this.onClickElsewhere }, h("q2-input", { key: '75675f105bd09279650e6aae6b869e0f3f99c270', ref: el => (this.inputField = el), class: "q2-search-input", label: (this.label && loc(this.label)) || '', value: this.searchText, iconLeft: "search", clearable: this.clearable && !this.loading && !!this.searchText, disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder ? loc(this.placeholder) : undefined, hideLabel: this.hideLabel, errors: (Array.isArray(this.errors) && this.errors.length > 0 && this.errors.map(e => loc(e))) ||
677
766
  (this.invalid && ['tecton.element.search.invalid']) ||
678
- [], ariaExpanded: this.isInputOnlyMode ? undefined : `${this.open}`, ariaControls: this.isInputOnlyMode ? undefined : this.optionListId, ariaHaspopup: this.isInputOnlyMode ? undefined : 'listbox', hideMessages: true, _role: this.isInputOnlyMode ? undefined : 'combobox', onTctInput: this.inputInputHandler, onInput: (e) => e.stopImmediatePropagation(), onChange: (e) => e.stopPropagation(), onTctChange: (e) => e.stopPropagation(), badgeValue: this.badgeValue }), this.renderOptionsDropdown())));
767
+ [], ariaExpanded: this.isInputOnlyMode ? undefined : `${this.open}`, ariaControls: this.isInputOnlyMode ? undefined : this.optionListId, ariaHaspopup: this.isInputOnlyMode ? undefined : 'listbox', hideMessages: true, _role: this.isInputOnlyMode ? undefined : 'combobox', onTctInput: this.inputInputHandler, onInput: (e) => e.stopImmediatePropagation(), onChange: (e) => e.stopPropagation(), onTctChange: (e) => e.stopPropagation(), badgeValue: this.badgeValue }, this.renderCustomDisplay()), this.renderOptionsDropdown())));
679
768
  }
680
769
  static get is() { return "q2-search"; }
681
770
  static get encapsulation() { return "shadow"; }
@@ -0,0 +1,145 @@
1
+ import { expect } from "@playwright/test";
2
+ import { test } from "@stencil/playwright";
3
+ import { setupPage, THEMES } from "../../../utils/test/vr-helpers";
4
+ const OPTIONS = `
5
+ <q2-option value="1" display="Apothecary"></q2-option>
6
+ <q2-option value="2" display="Borant"></q2-option>
7
+ <q2-option value="3" display="Valtay"></q2-option>
8
+ `;
9
+ const ERRORS = ['This field is required.', 'The value entered is invalid.'];
10
+ const VARIANTS = [
11
+ {
12
+ name: 'default',
13
+ html: '<q2-search label="Search" placeholder="Type to search"></q2-search>',
14
+ states: ['resting', 'focus'],
15
+ },
16
+ {
17
+ name: 'clearable-with-value',
18
+ html: `<q2-search label="Search" clearable value="1">${OPTIONS}</q2-search>`,
19
+ states: ['resting'],
20
+ },
21
+ {
22
+ name: 'optional',
23
+ html: '<q2-search label="Search" optional placeholder="Type to search"></q2-search>',
24
+ states: ['resting'],
25
+ },
26
+ {
27
+ name: 'readonly',
28
+ html: `<q2-search label="Search" readonly value="1">${OPTIONS}</q2-search>`,
29
+ states: ['resting'],
30
+ },
31
+ {
32
+ name: 'disabled',
33
+ html: '<q2-search label="Search" disabled placeholder="Type to search"></q2-search>',
34
+ states: ['resting'],
35
+ },
36
+ {
37
+ name: 'errored',
38
+ html: '<q2-search label="Search" placeholder="Type to search"></q2-search>',
39
+ states: ['resting'],
40
+ setup: 'errors',
41
+ },
42
+ {
43
+ name: 'expanded',
44
+ html: `<q2-search label="Search">${OPTIONS}</q2-search>`,
45
+ states: ['expanded', 'expanded-option-hover', 'expanded-option-focus'],
46
+ },
47
+ {
48
+ name: 'loading',
49
+ html: '<q2-search label="Search" loading placeholder="Type to search"></q2-search>',
50
+ states: ['expanded'],
51
+ },
52
+ {
53
+ name: 'no-results',
54
+ html: '<q2-search label="Search"></q2-search>',
55
+ states: ['expanded'],
56
+ },
57
+ {
58
+ name: 'multiple',
59
+ html: `<q2-search label="Search" multiple filter>${OPTIONS}</q2-search>`,
60
+ states: ['expanded', 'expanded-option-hover', 'expanded-option-focus'],
61
+ },
62
+ {
63
+ name: 'multiple-show-selected-toggle',
64
+ html: `<q2-search label="Search" multiple filter show-selected-toggle>${OPTIONS}</q2-search>`,
65
+ states: ['expanded'],
66
+ setup: 'multiple-selected',
67
+ },
68
+ ];
69
+ const applySetup = async (page, setup) => {
70
+ if (!setup)
71
+ return;
72
+ await page.evaluate(({ setup, errors }) => {
73
+ const el = document.querySelector('q2-search');
74
+ if (setup === 'errors')
75
+ el.errors = errors;
76
+ if (setup === 'multiple-selected')
77
+ el.selectedOptions = ['1'];
78
+ }, { setup, errors: ERRORS });
79
+ };
80
+ const openSearch = async (page, hasOptions) => {
81
+ await page.evaluate(() => {
82
+ const el = document.querySelector('q2-search');
83
+ return el.openPopover();
84
+ });
85
+ if (hasOptions) {
86
+ await page.locator('q2-option').first().waitFor({ state: 'visible' });
87
+ }
88
+ // Wait for the popover open transition (box-shadow, opacity) to fully settle.
89
+ await page.waitForTimeout(300);
90
+ };
91
+ const setup = (page, variant, theme) => setupPage(page, variant.html, { theme, setupLoc: true }).then(() => applySetup(page, variant.setup));
92
+ const restingCase = (variant, theme) => {
93
+ test(`q2-search--${variant.name}--resting — ${theme}`, async ({ page }) => {
94
+ await setup(page, variant, theme);
95
+ await expect(page).toHaveScreenshot(`q2-search--${variant.name}--resting--${theme}.png`);
96
+ });
97
+ };
98
+ const focusCase = (variant, theme) => {
99
+ test(`q2-search--${variant.name}--focus — ${theme}`, async ({ page }) => {
100
+ await setup(page, variant, theme);
101
+ await page.keyboard.press('Tab');
102
+ await expect(page).toHaveScreenshot(`q2-search--${variant.name}--focus--${theme}.png`);
103
+ });
104
+ };
105
+ const expandedCase = (variant, theme) => {
106
+ const hasOptions = !variant.name.includes('loading') && !variant.name.includes('no-results');
107
+ test(`q2-search--${variant.name}--expanded — ${theme}`, async ({ page }) => {
108
+ await setup(page, variant, theme);
109
+ await openSearch(page, hasOptions);
110
+ await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded--${theme}.png`);
111
+ });
112
+ };
113
+ const expandedOptionHoverCase = (variant, theme) => {
114
+ test(`q2-search--${variant.name}--expanded-option-hover — ${theme}`, async ({ page }) => {
115
+ await setup(page, variant, theme);
116
+ await openSearch(page, true);
117
+ await page.locator('q2-option[value="1"]').hover();
118
+ await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded-option-hover--${theme}.png`);
119
+ });
120
+ };
121
+ // ArrowDown after open moves focus to the first option, triggering :focus-visible.
122
+ const expandedOptionFocusCase = (variant, theme) => {
123
+ test(`q2-search--${variant.name}--expanded-option-focus — ${theme}`, async ({ page }) => {
124
+ await setup(page, variant, theme);
125
+ await openSearch(page, true);
126
+ await page.keyboard.press('ArrowDown');
127
+ await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded-option-focus--${theme}.png`);
128
+ });
129
+ };
130
+ const CASE_MAP = {
131
+ resting: restingCase,
132
+ focus: focusCase,
133
+ expanded: expandedCase,
134
+ 'expanded-option-hover': expandedOptionHoverCase,
135
+ 'expanded-option-focus': expandedOptionFocusCase,
136
+ };
137
+ test.describe('q2-search — variants × themes', () => {
138
+ for (const variant of VARIANTS) {
139
+ for (const theme of THEMES) {
140
+ for (const state of variant.states) {
141
+ CASE_MAP[state](variant, theme);
142
+ }
143
+ }
144
+ }
145
+ });
@@ -94,7 +94,7 @@ button {
94
94
  :host {
95
95
  display: block;
96
96
  background: var(--tct-section-background, var(--tct-section-background-color, var(--t-section-background-color, var(--tct-section-bg, var(--t-section-bg, var(--app-white, #ffffff))))));
97
- color: var(--tct-section-font-color, var(--t-section-font-color, var(--t-text, #4d4d4d)));
97
+ color: var(--tct-section-font-color, var(--t-section-font-color, inherit));
98
98
  border-radius: var(--tct-section-border-radius, var(--t-section-border-radius, var(--app-border-radius-1, 4px)));
99
99
  margin: var(--tct-section-margin, var(--t-section-margin, var(--app-scale-3x, 15px)));
100
100
  border-width: var(--tct-section-border-width, 0);
@@ -128,8 +128,8 @@ button {
128
128
  * @prop --tct-select-margin: (<length-percentage>+) Controls the outer margin of the select host.
129
129
  * @prop --tct-select-margin-top: (<length-percentage>) Controls the top margin of the select host when --tct-select-margin is not set.
130
130
  * @prop --tct-select-margin-bottom: (<length-percentage>) Controls the bottom margin of the select host when --tct-select-margin is not set.
131
- * @prop --tct-select-input-min-height?: (<length-percentage>) Controls the optional minimum height of the select input.
132
- * @prop --tct-select-input-max-height?: (<length-percentage>) Controls the optional maximum height of the select input.
131
+ * @prop --tct-select-input-min-height?: (<length-percentage>) Controls the optional minimum height of the select input. Use this to control the height of the select in the empty state, especially when using multiline-options with tall content.
132
+ * @prop --tct-select-input-max-height?: (<length-percentage>) Controls the optional maximum height of the select input. Use this to constrain the height when displaying multiline selected content.
133
133
  * @prop --tct-select-multi-select-option-background?: (<color>) Controls the optional background color of multi-select option chips in their default state.
134
134
  * @prop --tct-select-multi-select-option-color?: (<color>) Controls the optional text color of multi-select option chips in their default state.
135
135
  * @prop --tct-select-multi-select-option-active-background: (<color>) Controls the background color of multi-select option chips when active (checked).
@@ -161,6 +161,8 @@ button {
161
161
  ::slotted([slot=_selected-display]) {
162
162
  width: 100%;
163
163
  min-height: var(--comp-selected-display-height, 44px);
164
+ padding-top: var(--tct-select-selected-display-padding, var(--app-scale-2x, 10px));
165
+ padding-bottom: var(--tct-select-selected-display-padding, var(--app-scale-2x, 10px));
164
166
  }
165
167
 
166
168
  .custom-display-content {
@@ -82,6 +82,8 @@ export class Q2Select {
82
82
  * This property is only relevant for `multiple` (i.e., multi-select) implementations.
83
83
  */
84
84
  this.selectedOptions = [];
85
+ /** Determines whether to show a success state. The error state takes precedence when both are set. */
86
+ this.valid = false;
85
87
  this.addTouchEventListeners = () => {
86
88
  if (!isMobile() || !this.popoverElement)
87
89
  return;
@@ -271,6 +273,22 @@ export class Q2Select {
271
273
  return;
272
274
  this.open = open;
273
275
  };
276
+ this.onSelectedDisplayClick = (event) => {
277
+ // Stop click from bubbling to q2-input's onClick (which would toggle the dropdown)
278
+ event.stopPropagation();
279
+ if (this.open) {
280
+ this.focusInput();
281
+ return;
282
+ }
283
+ this.prioritizeSearch = this.searchable;
284
+ this.clearSelectedDisplay();
285
+ this.openDropdownWithoutActiveElement();
286
+ this.focusInput();
287
+ };
288
+ this.onSelectedDisplayMousedown = (event) => {
289
+ // Prevent focus shift away from the hidden input
290
+ event.preventDefault();
291
+ };
274
292
  this.removeTouchEventListeners = () => {
275
293
  if (!isMobile() || !this.popoverElement)
276
294
  return;
@@ -495,6 +513,8 @@ export class Q2Select {
495
513
  }
496
514
  else {
497
515
  this.removeTouchEventListeners();
516
+ // Reset prioritizeSearch when dropdown closes to ensure selected display can be restored
517
+ this.prioritizeSearch = false;
498
518
  }
499
519
  this.scheduledAfterRender.push(async () => {
500
520
  await waitForNextPaint();
@@ -657,10 +677,16 @@ export class Q2Select {
657
677
  if (namedSlot.firstElementChild.outerHTML !== selectionClone.outerHTML) {
658
678
  namedSlot.replaceChild(selectionClone, namedSlot.firstElementChild);
659
679
  }
680
+ namedSlot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
681
+ namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
682
+ namedSlot.removeEventListener('click', this.onSelectedDisplayClick);
683
+ namedSlot.addEventListener('click', this.onSelectedDisplayClick);
660
684
  }
661
685
  else {
662
686
  namedSlot = document.createElement('div');
663
687
  namedSlot.slot = '_selected-display';
688
+ namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
689
+ namedSlot.addEventListener('click', this.onSelectedDisplayClick);
664
690
  namedSlot.appendChild(selectionClone);
665
691
  this.hostElement.appendChild(namedSlot);
666
692
  }
@@ -690,8 +716,12 @@ export class Q2Select {
690
716
  mirrorEmit(this, ['input', 'tctInput'], { query: '' });
691
717
  }
692
718
  clearSelectedDisplay() {
693
- var _a;
694
- (_a = this.selectedDisplaySlot) === null || _a === void 0 ? void 0 : _a.remove();
719
+ const slot = this.selectedDisplaySlot;
720
+ if (slot) {
721
+ slot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
722
+ slot.removeEventListener('click', this.onSelectedDisplayClick);
723
+ slot.remove();
724
+ }
695
725
  }
696
726
  clearValue() {
697
727
  const { multiple } = this;
@@ -786,7 +816,7 @@ export class Q2Select {
786
816
  this.errors.length > 0 &&
787
817
  this.errors.map(error => loc(error))) ||
788
818
  (this.invalid && ['tecton.element.select.invalid']) ||
789
- [], disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder || undefined, hideLabel: this.hideLabel, ariaExpanded: `${this.open}`, ariaControls: "option-list", ariaHaspopup: "listbox", "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: e => e.stopImmediatePropagation(), onTctInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: e => e.stopPropagation(), onTctChange: this.inputChangeHandler, badgeValue: this.badgeValue, badgeTheme: this.inputFocused ? 'primary' : undefined, _role: "combobox", _preventEntry: !this.searchable }, this.renderCustomDisplay()), h("div", { class: "custom-display-content", hidden: !this.hasCustomDisplay || !!this.searchText, onClick: this.onCustomDisplayClick }, h("slot", { name: "q2-select-display" })), this.renderOptionsDropdown()));
819
+ [], disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder || undefined, hideLabel: this.hideLabel, valid: this.valid, ariaExpanded: `${this.open}`, ariaControls: "option-list", ariaHaspopup: "listbox", "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: e => e.stopImmediatePropagation(), onTctInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: e => e.stopPropagation(), onTctChange: this.inputChangeHandler, badgeValue: this.badgeValue, badgeTheme: this.inputFocused ? 'primary' : undefined, _role: "combobox", _preventEntry: !this.searchable }, this.renderCustomDisplay()), h("div", { class: "custom-display-content", hidden: !this.hasCustomDisplay || !!this.searchText, onClick: this.onCustomDisplayClick }, h("slot", { name: "q2-select-display" })), this.renderOptionsDropdown()));
790
820
  }
791
821
  renderVisibilityToggle() {
792
822
  var _a, _b;
@@ -797,7 +827,7 @@ export class Q2Select {
797
827
  ]), checked: showSelected, "test-id": "selectedOptionsButton", onClick: this.showSelectedOptions, onKeyDown: this.visibilityToggleKeyDown }), h("label", { htmlFor: "selected" }, loc('tecton.element.select.multiHeader.selected', [selectedOptionsCount]))))));
798
828
  }
799
829
  render() {
800
- return (h("click-elsewhere", { key: 'd83fb08f6af3a98edc661170f83d89af991275ec', class: this.wrapperClasses, role: "presentation", onChange: this.clickedElsewhere }, this.renderSelectField()));
830
+ return (h("click-elsewhere", { key: 'a08e10cf8bd4e2d3f210d36003417f2a1dec4b21', class: this.wrapperClasses, role: "presentation", onChange: this.clickedElsewhere }, this.renderSelectField()));
801
831
  }
802
832
  static get is() { return "q2-select"; }
803
833
  static get encapsulation() { return "shadow"; }
@@ -1227,6 +1257,26 @@ export class Q2Select {
1227
1257
  "setter": false,
1228
1258
  "defaultValue": "[]"
1229
1259
  },
1260
+ "valid": {
1261
+ "type": "boolean",
1262
+ "mutable": false,
1263
+ "complexType": {
1264
+ "original": "boolean",
1265
+ "resolved": "boolean",
1266
+ "references": {}
1267
+ },
1268
+ "required": false,
1269
+ "optional": false,
1270
+ "docs": {
1271
+ "tags": [],
1272
+ "text": "Determines whether to show a success state. The error state takes precedence when both are set."
1273
+ },
1274
+ "getter": false,
1275
+ "setter": false,
1276
+ "reflect": true,
1277
+ "attribute": "valid",
1278
+ "defaultValue": "false"
1279
+ },
1230
1280
  "value": {
1231
1281
  "type": "string",
1232
1282
  "mutable": true,
@@ -44,6 +44,11 @@ const VARIANTS = [
44
44
  states: ['resting'],
45
45
  setup: 'errors',
46
46
  },
47
+ {
48
+ name: 'valid',
49
+ html: `<q2-select label="My select" placeholder="Select an option" valid value="2">${OPTIONS}</q2-select>`,
50
+ states: ['resting'],
51
+ },
47
52
  ];
48
53
  const applySelectSetup = async (page, setup) => {
49
54
  if (!setup)
@@ -275,7 +275,7 @@ li {
275
275
  }
276
276
 
277
277
  .step-label {
278
- color: var(--tct-stepper-label-color, var(--tct-stepper-title-color, var(--t-stepper-title-color, var(--t-text, #4d4d4d))));
278
+ color: var(--tct-stepper-label-color, var(--tct-stepper-title-color, var(--t-stepper-title-color, inherit)));
279
279
  font-size: var(--tct-stepper-label-font-size, var(--tct-stepper-title-font-size, var(--t-stepper-title-font-size, var(--app-font-size-small, 12px))));
280
280
  line-height: var(--tct-stepper-label-line-height, 1.5em);
281
281
  text-overflow: ellipsis;
@@ -290,7 +290,7 @@ li {
290
290
  }
291
291
 
292
292
  .step-description {
293
- color: var(--tct-stepper-description-color, var(--t-stepper-description-color, var(--t-textA, rgba(77, 77, 77, 0.77))));
293
+ color: var(--tct-stepper-description-color, var(--t-stepper-description-color, inherit));
294
294
  font-size: var(--tct-stepper-description-font-size, var(--t-stepper-description-font-size, var(--app-font-size-small, 12px)));
295
295
  text-overflow: ellipsis;
296
296
  overflow: hidden;
@@ -1,6 +1,7 @@
1
1
  import { h, Fragment, } from "@stencil/core";
2
2
  import { loc, overrideFocus, isEventFromElement, createGuid } from "../../utils/index";
3
3
  import mirrorEmit from "../../utils/mirror-emit";
4
+ import sanitizeHTMLString from "../../utils/sanitize-html-string";
4
5
  /**
5
6
  * @name Stepper
6
7
  * @category Display
@@ -273,14 +274,14 @@ export class Q2Stepper {
273
274
  if (isPaneDisabled)
274
275
  stepClasses.push('pane-disabled');
275
276
  const disabled = isLocked || stepNumber > lastEnabledStep;
276
- return (h("li", { role: "presentation" }, h("button", { class: stepClasses.join(' '), type: "button", "aria-labelledby": labelId, "aria-describedBy": descriptionId, "aria-label": btnLabel, "aria-selected": `${isCurrentStep}`, "aria-disabled": disabled ? 'true' : undefined, role: "tab", tabIndex: isCurrentStep ? 0 : -1, onKeyDown: ev => this.onStepKeyDown(ev, stepNumber), onClick: ev => !isPaneDisabled && !disabled && this.onStepClick(ev, stepNumber) }, h(Fragment, null, statusIcon ? (h("div", { class: "step-icon" }, h("q2-icon", { type: statusIcon }))) : (h("div", { class: "step-bubble" }, stepNumber)), labelId && (h("div", { class: "step-label", id: labelId, innerHTML: label })), labelId && descriptionId && (h("div", { class: "step-description", id: descriptionId, innerHTML: description })))), stepIndex ? h("div", { class: "step-divider" }) : ''));
277
+ return (h("li", { role: "presentation" }, h("button", { class: stepClasses.join(' '), type: "button", "aria-labelledby": labelId, "aria-describedBy": descriptionId, "aria-label": btnLabel, "aria-selected": `${isCurrentStep}`, "aria-disabled": disabled ? 'true' : undefined, role: "tab", tabIndex: isCurrentStep ? 0 : -1, onKeyDown: ev => this.onStepKeyDown(ev, stepNumber), onClick: ev => !isPaneDisabled && !disabled && this.onStepClick(ev, stepNumber) }, h(Fragment, null, statusIcon ? (h("div", { class: "step-icon" }, h("q2-icon", { type: statusIcon }))) : (h("div", { class: "step-bubble" }, stepNumber)), labelId && (h("div", { class: "step-label", id: labelId, innerHTML: sanitizeHTMLString(label) })), labelId && descriptionId && (h("div", { class: "step-description", id: descriptionId, innerHTML: sanitizeHTMLString(description) })))), stepIndex ? h("div", { class: "step-divider" }) : ''));
277
278
  }
278
279
  render() {
279
280
  const { stepCount, scrollEnabled, showScrollLeft, showScrollRight } = this;
280
281
  const containerClasses = ['step-container'];
281
282
  if (scrollEnabled)
282
283
  containerClasses.push('has-scroll');
283
- return (h(Fragment, { key: 'dd38d7922ef9b468399b57f4e1d656b2213d6b32' }, h("div", { key: '92dc67bc25e5a5275241b91ec6cb968202e91af8', class: containerClasses.join(' ') }, scrollEnabled && (h(Fragment, { key: 'ef83e893c3dfe020cb1c561c1b0619f364c7f08f' }, h("div", { key: '9cf06f95042064daa7564a9927cf3f1ff9a227be', class: "gradient-left", hidden: !showScrollLeft }), h("div", { key: 'd9c58f971a8b2fd545c09e698d57baf356c3947b', class: "gradient-right", hidden: !showScrollRight }), h("q2-btn", { key: '38c601f9fe74886e912e983b9b52e7c1e1a0694e', class: "btn-left", hideLabel: true, hidden: !this.showScrollLeft, label: loc('tecton.element.stepper.scrollLeft'), onTctClick: () => this.onScrollBtnClick('left') }, h("q2-icon", { key: 'a53ac3dc6ebd84e3d221136868df0861bc6acf4f', type: "chevron-left" })), h("q2-btn", { key: '38363d0a8a2d9fa96a919bf08d243ddb42d65552', class: "btn-right", hideLabel: true, hidden: !this.showScrollRight, label: loc('tecton.element.stepper.scrollRight'), onTctClick: () => this.onScrollBtnClick('right') }, h("q2-icon", { key: '6da3f9a38d4b1bb375b25257634058c869f9478f', type: "chevron-right" })))), h("ul", { key: '2c5e3d0e0aebd5fa05ecce735232dd42d1aec470', onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, stepCount > 0 && [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))), h("div", { key: '21e4f4c96ebcef94c73a29f468c820c9d4c22a57', role: "list" }, h("slot", { key: '84d871317ccc4471f1d954d469047bc6f97399cf', onSlotchange: () => this.onSlotChange() }))));
284
+ return (h(Fragment, { key: 'c1e21a36e0b2f684f4520b0f75f78affd73359bd' }, h("div", { key: '3791e857d27aa3fea928f663268f21270d499023', class: containerClasses.join(' ') }, scrollEnabled && (h(Fragment, { key: '19b689b2b56f52099f22f859264e33e16fd918bf' }, h("div", { key: '5b1b1e00034fa009c555924c2067fed6369740cb', class: "gradient-left", hidden: !showScrollLeft }), h("div", { key: 'b5de1b413f6c8ce006207926f26ae845594228eb', class: "gradient-right", hidden: !showScrollRight }), h("q2-btn", { key: '832a97c5619cadb1167f6e1e7ecd94ab4f5f3cb1', class: "btn-left", hideLabel: true, hidden: !this.showScrollLeft, label: loc('tecton.element.stepper.scrollLeft'), onTctClick: () => this.onScrollBtnClick('left') }, h("q2-icon", { key: '3e53b2b2f19bbba59a37016b9cdf1a302b030b63', type: "chevron-left" })), h("q2-btn", { key: 'ffacbb0d2f9c15a503221a2dbc4662ba6f3c3272', class: "btn-right", hideLabel: true, hidden: !this.showScrollRight, label: loc('tecton.element.stepper.scrollRight'), onTctClick: () => this.onScrollBtnClick('right') }, h("q2-icon", { key: '2c60dc5392c9c9eec99dd24b229bbd1fa5e9587f', type: "chevron-right" })))), h("ul", { key: '25806a72f9f0cda2e032a81dbaac9f808be385c9', onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, stepCount > 0 && [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))), h("div", { key: '622b3ed56e3f66adc33bf197b7874a7b9bf8667f', role: "list" }, h("slot", { key: '73c4321743596227054e317c271bcc044179363b', onSlotchange: () => this.onSlotChange() }))));
284
285
  }
285
286
  static get is() { return "q2-stepper"; }
286
287
  static get encapsulation() { return "shadow"; }
@@ -134,7 +134,7 @@ button {
134
134
  }
135
135
 
136
136
  .step-description {
137
- color: var(--tct-stepper-vertical-description-color, var(--tct-advanced-stepper-description-color, var(--t-advanced-stepper-description-color, var(--t-textA, rgba(77, 77, 77, 0.77)))));
137
+ color: var(--tct-stepper-vertical-description-color, var(--tct-advanced-stepper-description-color, var(--t-advanced-stepper-description-color, inherit)));
138
138
  font-size: var(--tct-stepper-vertical-description-font-size, var(--tct-advanced-stepper-description-font-size, var(--t-advanced-stepper-description-font-size, var(--app-font-size-small, 12px))));
139
139
  padding-bottom: 0.2em;
140
140
  }
@@ -145,7 +145,7 @@ ul {
145
145
  --comp-btn-icon-visibility: var(--tct-stepper-vertical-btn-icon-visibility, visible);
146
146
  --comp-btn-content-gap: var(--tct-stepper-vertical-btn-gap, var(--tct-advanced-stepper-btn-gap, var(--t-advanced-stepper-btn-gap, var(--app-scale-3x, 15px))));
147
147
  --comp-btn-label-font-size: var(--tct-stepper-vertical-btn-label-font-size, var(--tct-advanced-stepper-btn-label-font-size, var(--t-advanced-stepper-btn-label-font-size, 16px)));
148
- --comp-btn-label-color: var(--tct-stepper-vertical-label-color, var(--tct-advanced-stepper-label-color, var(--t-advanced-stepper-label-color, var(--t-text, #4d4d4d))));
148
+ --comp-btn-label-color: var(--tct-stepper-vertical-label-color, var(--tct-advanced-stepper-label-color, var(--t-advanced-stepper-label-color, inherit)));
149
149
  --comp-tween: var(--tct-stepper-vertical-tween, var(--tct-advanced-stepper-tween, var(--t-advanced-stepper-tween, var(--app-tween-1, 0.2s ease))));
150
150
  --comp-bullet-bg: var(--tct-stepper-vertical-bullet-active-background, var(--tct-advanced-stepper-bullet-active-bg, var(--t-advanced-stepper-bullet-active-bg, var(--t-primary, #0079c1))));
151
151
  list-style: none;