q2-tecton-elements 1.71.2 → 1.72.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 (265) hide show
  1. package/dist/bundle-report.json +1282 -594
  2. package/dist/cjs/click-elsewhere_3.cjs.entry.js +10 -9
  3. package/dist/cjs/{index-SpDCZABA.js → index-BY3aao8R.js} +1 -1
  4. package/dist/cjs/loader.cjs.js +1 -1
  5. package/dist/cjs/{q2-action-group_2.cjs.entry.js → q2-action-group.cjs.entry.js} +1 -89
  6. package/dist/cjs/q2-action-sheet.cjs.entry.js +1 -1
  7. package/dist/cjs/q2-badge_2.cjs.entry.js +113 -12
  8. package/dist/cjs/q2-btn_2.cjs.entry.js +2 -2
  9. package/dist/cjs/q2-calendar.cjs.entry.js +7 -5
  10. package/dist/cjs/q2-card-image.cjs.entry.js +4 -4
  11. package/dist/cjs/q2-card.cjs.entry.js +1 -1
  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 +1 -1
  17. package/dist/cjs/q2-checkbox-group.cjs.entry.js +2 -2
  18. package/dist/cjs/q2-checkbox_2.cjs.entry.js +3 -3
  19. package/dist/cjs/q2-context.cjs.entry.js +4 -3
  20. package/dist/cjs/q2-data-table.cjs.entry.js +2 -2
  21. package/dist/cjs/q2-detail.cjs.entry.js +1 -1
  22. package/dist/cjs/q2-dropdown-item.cjs.entry.js +1 -1
  23. package/dist/cjs/q2-dropdown.cjs.entry.js +3 -3
  24. package/dist/cjs/q2-editable-field.cjs.entry.js +38 -37
  25. package/dist/cjs/q2-file-picker.cjs.entry.js +60 -4
  26. package/dist/cjs/q2-icon.cjs.entry.js +1 -1
  27. package/dist/cjs/q2-item.cjs.entry.js +2 -2
  28. package/dist/cjs/q2-link_2.cjs.entry.js +1 -1
  29. package/dist/cjs/q2-loc.cjs.entry.js +1 -1
  30. package/dist/cjs/q2-message.cjs.entry.js +2 -2
  31. package/dist/cjs/q2-meter.cjs.entry.js +1 -1
  32. package/dist/cjs/q2-modal.cjs.entry.js +59 -17
  33. package/dist/cjs/q2-month-picker.cjs.entry.js +1 -1
  34. package/dist/cjs/q2-optgroup.cjs.entry.js +1 -1
  35. package/dist/cjs/q2-option.cjs.entry.js +1 -1
  36. package/dist/cjs/q2-otp.cjs.entry.js +1 -1
  37. package/dist/cjs/q2-pagination.cjs.entry.js +1 -1
  38. package/dist/cjs/q2-pill.cjs.entry.js +2 -2
  39. package/dist/cjs/q2-radio-group.cjs.entry.js +22 -4
  40. package/dist/cjs/q2-radio.cjs.entry.js +3 -3
  41. package/dist/cjs/q2-relative-time.cjs.entry.js +3 -3
  42. package/dist/cjs/q2-resize-observer.cjs.entry.js +92 -0
  43. package/dist/cjs/q2-search.cjs.entry.js +2 -2
  44. package/dist/cjs/q2-section.cjs.entry.js +7 -7
  45. package/dist/cjs/q2-select.cjs.entry.js +35 -19
  46. package/dist/cjs/q2-stepper-pane.cjs.entry.js +2 -2
  47. package/dist/cjs/q2-stepper-vertical.cjs.entry.js +2 -2
  48. package/dist/cjs/q2-stepper.cjs.entry.js +1 -1
  49. package/dist/cjs/q2-surface.cjs.entry.js +1 -1
  50. package/dist/cjs/q2-tab-container.cjs.entry.js +2 -2
  51. package/dist/cjs/q2-tab-pane.cjs.entry.js +1 -1
  52. package/dist/cjs/q2-tecton-elements.cjs.js +1 -1
  53. package/dist/cjs/q2-textarea.cjs.entry.js +1 -1
  54. package/dist/cjs/q2-toast.cjs.entry.js +1 -1
  55. package/dist/cjs/q2-tooltip.cjs.entry.js +1 -1
  56. package/dist/cjs/tecton-tab-pane.cjs.entry.js +5 -3
  57. package/dist/collection/components/q2-btn/q2-btn.css +79 -21
  58. package/dist/collection/components/q2-btn/test/q2-btn-test.vr.js +156 -3
  59. package/dist/collection/components/q2-calendar/q2-calendar.css +3 -0
  60. package/dist/collection/components/q2-calendar/q2-calendar.js +5 -3
  61. package/dist/collection/components/q2-calendar/test/q2-calendar-test.vr.js +23 -2
  62. package/dist/collection/components/q2-card/test/q2-card-test.vr.js +4 -0
  63. package/dist/collection/components/q2-card-image/q2-card-image.css +89 -134
  64. package/dist/collection/components/q2-card-image/q2-card-image.js +4 -4
  65. package/dist/collection/components/q2-card-image/test/q2-card-image-test.vr.js +4 -0
  66. package/dist/collection/components/q2-carousel/test/q2-carousel-test.vr.js +13 -0
  67. package/dist/collection/components/q2-checkbox/q2-checkbox.css +2 -2
  68. package/dist/collection/components/q2-checkbox-group/q2-checkbox-group.css +2 -0
  69. package/dist/collection/components/q2-context/q2-context.css +5 -0
  70. package/dist/collection/components/q2-context/q2-context.js +2 -1
  71. package/dist/collection/components/q2-context/test/q2-context-test.vr.js +11 -1
  72. package/dist/collection/components/q2-data-table/q2-data-table.css +3 -0
  73. package/dist/collection/components/q2-data-table/test/q2-data-table-test.vr.js +5 -0
  74. package/dist/collection/components/q2-dropdown/q2-dropdown.css +2 -0
  75. package/dist/collection/components/q2-dropdown/q2-dropdown.js +1 -1
  76. package/dist/collection/components/q2-dropdown/test/q2-dropdown-test.vr.js +30 -0
  77. package/dist/collection/components/q2-editable-field/q2-editable-field.css +2 -0
  78. package/dist/collection/components/q2-editable-field/q2-editable-field.js +38 -43
  79. package/dist/collection/components/q2-file-picker/q2-file-picker.css +27 -0
  80. package/dist/collection/components/q2-file-picker/q2-file-picker.js +98 -2
  81. package/dist/collection/components/q2-file-picker/test/q2-file-picker-test.vr.js +22 -0
  82. package/dist/collection/components/q2-input/q2-input.css +67 -1
  83. package/dist/collection/components/q2-input/q2-input.js +155 -13
  84. package/dist/collection/components/q2-input/test/q2-input-test.vr.js +35 -0
  85. package/dist/collection/components/q2-item/q2-item.css +3 -1
  86. package/dist/collection/components/q2-item/test/q2-item-test.vr.js +6 -0
  87. package/dist/collection/components/q2-message/q2-message.css +5 -5
  88. package/dist/collection/components/q2-modal/q2-modal.css +40 -3
  89. package/dist/collection/components/q2-modal/q2-modal.js +100 -16
  90. package/dist/collection/components/q2-modal/test/q2-modal-test.vr.js +25 -0
  91. package/dist/collection/components/q2-pill/q2-pill.css +2 -2
  92. package/dist/collection/components/q2-popover/q2-popover.css +3 -2
  93. package/dist/collection/components/q2-popover/q2-popover.js +8 -7
  94. package/dist/collection/components/q2-radio/q2-radio.css +158 -104
  95. package/dist/collection/components/q2-radio/q2-radio.js +1 -1
  96. package/dist/collection/components/q2-radio/test/q2-radio-test.vr.js +25 -2
  97. package/dist/collection/components/q2-radio-group/q2-radio-group.css +39 -2
  98. package/dist/collection/components/q2-radio-group/q2-radio-group.js +68 -2
  99. package/dist/collection/components/q2-radio-group/test/q2-radio-group-test.vr.js +43 -1
  100. package/dist/collection/components/q2-relative-time/q2-relative-time.js +2 -2
  101. package/dist/collection/components/q2-search/q2-search.css +2 -0
  102. package/dist/collection/components/q2-section/q2-section.css +2 -0
  103. package/dist/collection/components/q2-section/q2-section.js +6 -6
  104. package/dist/collection/components/q2-select/q2-select.css +3 -0
  105. package/dist/collection/components/q2-select/q2-select.js +37 -18
  106. package/dist/collection/components/q2-select/test/q2-select-test.vr.js +13 -0
  107. package/dist/collection/components/q2-stepper-pane/q2-stepper-pane.js +1 -1
  108. package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.js +1 -1
  109. package/dist/collection/components/q2-surface/q2-surface.js +1 -1
  110. package/dist/collection/components/q2-tab-container/q2-tab-container.js +1 -1
  111. package/dist/collection/components/q2-tab-pane/q2-tab-pane.js +1 -1
  112. package/dist/collection/components/q2-tag/q2-tag.js +1 -1
  113. package/dist/collection/components/tecton-tab-pane/tecton-tab-pane.js +5 -3
  114. package/dist/collection/utils/index.js +1 -1
  115. package/dist/collection/utils/test/vr-helpers.js +16 -2
  116. package/dist/components/index2.js +1 -1
  117. package/dist/components/q2-btn2.js +1 -1
  118. package/dist/components/q2-calendar.js +11 -9
  119. package/dist/components/q2-card-image.js +24 -24
  120. package/dist/components/q2-checkbox-group.js +6 -6
  121. package/dist/components/q2-checkbox2.js +1 -1
  122. package/dist/components/q2-context.js +27 -26
  123. package/dist/components/q2-data-table.js +1 -1
  124. package/dist/components/q2-dropdown.js +21 -21
  125. package/dist/components/q2-editable-field.js +33 -35
  126. package/dist/components/q2-file-picker.js +70 -10
  127. package/dist/components/q2-input2.js +268 -163
  128. package/dist/components/q2-item2.js +1 -1
  129. package/dist/components/q2-message2.js +24 -24
  130. package/dist/components/q2-modal.js +96 -78
  131. package/dist/components/q2-pill.js +1 -1
  132. package/dist/components/q2-popover2.js +29 -26
  133. package/dist/components/q2-radio-group.js +70 -40
  134. package/dist/components/q2-radio.js +40 -55
  135. package/dist/components/q2-relative-time.js +5 -5
  136. package/dist/components/q2-search.js +1 -1
  137. package/dist/components/q2-section.js +33 -33
  138. package/dist/components/q2-select2.js +46 -39
  139. package/dist/components/q2-stepper-pane.js +15 -11
  140. package/dist/components/q2-stepper-vertical.js +4 -4
  141. package/dist/components/q2-surface.js +3 -3
  142. package/dist/components/q2-tab-container.js +21 -21
  143. package/dist/components/q2-tab-pane.js +2 -2
  144. package/dist/components/q2-tag2.js +5 -5
  145. package/dist/components/tecton-tab-pane.js +8 -7
  146. package/dist/esm/click-elsewhere_3.entry.js +10 -9
  147. package/dist/esm/{index-Cps4jSQM.js → index-DJw6Feh0.js} +1 -1
  148. package/dist/esm/loader.js +1 -1
  149. package/dist/esm/{q2-action-group_2.entry.js → q2-action-group.entry.js} +3 -90
  150. package/dist/esm/q2-action-sheet.entry.js +1 -1
  151. package/dist/esm/q2-badge_2.entry.js +113 -12
  152. package/dist/esm/q2-btn_2.entry.js +2 -2
  153. package/dist/esm/q2-calendar.entry.js +7 -5
  154. package/dist/esm/q2-card-image.entry.js +4 -4
  155. package/dist/esm/q2-card.entry.js +1 -1
  156. package/dist/esm/q2-carousel-pane.entry.js +1 -1
  157. package/dist/esm/q2-carousel.entry.js +1 -1
  158. package/dist/esm/q2-chart-area.entry.js +1 -1
  159. package/dist/esm/q2-chart-bar.entry.js +1 -1
  160. package/dist/esm/q2-chart-donut.entry.js +1 -1
  161. package/dist/esm/q2-checkbox-group.entry.js +2 -2
  162. package/dist/esm/q2-checkbox_2.entry.js +3 -3
  163. package/dist/esm/q2-context.entry.js +4 -3
  164. package/dist/esm/q2-data-table.entry.js +2 -2
  165. package/dist/esm/q2-detail.entry.js +1 -1
  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 +38 -37
  169. package/dist/esm/q2-file-picker.entry.js +60 -4
  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-link_2.entry.js +1 -1
  173. package/dist/esm/q2-loc.entry.js +1 -1
  174. package/dist/esm/q2-message.entry.js +2 -2
  175. package/dist/esm/q2-meter.entry.js +1 -1
  176. package/dist/esm/q2-modal.entry.js +59 -17
  177. package/dist/esm/q2-month-picker.entry.js +1 -1
  178. package/dist/esm/q2-optgroup.entry.js +1 -1
  179. package/dist/esm/q2-option.entry.js +1 -1
  180. package/dist/esm/q2-otp.entry.js +1 -1
  181. package/dist/esm/q2-pagination.entry.js +1 -1
  182. package/dist/esm/q2-pill.entry.js +2 -2
  183. package/dist/esm/q2-radio-group.entry.js +22 -4
  184. package/dist/esm/q2-radio.entry.js +3 -3
  185. package/dist/esm/q2-relative-time.entry.js +3 -3
  186. package/dist/esm/q2-resize-observer.entry.js +90 -0
  187. package/dist/esm/q2-search.entry.js +2 -2
  188. package/dist/esm/q2-section.entry.js +7 -7
  189. package/dist/esm/q2-select.entry.js +35 -19
  190. package/dist/esm/q2-stepper-pane.entry.js +2 -2
  191. package/dist/esm/q2-stepper-vertical.entry.js +2 -2
  192. package/dist/esm/q2-stepper.entry.js +1 -1
  193. package/dist/esm/q2-surface.entry.js +1 -1
  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 +5 -3
  201. package/dist/q2-tecton-elements/click-elsewhere_3.entry.js +32 -29
  202. package/dist/q2-tecton-elements/{index-Cps4jSQM.js → index-DJw6Feh0.js} +1 -1
  203. package/dist/q2-tecton-elements/{q2-action-group_2.entry.js → q2-action-group.entry.js} +35 -113
  204. package/dist/q2-tecton-elements/q2-action-sheet.entry.js +1 -1
  205. package/dist/q2-tecton-elements/q2-badge_2.entry.js +240 -140
  206. package/dist/q2-tecton-elements/q2-btn_2.entry.js +2 -2
  207. package/dist/q2-tecton-elements/q2-calendar.entry.js +14 -12
  208. package/dist/q2-tecton-elements/q2-card-image.entry.js +9 -9
  209. package/dist/q2-tecton-elements/q2-card.entry.js +1 -1
  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 +31 -31
  213. package/dist/q2-tecton-elements/q2-chart-bar.entry.js +16 -16
  214. package/dist/q2-tecton-elements/q2-chart-donut.entry.js +6 -6
  215. package/dist/q2-tecton-elements/q2-checkbox-group.entry.js +2 -2
  216. package/dist/q2-tecton-elements/q2-checkbox_2.entry.js +7 -7
  217. package/dist/q2-tecton-elements/q2-context.entry.js +22 -21
  218. package/dist/q2-tecton-elements/q2-data-table.entry.js +34 -34
  219. package/dist/q2-tecton-elements/q2-detail.entry.js +1 -1
  220. package/dist/q2-tecton-elements/q2-dropdown-item.entry.js +1 -1
  221. package/dist/q2-tecton-elements/q2-dropdown.entry.js +15 -15
  222. package/dist/q2-tecton-elements/q2-editable-field.entry.js +38 -40
  223. package/dist/q2-tecton-elements/q2-file-picker.entry.js +61 -6
  224. package/dist/q2-tecton-elements/q2-icon.entry.js +1 -1
  225. package/dist/q2-tecton-elements/q2-item.entry.js +2 -2
  226. package/dist/q2-tecton-elements/q2-link_2.entry.js +1 -1
  227. package/dist/q2-tecton-elements/q2-loc.entry.js +1 -1
  228. package/dist/q2-tecton-elements/q2-message.entry.js +24 -24
  229. package/dist/q2-tecton-elements/q2-meter.entry.js +1 -1
  230. package/dist/q2-tecton-elements/q2-modal.entry.js +61 -45
  231. package/dist/q2-tecton-elements/q2-month-picker.entry.js +1 -1
  232. package/dist/q2-tecton-elements/q2-optgroup.entry.js +11 -11
  233. package/dist/q2-tecton-elements/q2-option.entry.js +1 -1
  234. package/dist/q2-tecton-elements/q2-otp.entry.js +1 -1
  235. package/dist/q2-tecton-elements/q2-pagination.entry.js +1 -1
  236. package/dist/q2-tecton-elements/q2-pill.entry.js +2 -2
  237. package/dist/q2-tecton-elements/q2-radio-group.entry.js +55 -34
  238. package/dist/q2-tecton-elements/q2-radio.entry.js +38 -53
  239. package/dist/q2-tecton-elements/q2-relative-time.entry.js +12 -12
  240. package/dist/q2-tecton-elements/q2-resize-observer.entry.js +81 -0
  241. package/dist/q2-tecton-elements/q2-search.entry.js +2 -2
  242. package/dist/q2-tecton-elements/q2-section.entry.js +33 -33
  243. package/dist/q2-tecton-elements/q2-select.entry.js +27 -20
  244. package/dist/q2-tecton-elements/q2-stepper-pane.entry.js +20 -16
  245. package/dist/q2-tecton-elements/q2-stepper-vertical.entry.js +5 -5
  246. package/dist/q2-tecton-elements/q2-stepper.entry.js +1 -1
  247. package/dist/q2-tecton-elements/q2-surface.entry.js +3 -3
  248. package/dist/q2-tecton-elements/q2-tab-container.entry.js +20 -20
  249. package/dist/q2-tecton-elements/q2-tab-pane.entry.js +4 -4
  250. package/dist/q2-tecton-elements/q2-tecton-elements.esm.js +1 -1
  251. package/dist/q2-tecton-elements/q2-textarea.entry.js +1 -1
  252. package/dist/q2-tecton-elements/q2-toast.entry.js +1 -1
  253. package/dist/q2-tecton-elements/q2-tooltip.entry.js +1 -1
  254. package/dist/q2-tecton-elements/tecton-tab-pane.entry.js +8 -7
  255. package/dist/types/components/q2-card-image/q2-card-image.d.ts +1 -1
  256. package/dist/types/components/q2-dropdown/test/q2-dropdown-test.vr.d.ts +1 -0
  257. package/dist/types/components/q2-editable-field/q2-editable-field.d.ts +6 -1
  258. package/dist/types/components/q2-file-picker/q2-file-picker.d.ts +20 -0
  259. package/dist/types/components/q2-input/q2-input.d.ts +28 -2
  260. package/dist/types/components/q2-modal/q2-modal.d.ts +10 -1
  261. package/dist/types/components/q2-radio-group/q2-radio-group.d.ts +14 -0
  262. package/dist/types/components/q2-select/q2-select.d.ts +8 -2
  263. package/dist/types/components.d.ts +119 -11
  264. package/dist/types/utils/test/vr-helpers.d.ts +2 -0
  265. package/package.json +3 -3
@@ -364,7 +364,7 @@ export class Q2Dropdown {
364
364
  // #region Render Methods
365
365
  render() {
366
366
  const btnProps = this.toggleButtonProps;
367
- return (h("click-elsewhere", { key: '27e7a560b21894fb10175be18c9cb07e37f59db3', class: this.open ? 'dropdown-open' : '', onChange: this.onClickElsewhere, "test-id": "dropdownContainer" }, h("q2-btn", { key: 'b53dace27e75fdbcd87a1689470a1466ad9e07d3', tabIndex: 0, ref: el => (this.controlElement = el), class: btnProps.className, onClick: this.onToggleClick, onKeyDown: this.onToggleKeydown, fab: btnProps.fab, intent: btnProps.intent, onFocusout: this.handleFocusOut, active: btnProps.active, disabled: btnProps.disabled, ariaExpanded: `${!!btnProps.ariaExpanded}`, label: this.hideLabel && this.label ? loc(this.label) : undefined, hideLabel: this.hideLabel, ariaHasPopup: "menu", "test-id": "dropdownButton", block: this.block, description: loc('tecton.element.dropdown.itemCount', [this.determineDropdownItemCount]) }, this.hasCustomControl ? (h("div", { "test-id": "dropdownControl", class: btnProps.custom ? '' : 'hidden' }, h("slot", { name: "control" }))) : (h(Fragment, null, this.label && !this.hideLabel && (h("span", { class: "dropdown-button-text" }, loc(this.label))), this.icon ? h("q2-icon", { type: this.icon }) : ' '))), h("q2-popover", { key: '4a15e7d6d8f474c8464e39e35437cd8edcc9487d', ref: el => (this.popoverElement = el), controlElement: this.controlElement, open: this.open, "max-height": this.popoverMaxHeight, onFocusout: this.handleFocusOut, minHeight: this.popoverMinHeight, direction: this.popoverDirection, align: this.popoverAlignment, mode: this.popoverMode || undefined, block: this.block }, h("slot", { key: '7854254650f81b8d5a229acbec55aa8beab36882', name: "popover-top" }), h("q2-option-list", { key: 'a38c9411306ad8d39456dce81bb50e9af13bf1f6', onPopoverState: this.onPopoverState, id: "option-list", ref: el => (this.optionList = el), type: "menu", label: loc('tecton.element.optionList.label', [this.optionListLabel]), "no-select": true }, h("slot", { key: '7472127d019366f76eff86cd744d050d197b25c1' })), h("slot", { key: '5af670e8f5ed273175100ddc9202c44e2c06f7b3', name: "popover-bottom" }))));
367
+ return (h("click-elsewhere", { key: 'b71837747b991c78e7ec76cc781dc46b69f15ceb', class: this.open ? 'dropdown-open' : '', onChange: this.onClickElsewhere, "test-id": "dropdownContainer" }, h("q2-btn", { key: '82fe12ed6bc51dd731cd1ff30d315f5bd795ef45', tabIndex: 0, ref: el => (this.controlElement = el), class: btnProps.className, onClick: this.onToggleClick, onKeyDown: this.onToggleKeydown, fab: btnProps.fab, intent: btnProps.intent, onFocusout: this.handleFocusOut, active: btnProps.active, disabled: btnProps.disabled, ariaExpanded: `${!!btnProps.ariaExpanded}`, label: this.hideLabel && this.label ? loc(this.label) : undefined, hideLabel: this.hideLabel, ariaHasPopup: "menu", "test-id": "dropdownButton", block: this.block, description: loc('tecton.element.dropdown.itemCount', [this.determineDropdownItemCount]) }, this.hasCustomControl ? (h("div", { "test-id": "dropdownControl", class: btnProps.custom ? '' : 'hidden' }, h("slot", { name: "control" }))) : (h(Fragment, null, this.label && !this.hideLabel && (h("span", { class: "dropdown-button-text" }, loc(this.label))), this.icon ? h("q2-icon", { type: this.icon }) : ' '))), h("q2-popover", { key: 'b4da967caa9cd12e397b5320c055b3a62b2926ec', ref: el => (this.popoverElement = el), controlElement: this.controlElement, open: this.open, "max-height": this.popoverMaxHeight, onFocusout: this.handleFocusOut, minHeight: this.popoverMinHeight, direction: this.popoverDirection, align: this.popoverAlignment, mode: this.popoverMode || undefined, block: this.block }, h("slot", { key: 'f7a490170ad9429ead0d611adb78dd8272deaaa2', name: "popover-top" }), h("q2-option-list", { key: '87eafcc44a7b5deca4dabd6bc3a3ae04517a5917', onPopoverState: this.onPopoverState, id: "option-list", ref: el => (this.optionList = el), type: "menu", label: loc('tecton.element.optionList.label', [this.optionListLabel]), "no-select": true }, h("slot", { key: '394a44b4490f2b6aff52a8262c5ec3ecc54e9111' })), h("slot", { key: '6e84bdcae4daf64aded5fadcc185dbfab889626e', name: "popover-bottom" }))));
368
368
  }
369
369
  static get is() { return "q2-dropdown"; }
370
370
  static get encapsulation() { return "shadow"; }
@@ -0,0 +1,30 @@
1
+ import { expect } from "@playwright/test";
2
+ import { test } from "@stencil/playwright";
3
+ import { setupPage, THEMES } from "../../../utils/test/vr-helpers";
4
+ const VARIANTS = [
5
+ {
6
+ name: 'chevron',
7
+ html: `<q2-dropdown type="neutral" icon="chevron-down" label="Actions">
8
+ <q2-option value="view">View details</q2-option>
9
+ </q2-dropdown>`,
10
+ },
11
+ {
12
+ name: 'icon',
13
+ html: `<q2-dropdown type="icon" icon="options" label="More actions" hide-label>
14
+ <q2-option value="view">View details</q2-option>
15
+ </q2-dropdown>`,
16
+ },
17
+ ];
18
+ const restingCase = (variant, theme) => {
19
+ test(`q2-dropdown--${variant.name}--resting - ${theme}`, async ({ page }) => {
20
+ await setupPage(page, variant.html, { theme, setupLoc: true });
21
+ await expect(page).toHaveScreenshot(`q2-dropdown--${variant.name}--resting--${theme}.png`);
22
+ });
23
+ };
24
+ test.describe('q2-dropdown - variants x themes', () => {
25
+ for (const variant of VARIANTS) {
26
+ for (const theme of THEMES) {
27
+ restingCase(variant, theme);
28
+ }
29
+ }
30
+ });
@@ -88,6 +88,7 @@ button {
88
88
  }
89
89
  }
90
90
  /**
91
+ * @prop --tct-editable-field-icon-size: (<length>) Controls the size of edit, confirm, and cancel icons.
91
92
  * @prop --tct-editable-field-btn-hover-background: (<color>) Controls the background color of the editable field action buttons (begin, save, cancel) on hover.
92
93
  * @prop --tct-editable-field-btn-icon-stroke-primary: (<color>) Controls the primary stroke color of the editable field action button icons.
93
94
  * @prop --tct-editable-field-btn-icon-stroke-secondary: (<color>) Controls the secondary stroke color of the editable field action button icons.
@@ -101,6 +102,7 @@ button {
101
102
  .q2-editable-field-wrapper .save-edit,
102
103
  .q2-editable-field-wrapper .cancel-edit {
103
104
  flex: 0 0 44px;
105
+ --tct-icon-size: var(--tct-editable-field-icon-size, var(--const-px-18, 18px));
104
106
  --tct-btn-icon-hover-background: var(--tct-editable-field-btn-hover-background, var(--app-gray-l3, #f2f2f2));
105
107
  --tct-icon-stroke-primary: var(--tct-editable-field-btn-icon-stroke-primary, var(--app-gray, #747474));
106
108
  --tct-icon-stroke-secondary: var(--tct-editable-field-btn-icon-stroke-secondary, var(--app-gray, #747474));
@@ -21,15 +21,26 @@ export class Q2EditableField {
21
21
  this.value = '';
22
22
  this.cancelClick = (event) => {
23
23
  event === null || event === void 0 ? void 0 : event.stopPropagation();
24
- mirrorEmit(this, ['change', 'tctChange'], { editing: false, name: 'cancel' });
25
- this.innerValue = undefined;
26
- this.formattedValue = undefined;
27
- this.inputElement.value = '';
28
- this.inputElement.value = this.defaultValue;
24
+ const emittedEvents = this.emitChangeEvents({ editing: false, name: 'cancel' });
25
+ queueMicrotask(() => {
26
+ if (this.isDefaultPrevented(emittedEvents))
27
+ return;
28
+ this.innerValue = undefined;
29
+ this.formattedValue = undefined;
30
+ this.inputElement.value = '';
31
+ this.inputElement.value = this.defaultValue;
32
+ this.inputElement.value = this.value;
33
+ this.editing = false;
34
+ });
29
35
  };
30
36
  this.editClick = (event) => {
31
37
  event === null || event === void 0 ? void 0 : event.stopPropagation();
32
- mirrorEmit(this, ['change', 'tctChange'], { editing: true, name: 'edit' });
38
+ const emittedEvents = this.emitChangeEvents({ editing: true, name: 'edit' });
39
+ queueMicrotask(() => {
40
+ if (this.isDefaultPrevented(emittedEvents))
41
+ return;
42
+ this.editing = true;
43
+ });
33
44
  };
34
45
  this.inputChange = (e) => {
35
46
  e.stopPropagation();
@@ -58,11 +69,18 @@ export class Q2EditableField {
58
69
  this.saveClick = (event) => {
59
70
  event && event.stopPropagation();
60
71
  const valueFromInputProp = this.hostElement.shadowRoot.querySelector('q2-input').value;
61
- mirrorEmit(this, ['change', 'tctChange'], {
62
- editing: false,
63
- name: 'save',
64
- value: this.innerValue || valueFromInputProp,
65
- formattedValue: this.formattedValue || valueFromInputProp,
72
+ const value = this.innerValue || valueFromInputProp;
73
+ const formattedValue = this.formattedValue || valueFromInputProp;
74
+ const emittedEvents = this.emitChangeEvents({ editing: false, name: 'save', value, formattedValue });
75
+ queueMicrotask(() => {
76
+ if (this.isDefaultPrevented(emittedEvents))
77
+ return;
78
+ if (this.hasErrors) {
79
+ this.inputElement.focus();
80
+ return;
81
+ }
82
+ this.value = value;
83
+ this.editing = false;
66
84
  });
67
85
  };
68
86
  }
@@ -81,29 +99,6 @@ export class Q2EditableField {
81
99
  }
82
100
  // #endregion
83
101
  // #region Listeners
84
- onHostElementChange(event) {
85
- if (!isEventFromElement(event, this.hostElement) || this.hostElement.onchange)
86
- return;
87
- queueMicrotask(() => {
88
- switch (event.detail.name) {
89
- case 'save':
90
- if (this.hasErrors) {
91
- this.inputElement.focus();
92
- break;
93
- }
94
- this.value = event.detail.value;
95
- this.editing = event.detail.editing;
96
- break;
97
- case 'cancel':
98
- this.inputElement.value = this.value;
99
- this.editing = event.detail.editing;
100
- break;
101
- case 'edit':
102
- this.editing = event.detail.editing;
103
- break;
104
- }
105
- });
106
- }
107
102
  delegateFocus(event) {
108
103
  if (!isEventFromElement(event, this.hostElement))
109
104
  return;
@@ -199,6 +194,9 @@ export class Q2EditableField {
199
194
  get wrapperClass() {
200
195
  return `q2-editable-field-wrapper ${this.editing ? 'editing' : ''}`;
201
196
  }
197
+ emitChangeEvents(detail) {
198
+ return [this.change.emit(detail), this.tctChange.emit(detail)];
199
+ }
202
200
  generateEditStateDOM() {
203
201
  return (h("div", { class: this.wrapperClass, hidden: !this.editing }, h("q2-input", { ref: el => (this.inputElement = el), label: this.locLabel, hideLabel: this.hideLabel, value: this.value, hints: this.hasHints ? this.hints : undefined, errors: this.hasErrors ? this.errors : undefined, type: this.type, disabled: this.disabled, _updateValueOnInput: false, formatModifier: this.formatModifier, maxlength: this.maxlength, "test-id": "editableInput", onChange: e => e.stopImmediatePropagation(), onInput: e => e.stopImmediatePropagation(), onTctInput: this.inputInput, onTctChange: this.inputChange, onKeyDown: this.inputKeyDown, onClick: this.inputClick }), h("q2-btn", { ref: el => (this.cancelBtnElement = el), class: "cancel-edit", label: `${loc('tecton.element.editableField.cancel')} ${this.locLabel}`, "hide-label": true, "test-id": "cancelButton", onClick: e => e.stopImmediatePropagation(), onTctClick: this.cancelClick }, h("q2-icon", { type: "close" })), h("q2-btn", { ref: el => (this.saveBtnElement = el), class: "save-edit", label: `${loc('tecton.element.editableField.save')} ${this.locLabel}`, "hide-label": true, "test-id": "saveButton", onClick: e => e.stopImmediatePropagation(), onTctClick: this.saveClick }, h("q2-icon", { type: "checkmark" }))));
204
202
  }
@@ -208,10 +206,13 @@ export class Q2EditableField {
208
206
  }
209
207
  return (h("div", { class: this.wrapperClass, hidden: this.editing }, h("div", { class: "text-wrapper" }, this.formattedValue || this.value), h("q2-btn", { ref: el => (this.editBtnElement = el), class: "begin-edit", label: `${loc('tecton.element.editableField.edit')} ${this.locLabel}`, "hide-label": true, disabled: this.disabled, "test-id": "editButton", onClick: e => e.stopImmediatePropagation(), onTctClick: this.editClick }, h("q2-icon", { type: "edit" }))));
210
208
  }
209
+ isDefaultPrevented(events) {
210
+ return this.hostElement.onchange != null || events.some(event => event.defaultPrevented);
211
+ }
211
212
  // #endregion
212
213
  // #region Render Methods
213
214
  render() {
214
- return (h("div", { key: 'bd200b48458ec6c7cb6c6928a1758420dbca66e3' }, this.generateEditStateDOM(), this.generateReadStateDOM()));
215
+ return (h("div", { key: '73dfc2198007dc7366243914bb055db3f8ebda3a' }, this.generateEditStateDOM(), this.generateReadStateDOM()));
215
216
  }
216
217
  static get is() { return "q2-editable-field"; }
217
218
  static get encapsulation() { return "shadow"; }
@@ -530,7 +531,7 @@ export class Q2EditableField {
530
531
  "name": "deprecated",
531
532
  "text": "Use 'tctChange' instead"
532
533
  }],
533
- "text": "Emitted when the 'Edit', 'Cancel', or 'Save' buttons are clicked.\n\nThe event detail will not include a `value` or `formattedValue` if the event name is 'edit' or 'cancel'."
534
+ "text": "Emitted when the 'Edit', 'Cancel', or 'Save' buttons are clicked.\n\nThe event detail will not include a `value` or `formattedValue` if the event name is 'edit' or 'cancel'.\n\nCall `event.preventDefault()` to prevent the default behavior (the component's internal `editing` and `value` updates)."
534
535
  },
535
536
  "complexType": {
536
537
  "original": "{\n editing: boolean;\n name: 'edit' | 'cancel' | 'save';\n value?: string;\n formattedValue?: string;\n }",
@@ -566,7 +567,7 @@ export class Q2EditableField {
566
567
  "name": "info",
567
568
  "text": "If you are utilizing events to provide input validation, it is recommended you use the `input` event, not the `change` event."
568
569
  }],
569
- "text": "Emitted when the 'Edit', 'Cancel', or 'Save' buttons are clicked.\n\nThe event detail will not include a `value` or `formattedValue` if the event name is 'edit' or 'cancel'."
570
+ "text": "Emitted when the 'Edit', 'Cancel', or 'Save' buttons are clicked.\n\nThe event detail will not include a `value` or `formattedValue` if the event name is 'edit' or 'cancel'.\n\nCall `event.preventDefault()` to prevent the default behavior (the component's internal `editing` and `value` updates)."
570
571
  },
571
572
  "complexType": {
572
573
  "original": "{\n editing: boolean;\n name: 'edit' | 'cancel' | 'save';\n value?: string;\n formattedValue?: string;\n }",
@@ -685,12 +686,6 @@ export class Q2EditableField {
685
686
  }
686
687
  static get listeners() {
687
688
  return [{
688
- "name": "change",
689
- "method": "onHostElementChange",
690
- "target": undefined,
691
- "capture": false,
692
- "passive": false
693
- }, {
694
689
  "name": "focus",
695
690
  "method": "delegateFocus",
696
691
  "target": undefined,
@@ -230,6 +230,7 @@ button {
230
230
  * @prop --tct-file-picker-item-close-btn-border-radius: (<length-percentage>) Controls the corner radius of the file item close button.
231
231
  * @prop --tct-file-picker-item-close-btn-size: (<length>) Controls the width and height of the file item close button.
232
232
  * @prop --tct-file-picker-list-max-height: (<length-percentage>) Controls the maximum height of the file list container before scrolling.
233
+ * @prop --tct-file-picker-list-gradient-height: (<length-percentage>) Controls the height of the fade indicating more files are available below the visible list.
233
234
  * @prop --tct-file-picker-scrollbar-color: (<color>) Controls the scrollbar thumb color of the file list container.
234
235
  * @prop --tct-file-picker-loading-size: (<length>) Controls the font size driving the picker-level loading spinner.
235
236
  * @prop --tct-file-picker-loading-file-color: (<color>) Controls the text color of the loading-file message.
@@ -357,6 +358,28 @@ button {
357
358
  white-space: nowrap;
358
359
  }
359
360
 
361
+ .file-name-header {
362
+ display: flex;
363
+ align-items: center;
364
+ min-width: 0;
365
+ white-space: nowrap;
366
+ width: 100%;
367
+ }
368
+
369
+ .file-name-leading {
370
+ flex: 0 1 auto;
371
+ min-width: 0;
372
+ overflow: hidden;
373
+ text-overflow: ellipsis;
374
+ }
375
+
376
+ .file-name-trailing {
377
+ direction: rtl;
378
+ flex: 0 0 auto;
379
+ max-width: 50%;
380
+ overflow: hidden;
381
+ }
382
+
360
383
  .file-item-loading {
361
384
  /* stylelint-disable-next-line tecton/require-t-px-fallback */
362
385
  font-size: var(--tct-file-picker-file-item-loading-size, var(--app-scale-6x, 30px));
@@ -375,6 +398,10 @@ button {
375
398
  scrollbar-width: thin;
376
399
  scrollbar-color: var(--tct-file-picker-scrollbar-color, var(--t-a11y-gray-color, #949494)) transparent;
377
400
  }
401
+ .file-list-container.more-files {
402
+ -webkit-mask-image: linear-gradient(to bottom, currentColor calc(100% - var(--tct-file-picker-list-gradient-height, var(--app-scale-12x, 60px))), transparent 100%);
403
+ mask-image: linear-gradient(to bottom, currentColor calc(100% - var(--tct-file-picker-list-gradient-height, var(--app-scale-12x, 60px))), transparent 100%);
404
+ }
378
405
 
379
406
  .file-picker {
380
407
  display: flex;
@@ -24,6 +24,12 @@ export class Q2FilePicker {
24
24
  * The size of the browse button.
25
25
  */
26
26
  this.buttonSize = 'medium';
27
+ /**
28
+ * When `false`, the file name renders as-is and may wrap. Otherwise, long
29
+ * file names are middle-ellipsized so the beginning and end of the name
30
+ * remain visible.
31
+ */
32
+ this.ellipsizeFileName = true;
27
33
  /**
28
34
  * Allowed file types based on extensions (e.g., ['jpg', 'png', 'pdf'] or
29
35
  * 'jpg, png, pdf'). When using the attribute, provide a comma-separated
@@ -39,6 +45,10 @@ export class Q2FilePicker {
39
45
  * The maximum size (in bytes) of any file that can be selected.
40
46
  */
41
47
  this.maxFileSize = Infinity;
48
+ /**
49
+ * Shows a gradient at the bottom of the file list when more files are available below the visible area.
50
+ */
51
+ this.showGradient = true;
42
52
  /**
43
53
  * An array of `ValidFileStatus` objects representing the upload status of
44
54
  * files. Each `ValidFileStatus` object contains the following properties:
@@ -85,14 +95,21 @@ export class Q2FilePicker {
85
95
  this.disableEvent(e);
86
96
  this.isDropZoneHighlighted = true;
87
97
  };
98
+ this.updateFileListGradient = () => {
99
+ if (!this.fileListContainer)
100
+ return;
101
+ const { clientHeight, scrollHeight, scrollTop } = this.fileListContainer;
102
+ const hasMoreFiles = this.showGradient && scrollHeight > clientHeight && Math.ceil(scrollTop) + clientHeight < scrollHeight;
103
+ this.fileListContainer.classList.toggle('more-files', hasMoreFiles);
104
+ };
88
105
  // #endregion
89
106
  // #region Render Methods
90
107
  this.render = () => {
91
108
  const { disabled } = this;
92
- return (h("div", { class: "file-picker" }, (this.hasLabel || this.hasDescription) && (h("div", { class: "heading" }, this.hasLabel && (h("label", { class: "label", htmlFor: "file-field", "test-id": "label" }, !!this.label ? loc(this.label) : this.hasLabelSlotContent ? h("slot", { name: "label" }) : '')), this.hasDescription && (h("div", { class: "description", id: "description", "test-id": "description" }, !!this.description ? (loc(this.description)) : this.hasDescriptionSlotContent ? (h("slot", { name: "description" })) : (''))))), (this.variant === 'browse-drop' && (h("div", { class: this.dropZoneClasses, onDragEnter: this.disableEvent, onDragLeave: this.dimDropZone, onDragOver: this.highlightDropZone, onDrop: this.grabDroppedFiles, ref: el => (this.dropZone = el !== null && el !== void 0 ? el : this.dropZone), "test-id": "drop-zone" }, (this.areFilesUploading && (h(Fragment, null, h("q2-loading", { class: "loading" }), h("p", { class: "drop-zone-text" }, loc('tecton.element.filePicker.uploadingEllipsis'))))) || (h(Fragment, null, h("q2-icon", { type: "upload" }), h("p", { class: "drop-zone-text" }, h("q2-link", { class: "browse-link", label: loc('tecton.element.filePicker.browse'), onTctClick: () => this.launchFileBrowser(), variant: "inline", "test-id": "browse-link", disabled: disabled, href: "javascript:void(0)" }), loc('tecton.element.filePicker.orDragFilesHere', [this.maxFiles]))))))) || (h("div", { class: "browse", "test-id": "browse" }, h("q2-btn", { disabled: disabled || this.areFilesUploading, intent: "workflow-primary", loading: this.areFilesUploading, onClick: () => this.launchFileBrowser(), size: this.actualButtonSize, "test-id": "browse-button" }, h("q2-icon", { type: "paperclip" }), h("span", null, loc('tecton.element.filePicker.attachFiles', [this.maxFiles]))))), h("input", { "aria-describedby": (!!this.description && 'description') || undefined, class: "sr", id: "file-field", onChange: this.grabSelectedFiles, ref: el => (this.browseButtonInput = el !== null && el !== void 0 ? el : this.browseButtonInput), type: "file", "test-id": "file-input", disabled: disabled, multiple: true, tabIndex: -1 }), h("div", { class: "file-list-container" }, h("q2-list", { class: "file-list" }, this.displayedFiles.map(file => (h("q2-item", { class: this.getFileItemClasses(file.file.name), key: file.file.name, onAnimationEnd: this.getAnimationendHandlerToRemoveFileItem(file.file.name) }, h("div", { slot: "decorator" }, file.status === 'invalid-type' ||
109
+ return (h("div", { class: "file-picker" }, (this.hasLabel || this.hasDescription) && (h("div", { class: "heading" }, this.hasLabel && (h("label", { class: "label", htmlFor: "file-field", "test-id": "label" }, !!this.label ? loc(this.label) : this.hasLabelSlotContent ? h("slot", { name: "label" }) : '')), this.hasDescription && (h("div", { class: "description", id: "description", "test-id": "description" }, !!this.description ? (loc(this.description)) : this.hasDescriptionSlotContent ? (h("slot", { name: "description" })) : (''))))), (this.variant === 'browse-drop' && (h("div", { class: this.dropZoneClasses, onDragEnter: this.disableEvent, onDragLeave: this.dimDropZone, onDragOver: this.highlightDropZone, onDrop: this.grabDroppedFiles, ref: el => (this.dropZone = el !== null && el !== void 0 ? el : this.dropZone), "test-id": "drop-zone" }, (this.areFilesUploading && (h(Fragment, null, h("q2-loading", { class: "loading" }), h("p", { class: "drop-zone-text" }, loc('tecton.element.filePicker.uploadingEllipsis'))))) || (h(Fragment, null, h("q2-icon", { type: "upload" }), h("p", { class: "drop-zone-text" }, h("q2-link", { class: "browse-link", label: loc('tecton.element.filePicker.browse'), onTctClick: () => this.launchFileBrowser(), variant: "inline", "test-id": "browse-link", disabled: disabled, href: "javascript:void(0)" }), loc('tecton.element.filePicker.orDragFilesHere', [this.maxFiles]))))))) || (h("div", { class: "browse", "test-id": "browse" }, h("q2-btn", { block: this.isMobileViewport, disabled: disabled || this.areFilesUploading, intent: "workflow-primary", loading: this.areFilesUploading, onClick: () => this.launchFileBrowser(), size: this.actualButtonSize, "test-id": "browse-button" }, h("q2-icon", { type: "paperclip" }), h("span", null, loc('tecton.element.filePicker.attachFiles', [this.maxFiles]))))), h("input", { "aria-describedby": (!!this.description && 'description') || undefined, class: "sr", id: "file-field", onChange: this.grabSelectedFiles, ref: el => (this.browseButtonInput = el !== null && el !== void 0 ? el : this.browseButtonInput), type: "file", "test-id": "file-input", disabled: disabled, multiple: true, tabIndex: -1 }), h("div", { class: "file-list-container", onScroll: this.updateFileListGradient, ref: el => (this.fileListContainer = el !== null && el !== void 0 ? el : this.fileListContainer) }, h("q2-list", { class: "file-list", ref: el => (this.fileList = el !== null && el !== void 0 ? el : this.fileList) }, this.displayedFiles.map(file => (h("q2-item", { class: this.getFileItemClasses(file.file.name), key: file.file.name, onAnimationEnd: this.getAnimationendHandlerToRemoveFileItem(file.file.name) }, h("div", { slot: "decorator" }, file.status === 'invalid-type' ||
93
110
  file.status === 'over-size-limit' ||
94
111
  file.status === 'failed' ||
95
- file.status === 'over-max-files-limit' ? (h("q2-icon", { class: "icon-error", type: "error" })) : file.status === 'in-progress' ? (h("q2-loading", { class: "file-item-loading", "hide-from-screen-readers": true })) : (h("q2-icon", { class: "icon-success", type: "success" }))), h("div", { slot: "header" }, file.file.name), h("div", { class: "file-item-info", slot: "body" }, this.getFileItemStatusMessage(file)), h("div", { slot: "action" }, h("q2-btn", { class: "dismiss-button", intent: "neutral-text", "hide-label": "true", label: this.getFileItemButtonLabel(file), onClick: this.getClickHandlerToRemoveFileItem(file.file.name), disabled: disabled }, h("q2-icon", { type: "close" }))))))))));
112
+ file.status === 'over-max-files-limit' ? (h("q2-icon", { class: "icon-error", type: "error" })) : file.status === 'in-progress' ? (h("q2-loading", { class: "file-item-loading", "hide-from-screen-readers": true })) : (h("q2-icon", { class: "icon-success", type: "success" }))), this.ellipsizeFileName === false ? (h("div", { slot: "header" }, file.file.name)) : (h("div", { class: "file-name-header", slot: "header" }, h("span", { class: "file-name-leading" }, file.file.name.slice(0, Math.ceil(file.file.name.length / 2))), h("span", { class: "file-name-trailing" }, h("bdo", { dir: "ltr" }, file.file.name.slice(Math.ceil(file.file.name.length / 2)))))), h("div", { class: "file-item-info", slot: "body" }, this.getFileItemStatusMessage(file)), h("div", { slot: "action" }, h("q2-btn", { class: "dismiss-button", intent: "neutral-text", "hide-label": "true", label: this.getFileItemButtonLabel(file), onClick: this.getClickHandlerToRemoveFileItem(file.file.name), disabled: disabled }, h("q2-icon", { type: "close" }))))))))));
96
113
  };
97
114
  }
98
115
  /**
@@ -116,7 +133,29 @@ export class Q2FilePicker {
116
133
  console.error('Setting the value of this component directly is not allowed.');
117
134
  }
118
135
  // #endregion
136
+ // #region Component Lifecycle Events
137
+ disconnectedCallback() {
138
+ var _a;
139
+ (_a = this.fileListResizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
140
+ }
141
+ componentDidLoad() {
142
+ if (typeof ResizeObserver !== 'function')
143
+ return;
144
+ this.fileListResizeObserver = new ResizeObserver(this.updateFileListGradient);
145
+ this.observeFileListContent();
146
+ }
147
+ componentDidRender() {
148
+ this.observeFileListContent();
149
+ this.updateFileListGradient();
150
+ if (typeof requestAnimationFrame === 'function') {
151
+ requestAnimationFrame(this.updateFileListGradient);
152
+ }
153
+ }
154
+ // #endregion
119
155
  // #region Watchers
156
+ updateGradientVisibility() {
157
+ this.updateFileListGradient();
158
+ }
120
159
  updateFileList(newValue) {
121
160
  newValue.forEach(statusItem => {
122
161
  const matchingQueuedFileIndex = this.queuedFiles.findIndex(file => file.name === statusItem.name);
@@ -166,6 +205,11 @@ export class Q2FilePicker {
166
205
  get hasLabelSlotContent() {
167
206
  return hasSlotContent(this.el, 'label');
168
207
  }
208
+ get isMobileViewport() {
209
+ return typeof window !== 'undefined' && window.matchMedia
210
+ ? window.matchMedia('(max-width: 479px)').matches
211
+ : false;
212
+ }
169
213
  buildFilesObject(filesToUpload) {
170
214
  const invalidFiles = [];
171
215
  invalidFiles.push(...this.extractFilesOfInvalidTypes(filesToUpload));
@@ -300,6 +344,15 @@ export class Q2FilePicker {
300
344
  launchFileBrowser() {
301
345
  this.browseButtonInput.dispatchEvent(new MouseEvent('click'));
302
346
  }
347
+ observeFileListContent() {
348
+ if (!this.fileListResizeObserver || !this.fileList)
349
+ return;
350
+ this.fileListResizeObserver.disconnect();
351
+ this.fileListResizeObserver.observe(this.fileList);
352
+ this.fileList.querySelectorAll('q2-item').forEach(fileItem => {
353
+ this.fileListResizeObserver.observe(fileItem);
354
+ });
355
+ }
303
356
  static get is() { return "q2-file-picker"; }
304
357
  static get encapsulation() { return "shadow"; }
305
358
  static get originalStyleUrls() {
@@ -375,6 +428,26 @@ export class Q2FilePicker {
375
428
  "reflect": true,
376
429
  "attribute": "disabled"
377
430
  },
431
+ "ellipsizeFileName": {
432
+ "type": "boolean",
433
+ "mutable": false,
434
+ "complexType": {
435
+ "original": "boolean",
436
+ "resolved": "boolean",
437
+ "references": {}
438
+ },
439
+ "required": false,
440
+ "optional": false,
441
+ "docs": {
442
+ "tags": [],
443
+ "text": "When `false`, the file name renders as-is and may wrap. Otherwise, long\nfile names are middle-ellipsized so the beginning and end of the name\nremain visible."
444
+ },
445
+ "getter": false,
446
+ "setter": false,
447
+ "reflect": true,
448
+ "attribute": "ellipsize-file-name",
449
+ "defaultValue": "true"
450
+ },
378
451
  "fileTypes": {
379
452
  "type": "string",
380
453
  "mutable": false,
@@ -457,6 +530,26 @@ export class Q2FilePicker {
457
530
  "attribute": "max-file-size",
458
531
  "defaultValue": "Infinity"
459
532
  },
533
+ "showGradient": {
534
+ "type": "boolean",
535
+ "mutable": false,
536
+ "complexType": {
537
+ "original": "boolean",
538
+ "resolved": "boolean",
539
+ "references": {}
540
+ },
541
+ "required": false,
542
+ "optional": false,
543
+ "docs": {
544
+ "tags": [],
545
+ "text": "Shows a gradient at the bottom of the file list when more files are available below the visible area."
546
+ },
547
+ "getter": false,
548
+ "setter": false,
549
+ "reflect": true,
550
+ "attribute": "show-gradient",
551
+ "defaultValue": "true"
552
+ },
460
553
  "status": {
461
554
  "type": "unknown",
462
555
  "mutable": false,
@@ -571,6 +664,9 @@ export class Q2FilePicker {
571
664
  static get elementRef() { return "el"; }
572
665
  static get watchers() {
573
666
  return [{
667
+ "propName": "showGradient",
668
+ "methodName": "updateGradientVisibility"
669
+ }, {
574
670
  "propName": "status",
575
671
  "methodName": "updateFileList"
576
672
  }];
@@ -102,3 +102,25 @@ test.describe(`q2-file-picker — scaled font size × themes`, () => {
102
102
  }
103
103
  }
104
104
  });
105
+ test('q2-file-picker--scrollable-file-list--resting — default-2026', async ({ page }) => {
106
+ await setupPage(page, '<q2-file-picker file-types="pdf" max-files="1"></q2-file-picker>', {
107
+ theme: 'default-2026',
108
+ setupLoc: true,
109
+ });
110
+ await page.evaluate(() => {
111
+ const filePicker = document.querySelector('q2-file-picker');
112
+ const input = filePicker.shadowRoot.querySelector('[test-id="file-input"]');
113
+ const files = new DataTransfer();
114
+ for (let index = 0; index < 6; index += 1) {
115
+ files.items.add(new File(['content'], `file-${index}.txt`, { type: 'text/plain' }));
116
+ }
117
+ input.files = files.files;
118
+ input.dispatchEvent(new Event('change'));
119
+ });
120
+ await expect(page.locator('.file-list-container.more-files')).toHaveCount(1);
121
+ await expect(page).toHaveScreenshot('q2-file-picker--scrollable-file-list--resting--default-2026.png');
122
+ await page.locator('q2-file-picker').evaluate((filePicker) => {
123
+ filePicker.showGradient = false;
124
+ });
125
+ await expect(page.locator('.file-list-container.more-files')).toHaveCount(0);
126
+ });
@@ -167,6 +167,7 @@ button {
167
167
  * @prop --tct-input-count-width: (<length-percentage>) Controls the width of the character-count indicator.
168
168
  * @prop --tct-input-icon-stroke-primary: (<color>) Controls the primary stroke color of icons rendered inside the input.
169
169
  * @prop --tct-input-icon-stroke-secondary: (<color>) Controls the secondary stroke color of icons rendered inside the input.
170
+ * @prop --tct-input-icon-size: (<length>) Controls the size of icons rendered inside the input.
170
171
  * @prop --tct-input-icon-container-font-size?: (<length-percentage>) Controls the optional font size of content inside the input icon containers.
171
172
  * @prop --tct-input-icon-container-icon-min-width: (<length>) Controls the minimum width of icon slots inside the input icon containers.
172
173
  * @prop --tct-input-icon-container-empty-display: (<custom-ident>) Controls the display value of icon containers when empty.
@@ -194,6 +195,7 @@ button {
194
195
  display: block;
195
196
  margin: var(--tct-input-margin, var(--comp-default-input-margin));
196
197
  font-size: var(--tct-input-font-size, var(--t-input-font-size, var(--app-font-size, inherit)));
198
+ letter-spacing: inherit;
197
199
  }
198
200
 
199
201
  :host([hidden]) {
@@ -210,7 +212,7 @@ button {
210
212
  }
211
213
  .field-container.is-small .btn-clear {
212
214
  --tct-btn-icon-width: 20px;
213
- --tct-icon-size: 17px;
215
+ --tct-icon-size: var(--tct-input-icon-size, var(--const-px-18, 18px));
214
216
  }
215
217
 
216
218
  .input-label {
@@ -344,6 +346,58 @@ button {
344
346
  -webkit-text-fill-color: var(--tct-input-autofill-font-color, var(--t-text, inherit));
345
347
  }
346
348
 
349
+ .standard-input-container {
350
+ position: relative;
351
+ display: flex;
352
+ flex: 1;
353
+ min-width: 0;
354
+ }
355
+
356
+ .visible-last-count-value {
357
+ position: absolute;
358
+ inset: 0;
359
+ z-index: 0;
360
+ box-sizing: border-box;
361
+ display: flex;
362
+ align-items: center;
363
+ overflow: hidden;
364
+ padding: var(--tct-input-padding, 0);
365
+ color: var(--tct-input-font-color, var(--t-input-font-color, var(--t-text, inherit)));
366
+ font-weight: var(--tct-input-font-weight, var(--t-input-font-weight, 400));
367
+ font-family: var(--tct-input-visible-last-count-font-family, monospace);
368
+ letter-spacing: var(--tct-input-letter-spacing, var(--t-input-letter-spacing, inherit));
369
+ pointer-events: none;
370
+ text-overflow: ellipsis;
371
+ white-space: nowrap;
372
+ }
373
+
374
+ .visible-last-count-content {
375
+ display: inline-flex;
376
+ align-items: center;
377
+ flex: 0 0 auto;
378
+ transform: translateX(calc(var(--tct-input-visible-last-count-scroll-left, 0px) * -1));
379
+ }
380
+
381
+ .visible-last-count-character {
382
+ display: inline-grid;
383
+ flex: 0 0 auto;
384
+ }
385
+ .visible-last-count-character::before {
386
+ content: attr(data-character);
387
+ grid-area: 1/1;
388
+ visibility: hidden;
389
+ }
390
+
391
+ .visible-last-count-visible-value {
392
+ flex: 0 0 auto;
393
+ }
394
+
395
+ .visible-last-count-mask {
396
+ grid-area: 1/1;
397
+ justify-self: center;
398
+ transform: translateY(var(--tct-input-visible-last-count-mask-translate-y, 0));
399
+ }
400
+
347
401
  .input-field {
348
402
  flex: 1;
349
403
  border: 0;
@@ -365,6 +419,14 @@ button {
365
419
  /* To remove up/down arrow in number field for webkit based browser */
366
420
  /* For Firefox */
367
421
  }
422
+ .input-field.has-visible-last-count {
423
+ position: relative;
424
+ z-index: 1;
425
+ color: transparent;
426
+ caret-color: var(--tct-input-font-color, var(--t-input-font-color, var(--t-text, auto)));
427
+ -webkit-text-fill-color: transparent;
428
+ font-family: var(--tct-input-visible-last-count-font-family, monospace);
429
+ }
368
430
  .input-field:focus {
369
431
  outline: none;
370
432
  box-shadow: none;
@@ -441,6 +503,7 @@ button {
441
503
 
442
504
  .input-icons-container-left,
443
505
  .input-icons-container-right {
506
+ --tct-icon-size: var(--tct-input-icon-size, var(--const-px-18, 18px));
444
507
  --tct-btn-icon-hover-background: var(--tct-input-btn-hover-background);
445
508
  --tct-btn-hover-background: var(--tct-input-btn-hover-background);
446
509
  display: flex;
@@ -553,6 +616,9 @@ q2-icon {
553
616
  color: var(--tct-input-messages-font-color, var(--t-input-messages-font-color, inherit));
554
617
  border-radius: var(--tct-message-border-radius, var(--app-border-radius-1, inherit));
555
618
  }
619
+ .messages-container li:only-child {
620
+ list-style: none;
621
+ }
556
622
 
557
623
  .has-error label {
558
624
  color: var(--tct-input-error-label-font-color, var(--t-input-error-label-font-color, var(--tct-input-label-font-color, var(--t-input-label-font-color, inherit))));