@pine-ds/core 4.3.0 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/components/closest.js +1 -1
  2. package/components/floating-ui.dom.js +1 -1
  3. package/components/i18n-format.js +1 -1
  4. package/components/index.d.ts +2 -0
  5. package/components/index.js +1 -1
  6. package/components/index2.js +1 -1
  7. package/components/mock-pds-modal.js +1 -1
  8. package/components/pds-button2.js +1 -1
  9. package/components/pds-checkbox2.js +1 -1
  10. package/components/pds-chip2.js +1 -1
  11. package/components/pds-combobox.js +2 -2
  12. package/components/pds-container.js +1 -1
  13. package/components/pds-copytext.js +1 -1
  14. package/components/pds-datepicker.d.ts +11 -0
  15. package/components/pds-datepicker.js +1 -0
  16. package/components/pds-divider.js +1 -1
  17. package/components/pds-drawer-content.js +1 -1
  18. package/components/pds-drawer-footer.js +1 -1
  19. package/components/pds-drawer-header.js +1 -1
  20. package/components/pds-drawer.js +1 -1
  21. package/components/pds-dropdown-menu-item.js +1 -1
  22. package/components/pds-dropdown-menu-separator.js +1 -1
  23. package/components/pds-dropdown-menu.js +1 -1
  24. package/components/pds-filter.js +1 -1
  25. package/components/pds-filters.js +1 -1
  26. package/components/pds-image.js +1 -1
  27. package/components/pds-input.js +1 -1
  28. package/components/pds-input2.js +1 -0
  29. package/components/pds-link2.js +1 -1
  30. package/components/pds-loader2.js +1 -1
  31. package/components/pds-modal-content.js +1 -1
  32. package/components/pds-modal-footer.js +1 -1
  33. package/components/pds-modal-header.js +1 -1
  34. package/components/pds-modal2.js +1 -1
  35. package/components/pds-multiselect.js +1 -1
  36. package/components/pds-popover.js +1 -1
  37. package/components/pds-progress.js +1 -1
  38. package/components/pds-property.js +1 -1
  39. package/components/pds-radio-group.js +1 -1
  40. package/components/pds-radio.js +1 -1
  41. package/components/pds-row.js +1 -1
  42. package/components/pds-select.js +1 -1
  43. package/components/pds-sortable-item.js +1 -1
  44. package/components/pds-sortable.js +2 -2
  45. package/components/pds-switch.js +1 -1
  46. package/components/pds-table-body.js +1 -1
  47. package/components/pds-table-cell2.js +1 -1
  48. package/components/pds-table-head-cell2.js +1 -1
  49. package/components/pds-table-head.js +1 -1
  50. package/components/pds-table-row.js +1 -1
  51. package/components/pds-tabpanel.js +1 -1
  52. package/components/pds-tabs.js +1 -1
  53. package/components/pds-text2.js +1 -1
  54. package/components/pds-textarea.js +1 -1
  55. package/components/pds-toast.js +1 -1
  56. package/components/pds-tooltip.js +1 -1
  57. package/components/utils.js +1 -1
  58. package/dist/cjs/closest-D0qyYtJ3.js +20 -0
  59. package/dist/cjs/{floating-ui.dom-BZk7Blsu.js → floating-ui.dom-Dc8Anyel.js} +79 -0
  60. package/dist/cjs/{i18n-format-CrpIhahc.js → i18n-format-BD0PmYzT.js} +1 -0
  61. package/dist/cjs/{index-CaLa1zy9.js → index-Bl5KnQay.js} +4 -1
  62. package/dist/cjs/{index-DYvijwA6.js → index-D-QQKB0y.js} +8 -0
  63. package/dist/cjs/loader.cjs.js +2 -2
  64. package/dist/cjs/mock-pds-modal.cjs.entry.js +3 -3
  65. package/dist/cjs/pds-accordion.cjs.entry.js +2 -2
  66. package/dist/cjs/pds-alert.cjs.entry.js +1 -1
  67. package/dist/cjs/pds-avatar.cjs.entry.js +2 -2
  68. package/dist/cjs/pds-box.cjs.entry.js +2 -2
  69. package/dist/cjs/pds-button.cjs.entry.js +53 -4
  70. package/dist/cjs/pds-checkbox.cjs.entry.js +14 -6
  71. package/dist/cjs/pds-chip.cjs.entry.js +6 -6
  72. package/dist/cjs/pds-combobox.cjs.entry.js +1225 -117
  73. package/dist/cjs/pds-container.cjs.entry.js +2 -2
  74. package/dist/cjs/pds-copytext.cjs.entry.js +5 -5
  75. package/dist/cjs/pds-datepicker.cjs.entry.js +1962 -0
  76. package/dist/cjs/pds-divider.cjs.entry.js +2 -2
  77. package/dist/cjs/pds-drawer-content.cjs.entry.js +2 -2
  78. package/dist/cjs/pds-drawer-footer.cjs.entry.js +2 -2
  79. package/dist/cjs/pds-drawer-header.cjs.entry.js +2 -2
  80. package/dist/cjs/pds-drawer.cjs.entry.js +11 -4
  81. package/dist/cjs/pds-dropdown-menu-item.cjs.entry.js +2 -2
  82. package/dist/cjs/pds-dropdown-menu-separator.cjs.entry.js +2 -2
  83. package/dist/cjs/pds-dropdown-menu.cjs.entry.js +11 -4
  84. package/dist/cjs/pds-filter.cjs.entry.js +3 -3
  85. package/dist/cjs/pds-filters.cjs.entry.js +2 -2
  86. package/dist/cjs/pds-icon.cjs.entry.js +1 -1
  87. package/dist/cjs/pds-image.cjs.entry.js +3 -3
  88. package/dist/cjs/pds-input.cjs.entry.js +8 -5
  89. package/dist/cjs/pds-link.cjs.entry.js +5 -5
  90. package/dist/cjs/pds-loader.cjs.entry.js +2 -2
  91. package/dist/cjs/pds-modal-content.cjs.entry.js +3 -3
  92. package/dist/cjs/pds-modal-footer.cjs.entry.js +2 -2
  93. package/dist/cjs/pds-modal-header.cjs.entry.js +2 -2
  94. package/dist/cjs/pds-modal.cjs.entry.js +12 -6
  95. package/dist/cjs/pds-multiselect.cjs.entry.js +264 -51
  96. package/dist/cjs/pds-popover.cjs.entry.js +30 -12
  97. package/dist/cjs/pds-progress.cjs.entry.js +3 -3
  98. package/dist/cjs/pds-property.cjs.entry.js +2 -2
  99. package/dist/cjs/pds-radio-group.cjs.entry.js +5 -5
  100. package/dist/cjs/pds-radio.cjs.entry.js +5 -5
  101. package/dist/cjs/pds-row.cjs.entry.js +2 -2
  102. package/dist/cjs/pds-select.cjs.entry.js +3 -3
  103. package/dist/cjs/pds-sortable-item.cjs.entry.js +3 -3
  104. package/dist/cjs/pds-sortable.cjs.entry.js +2 -2
  105. package/dist/cjs/pds-switch.cjs.entry.js +14 -6
  106. package/dist/cjs/pds-tab.cjs.entry.js +1 -1
  107. package/dist/cjs/pds-table-body.cjs.entry.js +2 -2
  108. package/dist/cjs/pds-table-cell.cjs.entry.js +5 -5
  109. package/dist/cjs/pds-table-head-cell.cjs.entry.js +4 -4
  110. package/dist/cjs/pds-table-head.cjs.entry.js +3 -3
  111. package/dist/cjs/pds-table-row.cjs.entry.js +3 -3
  112. package/dist/cjs/pds-table.cjs.entry.js +1 -1
  113. package/dist/cjs/pds-tabpanel.cjs.entry.js +2 -2
  114. package/dist/cjs/pds-tabs.cjs.entry.js +2 -2
  115. package/dist/cjs/pds-text.cjs.entry.js +5 -5
  116. package/dist/cjs/pds-textarea.cjs.entry.js +14 -9
  117. package/dist/cjs/pds-toast.cjs.entry.js +4 -4
  118. package/dist/cjs/pds-tooltip.cjs.entry.js +4 -4
  119. package/dist/cjs/pine-core.cjs.js +2 -2
  120. package/dist/cjs/{truncation-tooltip-Bps7_rUy.js → truncation-tooltip-CYgQfBLt.js} +1 -1
  121. package/dist/cjs/{utils-KWALOgy9.js → utils-BhRmyxT8.js} +35 -4
  122. package/dist/collection/collection-manifest.json +1 -0
  123. package/dist/collection/components/pds-button/pds-button.js +53 -2
  124. package/dist/collection/components/pds-checkbox/pds-checkbox.css +7 -0
  125. package/dist/collection/components/pds-checkbox/pds-checkbox.js +19 -3
  126. package/dist/collection/components/pds-chip/pds-chip.js +1 -1
  127. package/dist/collection/components/pds-combobox/grouped-options-panel.js +262 -0
  128. package/dist/collection/components/pds-combobox/pds-combobox.css +242 -13
  129. package/dist/collection/components/pds-combobox/pds-combobox.js +1128 -114
  130. package/dist/collection/components/pds-combobox/stories/pds-combobox.stories.js +240 -0
  131. package/dist/collection/components/pds-container/pds-container.js +1 -1
  132. package/dist/collection/components/pds-copytext/pds-copytext.js +1 -1
  133. package/dist/collection/components/pds-datepicker/calendar-portal.js +136 -0
  134. package/dist/collection/components/pds-datepicker/date-utils.js +132 -0
  135. package/dist/collection/components/pds-datepicker/datepicker-interface.js +1 -0
  136. package/dist/collection/components/pds-datepicker/pds-datepicker.css +545 -0
  137. package/dist/collection/components/pds-datepicker/pds-datepicker.js +2406 -0
  138. package/dist/collection/components/pds-datepicker/presets.js +96 -0
  139. package/dist/collection/components/pds-datepicker/stories/pds-datepicker.stories.js +195 -0
  140. package/dist/collection/components/pds-datepicker/value.js +238 -0
  141. package/dist/collection/components/pds-divider/pds-divider.js +1 -1
  142. package/dist/collection/components/pds-drawer/pds-drawer-content/pds-drawer-content.js +1 -1
  143. package/dist/collection/components/pds-drawer/pds-drawer-footer/pds-drawer-footer.js +1 -1
  144. package/dist/collection/components/pds-drawer/pds-drawer-header/pds-drawer-header.js +1 -1
  145. package/dist/collection/components/pds-drawer/pds-drawer.css +4 -0
  146. package/dist/collection/components/pds-drawer/pds-drawer.js +9 -2
  147. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu-item/pds-dropdown-menu-item.js +1 -1
  148. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu-separator/pds-dropdown-menu-separator.js +1 -1
  149. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js +9 -2
  150. package/dist/collection/components/pds-filters/pds-filter/pds-filter.js +1 -1
  151. package/dist/collection/components/pds-filters/pds-filters.js +1 -1
  152. package/dist/collection/components/pds-image/pds-image.js +2 -2
  153. package/dist/collection/components/pds-input/pds-input.js +6 -3
  154. package/dist/collection/components/pds-link/pds-link.js +2 -2
  155. package/dist/collection/components/pds-loader/pds-loader.js +1 -1
  156. package/dist/collection/components/pds-modal/pds-modal-content/pds-modal-content.js +2 -2
  157. package/dist/collection/components/pds-modal/pds-modal-footer/pds-modal-footer.js +1 -1
  158. package/dist/collection/components/pds-modal/pds-modal-header/pds-modal-header.js +1 -1
  159. package/dist/collection/components/pds-modal/pds-modal.css +16 -0
  160. package/dist/collection/components/pds-modal/pds-modal.js +10 -4
  161. package/dist/collection/components/pds-modal/test/mock-pds-modal.js +1 -1
  162. package/dist/collection/components/pds-multiselect/pds-multiselect.css +19 -1
  163. package/dist/collection/components/pds-multiselect/pds-multiselect.js +390 -47
  164. package/dist/collection/components/pds-multiselect/stories/pds-multiselect.stories.js +136 -1
  165. package/dist/collection/components/pds-popover/pds-popover.js +29 -11
  166. package/dist/collection/components/pds-progress/pds-progress.js +1 -1
  167. package/dist/collection/components/pds-property/pds-property.js +1 -1
  168. package/dist/collection/components/pds-radio/pds-radio.js +3 -3
  169. package/dist/collection/components/pds-radio-group/pds-radio-group.js +3 -3
  170. package/dist/collection/components/pds-row/pds-row.js +1 -1
  171. package/dist/collection/components/pds-select/pds-select.js +1 -1
  172. package/dist/collection/components/pds-sortable/pds-sortable-item/pds-sortable-item.js +1 -1
  173. package/dist/collection/components/pds-sortable/pds-sortable.js +1 -1
  174. package/dist/collection/components/pds-switch/pds-switch.css +3 -0
  175. package/dist/collection/components/pds-switch/pds-switch.js +20 -4
  176. package/dist/collection/components/pds-table/pds-table-body/pds-table-body.js +1 -1
  177. package/dist/collection/components/pds-table/pds-table-cell/pds-table-cell.js +2 -2
  178. package/dist/collection/components/pds-table/pds-table-head/pds-table-head.js +1 -1
  179. package/dist/collection/components/pds-table/pds-table-head-cell/pds-table-head-cell.js +2 -2
  180. package/dist/collection/components/pds-table/pds-table-row/pds-table-row.js +1 -1
  181. package/dist/collection/components/pds-tabs/pds-tabpanel/pds-tabpanel.js +1 -1
  182. package/dist/collection/components/pds-tabs/pds-tabs.js +1 -1
  183. package/dist/collection/components/pds-text/pds-text.js +1 -1
  184. package/dist/collection/components/pds-textarea/pds-textarea.js +11 -6
  185. package/dist/collection/components/pds-toast/pds-toast.js +3 -3
  186. package/dist/collection/components/pds-tooltip/pds-tooltip.js +2 -2
  187. package/dist/collection/utils/closest.js +8 -0
  188. package/dist/collection/utils/utils.js +33 -4
  189. package/dist/docs.json +1933 -59
  190. package/dist/esm/closest-DHPzKMVS.js +17 -0
  191. package/dist/esm/{floating-ui.dom-DDtwbwIl.js → floating-ui.dom-BPqJgIq6.js} +79 -1
  192. package/dist/esm/{i18n-format-BKsJZTyn.js → i18n-format-BJgZHCWe.js} +1 -1
  193. package/dist/esm/{index-DcT8--Dn.js → index-CB8Yh0Nt.js} +4 -1
  194. package/dist/esm/{index-BU1hN5Vy.js → index-DxI-61GK.js} +5 -1
  195. package/dist/esm/loader.js +3 -3
  196. package/dist/esm/mock-pds-modal.entry.js +3 -3
  197. package/dist/esm/pds-accordion.entry.js +2 -2
  198. package/dist/esm/pds-alert.entry.js +1 -1
  199. package/dist/esm/pds-avatar.entry.js +2 -2
  200. package/dist/esm/pds-box.entry.js +2 -2
  201. package/dist/esm/pds-button.entry.js +53 -4
  202. package/dist/esm/pds-checkbox.entry.js +14 -6
  203. package/dist/esm/pds-chip.entry.js +6 -6
  204. package/dist/esm/pds-combobox.entry.js +1225 -117
  205. package/dist/esm/pds-container.entry.js +2 -2
  206. package/dist/esm/pds-copytext.entry.js +5 -5
  207. package/dist/esm/pds-datepicker.entry.js +1960 -0
  208. package/dist/esm/pds-divider.entry.js +2 -2
  209. package/dist/esm/pds-drawer-content.entry.js +2 -2
  210. package/dist/esm/pds-drawer-footer.entry.js +2 -2
  211. package/dist/esm/pds-drawer-header.entry.js +2 -2
  212. package/dist/esm/pds-drawer.entry.js +11 -4
  213. package/dist/esm/pds-dropdown-menu-item.entry.js +2 -2
  214. package/dist/esm/pds-dropdown-menu-separator.entry.js +2 -2
  215. package/dist/esm/pds-dropdown-menu.entry.js +11 -4
  216. package/dist/esm/pds-filter.entry.js +3 -3
  217. package/dist/esm/pds-filters.entry.js +2 -2
  218. package/dist/esm/pds-icon.entry.js +1 -1
  219. package/dist/esm/pds-image.entry.js +3 -3
  220. package/dist/esm/pds-input.entry.js +8 -5
  221. package/dist/esm/pds-link.entry.js +5 -5
  222. package/dist/esm/pds-loader.entry.js +2 -2
  223. package/dist/esm/pds-modal-content.entry.js +3 -3
  224. package/dist/esm/pds-modal-footer.entry.js +2 -2
  225. package/dist/esm/pds-modal-header.entry.js +2 -2
  226. package/dist/esm/pds-modal.entry.js +12 -6
  227. package/dist/esm/pds-multiselect.entry.js +264 -51
  228. package/dist/esm/pds-popover.entry.js +30 -12
  229. package/dist/esm/pds-progress.entry.js +3 -3
  230. package/dist/esm/pds-property.entry.js +2 -2
  231. package/dist/esm/pds-radio-group.entry.js +5 -5
  232. package/dist/esm/pds-radio.entry.js +5 -5
  233. package/dist/esm/pds-row.entry.js +2 -2
  234. package/dist/esm/pds-select.entry.js +3 -3
  235. package/dist/esm/pds-sortable-item.entry.js +3 -3
  236. package/dist/esm/pds-sortable.entry.js +2 -2
  237. package/dist/esm/pds-switch.entry.js +14 -6
  238. package/dist/esm/pds-tab.entry.js +1 -1
  239. package/dist/esm/pds-table-body.entry.js +2 -2
  240. package/dist/esm/pds-table-cell.entry.js +5 -5
  241. package/dist/esm/pds-table-head-cell.entry.js +4 -4
  242. package/dist/esm/pds-table-head.entry.js +3 -3
  243. package/dist/esm/pds-table-row.entry.js +3 -3
  244. package/dist/esm/pds-table.entry.js +1 -1
  245. package/dist/esm/pds-tabpanel.entry.js +2 -2
  246. package/dist/esm/pds-tabs.entry.js +2 -2
  247. package/dist/esm/pds-text.entry.js +5 -5
  248. package/dist/esm/pds-textarea.entry.js +14 -9
  249. package/dist/esm/pds-toast.entry.js +4 -4
  250. package/dist/esm/pds-tooltip.entry.js +4 -4
  251. package/dist/esm/pine-core.js +3 -3
  252. package/dist/esm/{truncation-tooltip-CdtEBn_5.js → truncation-tooltip-_902ENWC.js} +1 -1
  253. package/dist/esm/{utils-u_0lxWnH.js → utils-OYK5-nwe.js} +34 -5
  254. package/dist/esm-es5/closest-DHPzKMVS.js +1 -0
  255. package/dist/esm-es5/floating-ui.dom-BPqJgIq6.js +1 -0
  256. package/dist/esm-es5/{i18n-format-BKsJZTyn.js → i18n-format-BJgZHCWe.js} +1 -1
  257. package/dist/esm-es5/index-CB8Yh0Nt.js +2 -0
  258. package/dist/esm-es5/index-DxI-61GK.js +1 -0
  259. package/dist/esm-es5/loader.js +1 -1
  260. package/dist/esm-es5/mock-pds-modal.entry.js +1 -1
  261. package/dist/esm-es5/pds-accordion.entry.js +1 -1
  262. package/dist/esm-es5/pds-alert.entry.js +1 -1
  263. package/dist/esm-es5/pds-avatar.entry.js +1 -1
  264. package/dist/esm-es5/pds-box.entry.js +1 -1
  265. package/dist/esm-es5/pds-button.entry.js +1 -1
  266. package/dist/esm-es5/pds-checkbox.entry.js +1 -1
  267. package/dist/esm-es5/pds-chip.entry.js +1 -1
  268. package/dist/esm-es5/pds-combobox.entry.js +2 -2
  269. package/dist/esm-es5/pds-container.entry.js +1 -1
  270. package/dist/esm-es5/pds-copytext.entry.js +1 -1
  271. package/dist/esm-es5/pds-datepicker.entry.js +1 -0
  272. package/dist/esm-es5/pds-divider.entry.js +1 -1
  273. package/dist/esm-es5/pds-drawer-content.entry.js +1 -1
  274. package/dist/esm-es5/pds-drawer-footer.entry.js +1 -1
  275. package/dist/esm-es5/pds-drawer-header.entry.js +1 -1
  276. package/dist/esm-es5/pds-drawer.entry.js +1 -1
  277. package/dist/esm-es5/pds-dropdown-menu-item.entry.js +1 -1
  278. package/dist/esm-es5/pds-dropdown-menu-separator.entry.js +1 -1
  279. package/dist/esm-es5/pds-dropdown-menu.entry.js +1 -1
  280. package/dist/esm-es5/pds-filter.entry.js +1 -1
  281. package/dist/esm-es5/pds-filters.entry.js +1 -1
  282. package/dist/esm-es5/pds-icon.entry.js +1 -1
  283. package/dist/esm-es5/pds-image.entry.js +1 -1
  284. package/dist/esm-es5/pds-input.entry.js +1 -1
  285. package/dist/esm-es5/pds-link.entry.js +1 -1
  286. package/dist/esm-es5/pds-loader.entry.js +1 -1
  287. package/dist/esm-es5/pds-modal-content.entry.js +1 -1
  288. package/dist/esm-es5/pds-modal-footer.entry.js +1 -1
  289. package/dist/esm-es5/pds-modal-header.entry.js +1 -1
  290. package/dist/esm-es5/pds-modal.entry.js +1 -1
  291. package/dist/esm-es5/pds-multiselect.entry.js +1 -1
  292. package/dist/esm-es5/pds-popover.entry.js +1 -1
  293. package/dist/esm-es5/pds-progress.entry.js +1 -1
  294. package/dist/esm-es5/pds-property.entry.js +1 -1
  295. package/dist/esm-es5/pds-radio-group.entry.js +1 -1
  296. package/dist/esm-es5/pds-radio.entry.js +1 -1
  297. package/dist/esm-es5/pds-row.entry.js +1 -1
  298. package/dist/esm-es5/pds-select.entry.js +1 -1
  299. package/dist/esm-es5/pds-sortable-item.entry.js +1 -1
  300. package/dist/esm-es5/pds-sortable.entry.js +2 -2
  301. package/dist/esm-es5/pds-switch.entry.js +1 -1
  302. package/dist/esm-es5/pds-tab.entry.js +1 -1
  303. package/dist/esm-es5/pds-table-body.entry.js +1 -1
  304. package/dist/esm-es5/pds-table-cell.entry.js +1 -1
  305. package/dist/esm-es5/pds-table-head-cell.entry.js +1 -1
  306. package/dist/esm-es5/pds-table-head.entry.js +1 -1
  307. package/dist/esm-es5/pds-table-row.entry.js +1 -1
  308. package/dist/esm-es5/pds-table.entry.js +1 -1
  309. package/dist/esm-es5/pds-tabpanel.entry.js +1 -1
  310. package/dist/esm-es5/pds-tabs.entry.js +1 -1
  311. package/dist/esm-es5/pds-text.entry.js +1 -1
  312. package/dist/esm-es5/pds-textarea.entry.js +1 -1
  313. package/dist/esm-es5/pds-toast.entry.js +1 -1
  314. package/dist/esm-es5/pds-tooltip.entry.js +1 -1
  315. package/dist/esm-es5/pine-core.js +1 -1
  316. package/dist/esm-es5/{truncation-tooltip-CdtEBn_5.js → truncation-tooltip-_902ENWC.js} +1 -1
  317. package/dist/esm-es5/utils-OYK5-nwe.js +1 -0
  318. package/dist/pine-core/p-039369b4.system.entry.js +1 -0
  319. package/dist/pine-core/p-0414092a.system.entry.js +1 -0
  320. package/dist/pine-core/p-04807201.entry.js +1 -0
  321. package/dist/pine-core/{p-cfcb89d1.system.entry.js → p-07f0d168.system.entry.js} +1 -1
  322. package/dist/pine-core/p-08f5d19c.entry.js +1 -0
  323. package/dist/pine-core/{p-d70aa0c7.system.entry.js → p-0aaf8faa.system.entry.js} +1 -1
  324. package/dist/pine-core/p-0bad5955.entry.js +1 -0
  325. package/dist/pine-core/{p-99f300ef.system.entry.js → p-0c3bf377.system.entry.js} +1 -1
  326. package/dist/pine-core/p-0ce79cd0.entry.js +1 -0
  327. package/dist/pine-core/{p-f682f08a.system.entry.js → p-1057b8c3.system.entry.js} +1 -1
  328. package/dist/pine-core/{p-089606b8.system.entry.js → p-108c910a.system.entry.js} +1 -1
  329. package/dist/pine-core/{p-ea986474.system.entry.js → p-166f61a6.system.entry.js} +1 -1
  330. package/dist/pine-core/{p-95defb53.entry.js → p-16c8f5e3.entry.js} +1 -1
  331. package/dist/pine-core/p-16e258d1.entry.js +1 -0
  332. package/dist/pine-core/p-19dbd9f6.entry.js +1 -0
  333. package/dist/pine-core/{p-a8f1a48d.entry.js → p-1be33c95.entry.js} +1 -1
  334. package/dist/pine-core/{p-70fb83d4.entry.js → p-1e3a31da.entry.js} +1 -1
  335. package/dist/pine-core/p-1ea45d33.system.entry.js +1 -0
  336. package/dist/pine-core/{p-12941e0d.entry.js → p-1f228db9.entry.js} +1 -1
  337. package/dist/pine-core/p-257c6ef9.entry.js +1 -0
  338. package/dist/pine-core/p-26415245.system.entry.js +1 -0
  339. package/dist/pine-core/p-26e1e5bb.entry.js +1 -0
  340. package/dist/pine-core/p-27c06bf8.entry.js +2 -0
  341. package/dist/pine-core/p-330a76f6.system.entry.js +1 -0
  342. package/dist/pine-core/{p-4ebdb90b.system.entry.js → p-33c63be6.system.entry.js} +1 -1
  343. package/dist/pine-core/{p-c5b6b545.entry.js → p-344609f9.entry.js} +2 -2
  344. package/dist/pine-core/{p-2dbc90ba.entry.js → p-3a1711c1.entry.js} +1 -1
  345. package/dist/pine-core/p-3a9c58bd.system.entry.js +1 -0
  346. package/dist/pine-core/{p-32fc82c2.entry.js → p-3ebd543f.entry.js} +1 -1
  347. package/dist/pine-core/p-3fbcb0c8.system.entry.js +1 -0
  348. package/dist/pine-core/{p-e08e4ca7.entry.js → p-427b4aeb.entry.js} +1 -1
  349. package/dist/pine-core/{p-f5cf98be.system.entry.js → p-42bd87ea.system.entry.js} +1 -1
  350. package/dist/pine-core/{p-8d1e7b3c.system.entry.js → p-43c691bf.system.entry.js} +1 -1
  351. package/dist/pine-core/p-4566d659.system.entry.js +1 -0
  352. package/dist/pine-core/{p-b9a857fc.system.entry.js → p-4b8cf04a.system.entry.js} +1 -1
  353. package/dist/pine-core/p-4d6f471c.entry.js +1 -0
  354. package/dist/pine-core/{p-ec04d4c3.entry.js → p-4e7580c4.entry.js} +1 -1
  355. package/dist/pine-core/{p-fbb72e66.system.entry.js → p-4f4a2d2a.system.entry.js} +1 -1
  356. package/dist/pine-core/{p-b8a5597d.entry.js → p-5211aba7.entry.js} +1 -1
  357. package/dist/pine-core/{p-7e4729e0.entry.js → p-524b7d3f.entry.js} +1 -1
  358. package/dist/pine-core/{p-c08b1697.entry.js → p-5613c64c.entry.js} +1 -1
  359. package/dist/pine-core/{p-5a8345e2.entry.js → p-5bb24cb4.entry.js} +1 -1
  360. package/dist/pine-core/{p-73c3a73f.entry.js → p-5bb80b3c.entry.js} +1 -1
  361. package/dist/pine-core/{p-e039ebb6.system.entry.js → p-5c6e0a26.system.entry.js} +1 -1
  362. package/dist/pine-core/{p-b53d9620.system.entry.js → p-5db57551.system.entry.js} +1 -1
  363. package/dist/pine-core/{p-6b260a97.entry.js → p-5eb00ba5.entry.js} +1 -1
  364. package/dist/pine-core/p-61756414.system.entry.js +1 -0
  365. package/dist/pine-core/{p-08196d6c.entry.js → p-682e9e8f.entry.js} +1 -1
  366. package/dist/pine-core/p-6965db1d.entry.js +1 -0
  367. package/dist/pine-core/{p-317337e4.entry.js → p-6b180ee2.entry.js} +1 -1
  368. package/dist/pine-core/{p-d33d65f6.entry.js → p-6c53962f.entry.js} +1 -1
  369. package/dist/pine-core/p-6da6520b.system.entry.js +3 -0
  370. package/dist/pine-core/{p-bd9b2931.system.entry.js → p-6e3bf862.system.entry.js} +1 -1
  371. package/dist/pine-core/{p-9d77f2f8.system.entry.js → p-71c9f866.system.entry.js} +1 -1
  372. package/dist/pine-core/{p-a616385b.system.entry.js → p-7265b94c.system.entry.js} +1 -1
  373. package/dist/pine-core/{p-55532d56.system.entry.js → p-74229b5e.system.entry.js} +1 -1
  374. package/dist/pine-core/p-7512c2d4.system.entry.js +1 -0
  375. package/dist/pine-core/p-76db406d.system.entry.js +1 -0
  376. package/dist/pine-core/{p-3b555f06.system.entry.js → p-79aa5f43.system.entry.js} +1 -1
  377. package/dist/pine-core/{p-77082557.system.entry.js → p-7bbcda0f.system.entry.js} +1 -1
  378. package/dist/pine-core/p-7c8946e6.entry.js +1 -0
  379. package/dist/pine-core/p-7c98c90a.system.entry.js +1 -0
  380. package/dist/pine-core/{p-93c52e2b.system.entry.js → p-8252cd84.system.entry.js} +1 -1
  381. package/dist/pine-core/p-8469cf3e.entry.js +1 -0
  382. package/dist/pine-core/p-84ba0e6a.system.entry.js +1 -0
  383. package/dist/pine-core/{p-45d55983.entry.js → p-86fc0bfa.entry.js} +1 -1
  384. package/dist/pine-core/{p-67fc26e5.system.entry.js → p-90ea812c.system.entry.js} +1 -1
  385. package/dist/pine-core/p-948826db.entry.js +1 -0
  386. package/dist/pine-core/{p-35edd8b0.entry.js → p-9b66642d.entry.js} +1 -1
  387. package/dist/pine-core/p-BJgZHCWe.js +1 -0
  388. package/dist/pine-core/p-BPqJgIq6.js +1 -0
  389. package/dist/pine-core/p-BSRFZB4I.system.js +1 -0
  390. package/dist/pine-core/p-BZsj6eAn.system.js +1 -0
  391. package/dist/pine-core/p-CB8Yh0Nt.js +2 -0
  392. package/dist/pine-core/{p-B2qvvB3q.system.js → p-CBu9UrXr.system.js} +1 -1
  393. package/dist/pine-core/p-COtCa1Md.system.js +1 -0
  394. package/dist/pine-core/p-CTQZ2fkv.system.js +1 -0
  395. package/dist/pine-core/{p-B2nn1gSd.js → p-CnM3cCof.js} +1 -1
  396. package/dist/pine-core/p-CnO10OxH.system.js +1 -0
  397. package/dist/pine-core/p-D-akEPIU.system.js +2 -0
  398. package/dist/pine-core/p-DHPzKMVS.js +1 -0
  399. package/dist/pine-core/p-Dx8tEj0U.system.js +1 -0
  400. package/dist/pine-core/p-DxI-61GK.js +1 -0
  401. package/dist/pine-core/p-OYK5-nwe.js +1 -0
  402. package/dist/pine-core/p-a10af84b.system.entry.js +1 -0
  403. package/dist/pine-core/p-a21b530a.system.entry.js +1 -0
  404. package/dist/pine-core/{p-b0becff3.system.entry.js → p-a85535a4.system.entry.js} +1 -1
  405. package/dist/pine-core/p-abc0fe2f.system.entry.js +1 -0
  406. package/dist/pine-core/p-ac6a5bf0.entry.js +1 -0
  407. package/dist/pine-core/{p-5f5339ab.entry.js → p-b0526f98.entry.js} +1 -1
  408. package/dist/pine-core/p-b130b716.entry.js +1 -0
  409. package/dist/pine-core/{p-4cbb691f.entry.js → p-b195d345.entry.js} +1 -1
  410. package/dist/pine-core/{p-5c5bd609.entry.js → p-b4923acf.entry.js} +1 -1
  411. package/dist/pine-core/{p-15a0fa0a.system.entry.js → p-b4e440e3.system.entry.js} +1 -1
  412. package/dist/pine-core/p-b8693a87.entry.js +1 -0
  413. package/dist/pine-core/{p-bf025e38.entry.js → p-b8ada1eb.entry.js} +1 -1
  414. package/dist/pine-core/{p-a6a269da.system.entry.js → p-bb85bbb5.system.entry.js} +1 -1
  415. package/dist/pine-core/{p-fa8d3155.system.entry.js → p-bbc539bc.system.entry.js} +2 -2
  416. package/dist/pine-core/{p-f26dcbc2.system.entry.js → p-bf833976.system.entry.js} +1 -1
  417. package/dist/pine-core/{p-e055c543.entry.js → p-c23097af.entry.js} +1 -1
  418. package/dist/pine-core/p-c2dd84bd.system.entry.js +1 -0
  419. package/dist/pine-core/{p-441682f4.system.entry.js → p-c4520b04.system.entry.js} +1 -1
  420. package/dist/pine-core/{p-f1365550.entry.js → p-c4f68dfc.entry.js} +1 -1
  421. package/dist/pine-core/{p-fa2a786d.system.entry.js → p-c6fa6744.system.entry.js} +1 -1
  422. package/dist/pine-core/p-c7dba815.entry.js +1 -0
  423. package/dist/pine-core/p-cb6f55ff.entry.js +1 -0
  424. package/dist/pine-core/p-cfb8fa7c.system.entry.js +1 -0
  425. package/dist/pine-core/{p-2bb101c2.entry.js → p-d0d7d1d4.entry.js} +1 -1
  426. package/dist/pine-core/{p-4f5aacd9.entry.js → p-d1112c8a.entry.js} +1 -1
  427. package/dist/pine-core/{p-5f3d0c86.system.entry.js → p-d4e91ad9.system.entry.js} +1 -1
  428. package/dist/pine-core/{p-44222439.entry.js → p-da018dcb.entry.js} +1 -1
  429. package/dist/pine-core/{p-57784f2f.system.entry.js → p-dc27abe6.system.entry.js} +1 -1
  430. package/dist/pine-core/{p-f9f7101e.entry.js → p-dc343b6d.entry.js} +1 -1
  431. package/dist/pine-core/{p-fb774f89.system.entry.js → p-dde753e7.system.entry.js} +1 -1
  432. package/dist/pine-core/{p-558ac401.entry.js → p-dea3a582.entry.js} +1 -1
  433. package/dist/pine-core/p-df29fd41.entry.js +1 -0
  434. package/dist/pine-core/{p-c6426e16.system.entry.js → p-e4e2eae2.system.entry.js} +1 -1
  435. package/dist/pine-core/{p-1abae35f.entry.js → p-e8668178.entry.js} +1 -1
  436. package/dist/pine-core/{p-20753e42.system.entry.js → p-eb28d21d.system.entry.js} +1 -1
  437. package/dist/pine-core/p-eb71a82d.system.entry.js +1 -0
  438. package/dist/pine-core/{p-13bb89ff.entry.js → p-ed63873c.entry.js} +1 -1
  439. package/dist/pine-core/{p-5d2f95bd.entry.js → p-f4f6dc36.entry.js} +1 -1
  440. package/dist/pine-core/{p-6b3d8c2b.system.entry.js → p-f67a0ca8.system.entry.js} +1 -1
  441. package/dist/pine-core/{p-003df3b3.entry.js → p-fc455968.entry.js} +1 -1
  442. package/dist/pine-core/{p-02452806.system.entry.js → p-fe3e2ebd.system.entry.js} +1 -1
  443. package/dist/pine-core/pine-core.css +1 -1
  444. package/dist/pine-core/pine-core.esm.js +1 -1
  445. package/dist/pine-core/pine-core.js +1 -1
  446. package/dist/types/components/pds-button/pds-button.d.ts +10 -0
  447. package/dist/types/components/pds-checkbox/pds-checkbox.d.ts +5 -0
  448. package/dist/types/components/pds-combobox/combobox-interface.d.ts +17 -0
  449. package/dist/types/components/pds-combobox/grouped-options-panel.d.ts +105 -0
  450. package/dist/types/components/pds-combobox/pds-combobox.d.ts +235 -3
  451. package/dist/types/components/pds-datepicker/calendar-portal.d.ts +43 -0
  452. package/dist/types/components/pds-datepicker/date-utils.d.ts +48 -0
  453. package/dist/types/components/pds-datepicker/datepicker-interface.d.ts +30 -0
  454. package/dist/types/components/pds-datepicker/pds-datepicker.d.ts +489 -0
  455. package/dist/types/components/pds-datepicker/presets.d.ts +23 -0
  456. package/dist/types/components/pds-datepicker/value.d.ts +47 -0
  457. package/dist/types/components/pds-dropdown-menu/pds-dropdown-menu.d.ts +1 -0
  458. package/dist/types/components/pds-multiselect/multiselect-interface.d.ts +19 -0
  459. package/dist/types/components/pds-multiselect/pds-multiselect.d.ts +56 -1
  460. package/dist/types/components/pds-popover/pds-popover.d.ts +1 -0
  461. package/dist/types/components/pds-switch/pds-switch.d.ts +5 -0
  462. package/dist/types/components.d.ts +677 -4
  463. package/dist/types/utils/closest.d.ts +2 -0
  464. package/dist/types/utils/utils.d.ts +9 -1
  465. package/dist/vscode.html-data.json +467 -3
  466. package/hydrate/index.js +3973 -362
  467. package/hydrate/index.mjs +3973 -362
  468. package/package.json +2 -2
  469. package/dist/cjs/closest-BZXvuB_Y.js +0 -11
  470. package/dist/esm/closest-DnUJodVd.js +0 -9
  471. package/dist/esm-es5/closest-DnUJodVd.js +0 -1
  472. package/dist/esm-es5/floating-ui.dom-DDtwbwIl.js +0 -1
  473. package/dist/esm-es5/index-BU1hN5Vy.js +0 -1
  474. package/dist/esm-es5/index-DcT8--Dn.js +0 -2
  475. package/dist/esm-es5/utils-u_0lxWnH.js +0 -1
  476. package/dist/pine-core/p-026ee6de.entry.js +0 -1
  477. package/dist/pine-core/p-03f3fc92.system.entry.js +0 -1
  478. package/dist/pine-core/p-06375326.system.entry.js +0 -1
  479. package/dist/pine-core/p-1df5e088.entry.js +0 -1
  480. package/dist/pine-core/p-24214ab9.system.entry.js +0 -1
  481. package/dist/pine-core/p-250011ba.entry.js +0 -1
  482. package/dist/pine-core/p-2b420257.entry.js +0 -1
  483. package/dist/pine-core/p-375eb7f4.entry.js +0 -1
  484. package/dist/pine-core/p-3b796898.entry.js +0 -1
  485. package/dist/pine-core/p-3c5489ce.entry.js +0 -1
  486. package/dist/pine-core/p-3e868906.system.entry.js +0 -1
  487. package/dist/pine-core/p-464f23e6.entry.js +0 -1
  488. package/dist/pine-core/p-49c6112a.entry.js +0 -1
  489. package/dist/pine-core/p-4bd57896.system.entry.js +0 -1
  490. package/dist/pine-core/p-6a6a767b.system.entry.js +0 -1
  491. package/dist/pine-core/p-6dabeebc.system.entry.js +0 -3
  492. package/dist/pine-core/p-70891202.entry.js +0 -1
  493. package/dist/pine-core/p-73fa955a.system.entry.js +0 -1
  494. package/dist/pine-core/p-755e0b3c.system.entry.js +0 -1
  495. package/dist/pine-core/p-8b051229.entry.js +0 -1
  496. package/dist/pine-core/p-8d8a8550.system.entry.js +0 -1
  497. package/dist/pine-core/p-93486f2e.entry.js +0 -1
  498. package/dist/pine-core/p-93ae562d.entry.js +0 -1
  499. package/dist/pine-core/p-95b8bece.system.entry.js +0 -1
  500. package/dist/pine-core/p-9d902000.system.entry.js +0 -1
  501. package/dist/pine-core/p-9ef355b7.entry.js +0 -1
  502. package/dist/pine-core/p-BI7Ml0VF.system.js +0 -1
  503. package/dist/pine-core/p-BKsJZTyn.js +0 -1
  504. package/dist/pine-core/p-BU1hN5Vy.js +0 -1
  505. package/dist/pine-core/p-BrLs99ML.system.js +0 -1
  506. package/dist/pine-core/p-CJ8t3EBJ.system.js +0 -2
  507. package/dist/pine-core/p-Cr7-rJtJ.system.js +0 -1
  508. package/dist/pine-core/p-DDtwbwIl.js +0 -1
  509. package/dist/pine-core/p-D_I-k33A.system.js +0 -1
  510. package/dist/pine-core/p-DcT8--Dn.js +0 -2
  511. package/dist/pine-core/p-DnUJodVd.js +0 -1
  512. package/dist/pine-core/p-a009ab10.system.entry.js +0 -1
  513. package/dist/pine-core/p-a8cd2ab5.entry.js +0 -1
  514. package/dist/pine-core/p-b45b8f8b.system.entry.js +0 -1
  515. package/dist/pine-core/p-b85bb61d.system.entry.js +0 -1
  516. package/dist/pine-core/p-bdded57a.system.entry.js +0 -1
  517. package/dist/pine-core/p-c1a65082.entry.js +0 -1
  518. package/dist/pine-core/p-c1d1befb.system.entry.js +0 -1
  519. package/dist/pine-core/p-ctdGub9B.system.js +0 -1
  520. package/dist/pine-core/p-d9c1ee36.system.entry.js +0 -1
  521. package/dist/pine-core/p-df285ece.system.entry.js +0 -1
  522. package/dist/pine-core/p-ee114aef.entry.js +0 -1
  523. package/dist/pine-core/p-ee997fbf.entry.js +0 -2
  524. package/dist/pine-core/p-f89197c9.entry.js +0 -1
  525. package/dist/pine-core/p-kYMYDfJY.system.js +0 -1
  526. package/dist/pine-core/p-u_0lxWnH.js +0 -1
@@ -1,7 +1,7 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-DcT8--Dn.js';
1
+ import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-CB8Yh0Nt.js';
2
2
  import { i as isSpecTest, m as messageId, a as assignDescription } from './form-BuRbS7Hp.js';
3
- import { c as computePosition, a as autoUpdate, o as offset, f as flip, s as shift } from './floating-ui.dom-DDtwbwIl.js';
4
- import { d as debounceEvent } from './utils-u_0lxWnH.js';
3
+ import { a as autoUpdate, c as computePosition, o as offset, f as flip, s as shift, b as size, h as hide } from './floating-ui.dom-BPqJgIq6.js';
4
+ import { c as cancelDebouncedEvent, d as debounceEvent, f as flushDebouncedEvent } from './utils-OYK5-nwe.js';
5
5
 
6
6
  /*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE */
7
7
 
@@ -1389,7 +1389,269 @@ function createDOMPurify() {
1389
1389
  }
1390
1390
  var purify = createDOMPurify();
1391
1391
 
1392
- const pdsComboboxCss = () => `:host{display:block}:host([aria-disabled=true]) .pds-combobox__input-icon{color:var(--pine-color-text-disabled);pointer-events:none}.pds-combobox{position:relative}.pds-combobox__label{color:var(--pine-color-text-label);display:block;font:var(--pine-typography-body-medium);letter-spacing:var(--pine-letter-spacing);-webkit-margin-after:var(--pine-dimension-2xs);margin-block-end:var(--pine-dimension-2xs)}.pds-combobox__input-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;position:relative;width:100%}.pds-combobox__input{background:var(--pine-color-background-container);border:var(--pine-border);border-radius:var(--pine-dimension-125);-webkit-box-sizing:border-box;box-sizing:border-box;color:var(--pine-color-text-strong);-ms-flex:1;flex:1;font:var(--pine-typography-body-medium);padding:var(--pine-dimension-xs) var(--pine-dimension-450) var(--pine-dimension-xs) var(--pine-dimension-150);-webkit-transition:border-color var(--pine-motion-duration-base) ease;transition:border-color var(--pine-motion-duration-base) ease;width:100%}.pds-combobox__input:hover:not(:disabled){border-color:var(--pine-color-border-hover)}.pds-combobox__input:disabled{background:var(--pine-color-background-container-disabled);border-color:var(--pine-color-border-disabled);color:var(--pine-color-text-disabled);cursor:not-allowed}.pds-combobox__input:disabled::-webkit-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::-moz-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled:-ms-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::-ms-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:focus-visible{border-color:var(--pine-color-border-active);outline:var(--pine-outline-focus);outline-offset:var(--pine-border-width)}.pds-combobox__input::-webkit-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::-moz-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input:-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input.pds-combobox__input--invalid{background:var(--pine-color-red-050);border-color:var(--pine-color-border-danger)}:host-context([data-theme=dark]) .pds-combobox__input.pds-combobox__input--invalid{background:var(--pine-color-red-950)}.pds-combobox__input.pds-combobox__input--invalid:hover:not(:disabled){border-color:var(--pine-color-border-danger)}.pds-combobox__input.pds-combobox__input--invalid:focus-visible{outline-color:var(--pine-color-focus-ring-danger)}.pds-combobox__input-icon{color:var(--pine-color-text-secondary);inset-inline-end:var(--pine-dimension-150);pointer-events:none;position:absolute;z-index:calc(var(--pine-z-index-raised) - 1)}.pds-combobox__helper{color:var(--pine-color-text-message);font:var(--pine-typography-body-sm-medium);-webkit-margin-before:var(--pine-dimension-2xs);margin-block-start:var(--pine-dimension-2xs)}.pds-combobox__error{-ms-flex-align:start;align-items:flex-start;color:var(--pine-color-text-message-danger);display:-ms-flexbox;display:flex;font:var(--pine-typography-body-sm-medium);gap:var(--pine-dimension-2xs);-webkit-margin-before:var(--pine-dimension-2xs);margin-block-start:var(--pine-dimension-2xs)}.pds-combobox__error pds-icon{-ms-flex-negative:0;flex-shrink:0;-webkit-margin-before:var(--pine-dimension-025);margin-block-start:var(--pine-dimension-025)}.pds-combobox__listbox{background:var(--pine-color-background-overlay);border:0;border-radius:var(--pine-dimension-125);-webkit-box-shadow:var(--pine-box-shadow);box-shadow:var(--pine-box-shadow);list-style:none;margin:0;min-width:220px;overflow-y:auto;padding:var(--pine-dimension-xs);position:absolute;z-index:var(--pine-z-index-raised)}.pds-combobox__option{-ms-flex-align:center;align-items:center;background:transparent;border-radius:var(--pine-dimension-125);color:var(--pine-color-text-secondary);cursor:pointer;display:-ms-flexbox;display:flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;padding:var(--pine-dimension-xs) var(--pine-dimension-sm);position:relative;-webkit-transition:background 0.15s;transition:background 0.15s}.pds-combobox__option[aria-selected=true]{background:var(--pine-color-background-muted)}.pds-combobox__option:focus-visible{outline:0}.pds-combobox__option.pds-combobox__option--layout .pds-combobox__option-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__option.pds-combobox__option--chip .pds-combobox__option-chip{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__option:last-child{-webkit-margin-after:0;margin-block-end:0}.pds-combobox__option--highlighted,.pds-combobox__option[selected],.pds-combobox__option--selected{background:var(--pine-color-background-muted)}.pds-combobox__option-check{color:currentColor;font-size:var(--pine-dimension-150);-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__group-label{color:var(--pine-color-text-tertiary);cursor:default;font:var(--pine-typography-heading-caption);-webkit-margin-after:var(--pine-dimension-2xs);margin-block-end:var(--pine-dimension-2xs);-webkit-margin-before:var(--pine-dimension-150);margin-block-start:var(--pine-dimension-150);padding:var(--pine-dimension-2xs) var(--pine-dimension-sm);text-transform:uppercase}.pds-combobox__group-label:first-child{-webkit-margin-before:0;margin-block-start:0}.pds-combobox__loading{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding:var(--pine-dimension-150)}.pds-combobox__empty{color:var(--pine-color-text-tertiary);padding:var(--pine-dimension-150) var(--pine-dimension-sm);text-align:center}.pds-combobox__load-more{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding:var(--pine-dimension-150)}.pds-combobox__button-trigger{-ms-flex-align:center;align-items:center;background:var(--color-background-default, var(--pine-color-secondary));border:var(--pine-border);border-radius:var(--pine-border-radius-full);color:var(--color-text-default, var(--pine-color-text-inverse-emphasis));cursor:pointer;display:-ms-flexbox;display:flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;min-height:var(--pine-dimension-450);outline:none;padding:0 var(--pine-dimension-sm);-webkit-transition:border-color 0.15s, background 0.15s, -webkit-box-shadow 0.15s;transition:border-color 0.15s, background 0.15s, -webkit-box-shadow 0.15s;transition:border-color 0.15s, box-shadow 0.15s, background 0.15s;transition:border-color 0.15s, box-shadow 0.15s, background 0.15s, -webkit-box-shadow 0.15s;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.pds-combobox__button-trigger .pds-combobox__button-trigger-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1}.pds-combobox__button-trigger .trigger-content{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__button-trigger:focus-visible{border-color:var(--color-border-focus, var(--pine-color-border));-webkit-box-shadow:0 0 0 2px var(--color-outline, var(--pine-color-focus-ring));box-shadow:0 0 0 2px var(--color-outline, var(--pine-color-focus-ring))}.pds-combobox__button-trigger:hover{background:var(--color-background-hover, var(--pine-color-secondary-hover));border-color:var(--color-border-hover, var(--pine-color-border-hover))}.pds-combobox__button-trigger[aria-disabled=true],.pds-combobox__button-trigger:disabled{background:var(--color-background-disabled, var(--pine-color-secondary-disabled));border-color:var(--color-border-disabled, var(--pine-color-border-disabled));color:var(--color-text-disabled, var(--pine-color-text-secondary-disabled));cursor:not-allowed;opacity:0.6}.pds-combobox__button-trigger-label{color:inherit;-ms-flex:1 1 auto;flex:1 1 auto;text-align:start}.pds-combobox__button-trigger--input-shape{border-radius:var(--pine-dimension-125);min-height:var(--pine-dimension-500)}.pds-combobox__button-trigger-chevron{color:currentColor;-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__button-trigger--primary{--color-background-default:var(--pine-color-primary);--color-background-hover:var(--pine-color-primary-hover);--color-background-disabled:var(--pine-color-primary-disabled);--color-border-default:var(--pine-color-primary);--color-border-hover:var(--pine-color-primary-hover);--color-border-disabled:var(--pine-color-primary-disabled);--color-border-focus:var(--pine-color-primary);--color-text-default:var(--pine-color-text-primary);--color-text-disabled:var(--pine-color-text-primary-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--accent{--color-background-default:var(--pine-color-accent);--color-background-hover:var(--pine-color-accent-hover);--color-background-disabled:var(--pine-color-accent-disabled);--color-border-default:var(--pine-color-accent);--color-border-hover:var(--pine-color-accent-hover);--color-border-disabled:var(--pine-color-accent-disabled);--color-border-focus:var(--pine-color-accent);--color-text-default:var(--pine-color-text-primary);--color-text-disabled:var(--pine-color-text-accent-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--secondary{--color-background-default:var(--pine-color-secondary);--color-background-hover:var(--pine-color-secondary-hover);--color-background-disabled:var(--pine-color-secondary-disabled);--color-border-default:var(--pine-color-border);--color-border-hover:var(--pine-color-border-hover);--color-border-disabled:var(--pine-color-border-disabled);--color-border-focus:var(--pine-color-border);--color-text-default:var(--pine-color-text-secondary);--color-text-disabled:var(--pine-color-text-secondary-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--destructive{--color-background-default:var(--pine-color-danger);--color-background-hover:var(--pine-color-danger-hover);--color-background-disabled:var(--pine-color-danger-disabled);--color-border-default:var(--pine-color-danger);--color-border-hover:var(--pine-color-danger-hover);--color-border-disabled:var(--pine-color-danger-disabled);--color-border-focus:var(--pine-color-danger);--color-text-default:var(--pine-color-white);--color-text-disabled:var(--pine-color-text-danger-disabled);--color-outline:var(--pine-color-focus-ring-danger)}.visually-hidden{border:0;clip:rect(0 0 0 0);-webkit-clip-path:polygon(0 0, 0 0, 0 0);clip-path:polygon(0 0, 0 0, 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}[data-layout]{border-radius:var(--pine-dimension-125);padding-block:var(--pine-dimension-xs)}.pds-combobox__chip-trigger{-ms-flex-align:center;align-items:center;border-radius:var(--pine-dimension-sm);cursor:pointer;display:-ms-inline-flexbox;display:inline-flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;outline:none;padding-block:var(--pine-dimension-025);padding-inline:var(--pine-dimension-150);-webkit-transition:all 0.15s ease;transition:all 0.15s ease;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.pds-combobox__chip-trigger .pds-combobox__chip-trigger-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1}.pds-combobox__chip-trigger .trigger-content{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__chip-trigger:focus-visible{outline:var(--pine-outline-focus);outline-offset:var(--pine-border-width)}.pds-combobox__chip-trigger[aria-disabled=true]{cursor:not-allowed;opacity:0.6}.pds-combobox__chip-trigger-label{color:inherit;-ms-flex:1 1 auto;flex:1 1 auto;text-align:start}.pds-combobox__chip-trigger-chevron{color:currentColor;-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__chip-trigger-icon{-webkit-margin-end:var(--pine-dimension-2xs);margin-inline-end:var(--pine-dimension-2xs)}.pds-combobox__chip-trigger--neutral,.pds-combobox__chip-trigger--accent,.pds-combobox__chip-trigger--success,.pds-combobox__chip-trigger--warning,.pds-combobox__chip-trigger--danger,.pds-combobox__chip-trigger--info{background:var(--chip-bg);border:var(--pine-border-width) solid var(--chip-border);color:var(--chip-text)}.pds-combobox__chip-trigger--neutral:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--accent:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--success:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--warning:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--danger:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--info:hover:not([aria-disabled=true]){background:var(--chip-bg-hover)}.pds-combobox__chip-trigger--neutral:focus-visible,.pds-combobox__chip-trigger--accent:focus-visible,.pds-combobox__chip-trigger--success:focus-visible,.pds-combobox__chip-trigger--warning:focus-visible,.pds-combobox__chip-trigger--danger:focus-visible,.pds-combobox__chip-trigger--info:focus-visible{border-color:var(--chip-border)}.pds-combobox__chip-trigger--neutral{--chip-bg:var(--pine-chip-color-neutral);--chip-bg-hover:var(--pine-chip-color-neutral-hover);--chip-border:var(--pine-chip-color-neutral-hover);--chip-text:var(--pine-color-text-neutral)}.pds-combobox__chip-trigger--accent{--chip-bg:var(--pine-chip-color-accent);--chip-bg-hover:var(--pine-chip-color-accent-hover);--chip-border:var(--pine-chip-color-accent-hover);--chip-text:var(--pine-color-text-accent)}.pds-combobox__chip-trigger--success{--chip-bg:var(--pine-chip-color-success);--chip-bg-hover:var(--pine-chip-color-success-hover);--chip-border:var(--pine-chip-color-success-hover);--chip-text:var(--pine-color-text-success)}.pds-combobox__chip-trigger--warning{--chip-bg:var(--pine-chip-color-warning);--chip-bg-hover:var(--pine-chip-color-warning-hover);--chip-border:var(--pine-chip-color-warning-hover);--chip-text:var(--pine-color-text-warning)}.pds-combobox__chip-trigger--danger{--chip-bg:var(--pine-chip-color-danger);--chip-bg-hover:var(--pine-chip-color-danger-hover);--chip-border:var(--pine-chip-color-danger-hover);--chip-text:var(--pine-color-text-danger)}.pds-combobox__chip-trigger--info{--chip-bg:var(--pine-chip-color-info);--chip-bg-hover:var(--pine-chip-color-info-hover);--chip-border:var(--pine-chip-color-info-hover);--chip-text:var(--pine-color-text-info)}.pds-combobox__chip-trigger--brand{background:-webkit-gradient(linear, left top, right top, from(#FF3E14), to(#6B62F2));background:linear-gradient(90deg, #FF3E14 0%, #6B62F2 100%);border:0;color:var(--pine-color-text-neutral);padding:1px;position:relative}.pds-combobox__chip-trigger--brand .pds-combobox__chip-trigger-label{background:rgba(255, 255, 255, 0.9);border-radius:calc(var(--pine-dimension-sm) - 1px);color:var(--pine-color-text-neutral);font-weight:var(--pine-font-weight-medium);padding:var(--pine-dimension-025) var(--pine-dimension-150);position:relative;z-index:1}.pds-combobox__chip-trigger--brand .pds-combobox__chip-trigger-chevron{position:relative;z-index:1}.pds-combobox__chip-trigger--brand:hover:not([aria-disabled=true]) .pds-combobox__chip-trigger-label{background:rgba(255, 255, 255, 0.8)}.pds-combobox__chip-trigger--dropdown:not(.pds-combobox__chip-trigger--brand){padding:var(--pine-dimension-none)}.pds-combobox__chip-trigger--dropdown:not(.pds-combobox__chip-trigger--brand) .pds-combobox__chip-trigger-label{padding:var(--pine-dimension-025) var(--pine-dimension-150)}.pds-combobox__chip-trigger--large .pds-combobox__chip-trigger-label{font-family:var(--pine-font-family-heading);font-size:var(--pine-font-size-heading-6);font-weight:var(--pine-font-weight-medium);letter-spacing:var(--pine-letter-spacing-heading-6)}.pds-combobox__chip-trigger--dot .pds-combobox__chip-trigger-label::before{border:var(--pine-border-width) solid transparent;border-radius:var(--pine-border-radius-full);content:"";display:inline-block;height:var(--pine-dimension-2xs);-webkit-margin-end:var(--pine-dimension-2xs);margin-inline-end:var(--pine-dimension-2xs);width:var(--pine-dimension-2xs)}`;
1392
+ /** The optgroup an option sits in, or null for an ungrouped option. */
1393
+ function parentOptgroupOf(option) {
1394
+ const parent = option === null || option === void 0 ? void 0 : option.parentElement;
1395
+ return parent !== null && parent !== undefined && parent.tagName === 'OPTGROUP' ? parent : null;
1396
+ }
1397
+ /** A Pine icon name: letters, digits and hyphens, such as `hashtag`. Never a URL or file path. */
1398
+ const PINE_ICON_NAME = /^[a-z0-9-]+$/i;
1399
+ /**
1400
+ * An optgroup's `data-icon` when it's a Pine icon name, or null. One definition of a usable group
1401
+ * icon for every mode, checked here rather than trusting `pds-icon` to reject anything else; it is
1402
+ * only ever passed to `pds-icon` as `name`.
1403
+ */
1404
+ function groupIconOf(optgroup) {
1405
+ const icon = optgroup.getAttribute('data-icon');
1406
+ return icon !== null && PINE_ICON_NAME.test(icon) ? icon : null;
1407
+ }
1408
+ /** An option is disabled by its own `disabled` or its optgroup's, as in a native select. */
1409
+ function isOptionDisabled(option) {
1410
+ var _a;
1411
+ if (option === null || option === undefined)
1412
+ return false;
1413
+ return option.hasAttribute('disabled') || ((_a = parentOptgroupOf(option)) === null || _a === void 0 ? void 0 : _a.hasAttribute('disabled')) === true;
1414
+ }
1415
+ /** A group with no option left to choose. It still opens, so its options can be seen. */
1416
+ function isGroupDisabled(group) {
1417
+ return group.options.every(({ option }) => isOptionDisabled(option));
1418
+ }
1419
+ /**
1420
+ * Groups the combobox's filtered items for the panel: each optgroup becomes one entry holding its
1421
+ * options, and ungrouped options stay where they are. Indexes count options in list order, the
1422
+ * same as the inline listbox, so `data-option-index` means the same thing in every mode.
1423
+ */
1424
+ function buildPanelEntries(items) {
1425
+ const entries = [];
1426
+ const groups = new Map();
1427
+ let index = 0;
1428
+ items.forEach(item => {
1429
+ if (item.tagName !== 'OPTION')
1430
+ return;
1431
+ const option = item;
1432
+ const optgroup = parentOptgroupOf(option);
1433
+ if (optgroup !== null) {
1434
+ let group = groups.get(optgroup);
1435
+ if (!group) {
1436
+ group = { optgroup, label: optgroup.label, icon: groupIconOf(optgroup), options: [] };
1437
+ groups.set(optgroup, group);
1438
+ entries.push({ kind: 'group', group });
1439
+ }
1440
+ group.options.push({ option, index: index++ });
1441
+ }
1442
+ else {
1443
+ entries.push({ kind: 'option', option, index: index++ });
1444
+ }
1445
+ });
1446
+ return entries;
1447
+ }
1448
+ /** The label of the optgroup an option sits in, or null for an ungrouped option. */
1449
+ function groupLabelOf(option) {
1450
+ var _a, _b;
1451
+ return (_b = (_a = parentOptgroupOf(option)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : null;
1452
+ }
1453
+ /**
1454
+ * The items Up and Down move through from `current`, one tree level at a time: the panel's rows
1455
+ * (groups and ungrouped options), or the open group's options. Drilled into a group, its row
1456
+ * (drawn as the row back) comes first, above its options, as a tree draws a parent above its children.
1457
+ * Disabled options and groups stay in it, as the APG listbox and tree patterns advise, so they're
1458
+ * announced as unavailable rather than hidden from the keyboard.
1459
+ */
1460
+ function panelColumn(entries, openGroup, current, drilledIn) {
1461
+ const open = openGroup === null ? undefined : findGroup(entries, openGroup);
1462
+ if (open !== undefined) {
1463
+ const options = open.options.map(({ index }) => index);
1464
+ if (drilledIn)
1465
+ return [open.optgroup, ...options];
1466
+ if (typeof current === 'number' && options.includes(current))
1467
+ return options;
1468
+ }
1469
+ return entries.map(entry => (entry.kind === 'group' ? entry.group.optgroup : entry.index));
1470
+ }
1471
+ /** The panel's group for an optgroup, if it's showing. */
1472
+ function findGroup(entries, optgroup) {
1473
+ for (const entry of entries) {
1474
+ if (entry.kind === 'group' && entry.group.optgroup === optgroup)
1475
+ return entry.group;
1476
+ }
1477
+ return undefined;
1478
+ }
1479
+ /** Moving from one group row to another waits this long, so a diagonal trip into the flyout doesn't switch groups. */
1480
+ const SWITCH_DELAY_MS = 120;
1481
+ /** Leaving a group (into the gap beside its flyout, say) waits this long before closing it. */
1482
+ const CLOSE_DELAY_MS = 200;
1483
+ /** Space between the panel's edge and the flyout: --pine-dimension-050 (4px), per the Figma frames. */
1484
+ const FLYOUT_GAP_PX = 4;
1485
+ /** How close the flyout may come to the viewport edge: --pine-dimension-100 (8px). */
1486
+ const VIEWPORT_PADDING_PX = 8;
1487
+ /** A flyout never shrinks below roughly three rows, even when little space is left. */
1488
+ const MIN_FLYOUT_HEIGHT_PX = 120;
1489
+ /**
1490
+ * Opens and closes a group's flyout with hover intent, and keeps the open flyout positioned beside
1491
+ * its group row. The flyout renders inside the row, so moving the pointer into it never leaves
1492
+ * the row; the delays cover the gap between panel and flyout and diagonal moves across rows.
1493
+ */
1494
+ /**
1495
+ * Scrolls `el` into view inside `container` only. A flyout option needs this: the flyout is `fixed`
1496
+ * beside the panel but sits inside it in the DOM, so `scrollIntoView` would also scroll the panel
1497
+ * and the page, moving the flyout's row out from under it.
1498
+ */
1499
+ function scrollIntoViewWithin(container, el) {
1500
+ const bounds = container.getBoundingClientRect();
1501
+ const rect = el.getBoundingClientRect();
1502
+ if (rect.top < bounds.top) {
1503
+ container.scrollTop -= bounds.top - rect.top;
1504
+ }
1505
+ else if (rect.bottom > bounds.bottom) {
1506
+ container.scrollTop += rect.bottom - bounds.bottom;
1507
+ }
1508
+ }
1509
+ class FlyoutController {
1510
+ constructor(getOpenGroup, setOpenGroup) {
1511
+ this.getOpenGroup = getOpenGroup;
1512
+ this.setOpenGroup = setOpenGroup;
1513
+ }
1514
+ /** Pointer entered a group row (or its flyout, which sits inside it). */
1515
+ enter(label) {
1516
+ this.clearClose();
1517
+ const open = this.getOpenGroup();
1518
+ if (open === label) {
1519
+ this.clearSwitch();
1520
+ return;
1521
+ }
1522
+ if (open === null) {
1523
+ this.setOpenGroup(label);
1524
+ return;
1525
+ }
1526
+ this.clearSwitch();
1527
+ this.switchTimer = setTimeout(() => {
1528
+ this.switchTimer = undefined;
1529
+ this.setOpenGroup(label);
1530
+ }, SWITCH_DELAY_MS);
1531
+ }
1532
+ /** Pointer left a group row and its flyout. */
1533
+ leave(label) {
1534
+ this.clearSwitch();
1535
+ if (this.getOpenGroup() !== label)
1536
+ return;
1537
+ this.clearClose();
1538
+ this.closeTimer = setTimeout(() => {
1539
+ this.closeTimer = undefined;
1540
+ if (this.getOpenGroup() === label)
1541
+ this.setOpenGroup(null);
1542
+ }, CLOSE_DELAY_MS);
1543
+ }
1544
+ /**
1545
+ * A click or tap on a group row opens it. It never closes it: on desktop the hover that preceded
1546
+ * the click has already opened it, and touch browsers fire an emulated mouseenter and then click
1547
+ * in the same tap. Closing happens on leaving the row or closing the panel.
1548
+ */
1549
+ open(label) {
1550
+ this.clearTimers();
1551
+ this.setOpenGroup(label);
1552
+ }
1553
+ /**
1554
+ * Keeps `flyout` beside `row`: horizontally against the panel's edge, vertically so its first
1555
+ * option lines up with the row. `fixed` positioning so the panel's scrolling can't clip it,
1556
+ * including when the panel is portaled into a dialog.
1557
+ */
1558
+ position(row, panel, flyout) {
1559
+ if (this.positionedFlyout === flyout && this.stopAutoUpdate)
1560
+ return;
1561
+ this.stopPositioning();
1562
+ this.positionedFlyout = flyout;
1563
+ const reference = {
1564
+ getBoundingClientRect: () => {
1565
+ const panelRect = panel.getBoundingClientRect();
1566
+ const rowRect = row.getBoundingClientRect();
1567
+ return {
1568
+ x: panelRect.x,
1569
+ y: rowRect.y,
1570
+ left: panelRect.left,
1571
+ right: panelRect.right,
1572
+ top: rowRect.top,
1573
+ bottom: rowRect.bottom,
1574
+ width: panelRect.width,
1575
+ height: rowRect.height,
1576
+ };
1577
+ },
1578
+ contextElement: row,
1579
+ };
1580
+ // The flyout's own top padding, so its first option, not its edge, lines up with the row.
1581
+ const flyoutPaddingTop = parseFloat(getComputedStyle(flyout).paddingTop) || 0;
1582
+ const update = () => computePosition(reference, flyout, {
1583
+ placement: 'right-start',
1584
+ strategy: 'fixed',
1585
+ middleware: [
1586
+ offset({ mainAxis: FLYOUT_GAP_PX, crossAxis: -flyoutPaddingTop }),
1587
+ flip({ fallbackPlacements: ['left-start'] }),
1588
+ shift({ padding: VIEWPORT_PADDING_PX }),
1589
+ // A long group scrolls inside the flyout instead of running off the viewport.
1590
+ size({
1591
+ padding: VIEWPORT_PADDING_PX,
1592
+ apply({ availableHeight }) {
1593
+ flyout.style.maxHeight = `${Math.max(availableHeight, MIN_FLYOUT_HEIGHT_PX)}px`;
1594
+ },
1595
+ }),
1596
+ // Hidden with its row when the panel scrolls the row out of view.
1597
+ hide({ strategy: 'referenceHidden' }),
1598
+ ],
1599
+ }).then(({ x, y, middlewareData }) => {
1600
+ var _a;
1601
+ // It starts hidden (see the stylesheet) so it never flashes in the row before it's placed.
1602
+ Object.assign(flyout.style, {
1603
+ position: 'fixed',
1604
+ left: `${x}px`,
1605
+ top: `${y}px`,
1606
+ visibility: ((_a = middlewareData.hide) === null || _a === void 0 ? void 0 : _a.referenceHidden) === true ? 'hidden' : 'visible',
1607
+ });
1608
+ const reveal = this.pendingReveal;
1609
+ this.pendingReveal = undefined;
1610
+ if (reveal !== undefined && flyout.contains(reveal))
1611
+ scrollIntoViewWithin(flyout, reveal);
1612
+ });
1613
+ this.stopAutoUpdate = autoUpdate(reference, flyout, () => {
1614
+ void update();
1615
+ });
1616
+ }
1617
+ /**
1618
+ * Scrolls `option` into view inside its flyout. Before the flyout's first placement its height
1619
+ * isn't capped yet, so the option looks visible; it's revealed again once the placement lands.
1620
+ */
1621
+ reveal(flyout, option) {
1622
+ scrollIntoViewWithin(flyout, option);
1623
+ if (flyout.style.maxHeight === '')
1624
+ this.pendingReveal = option;
1625
+ }
1626
+ stopPositioning() {
1627
+ var _a;
1628
+ (_a = this.stopAutoUpdate) === null || _a === void 0 ? void 0 : _a.call(this);
1629
+ this.stopAutoUpdate = undefined;
1630
+ this.positionedFlyout = undefined;
1631
+ this.pendingReveal = undefined;
1632
+ }
1633
+ /** The panel closed or the component left the page. */
1634
+ reset() {
1635
+ this.clearTimers();
1636
+ this.stopPositioning();
1637
+ }
1638
+ clearTimers() {
1639
+ this.clearSwitch();
1640
+ this.clearClose();
1641
+ }
1642
+ clearSwitch() {
1643
+ if (this.switchTimer !== undefined)
1644
+ clearTimeout(this.switchTimer);
1645
+ this.switchTimer = undefined;
1646
+ }
1647
+ clearClose() {
1648
+ if (this.closeTimer !== undefined)
1649
+ clearTimeout(this.closeTimer);
1650
+ this.closeTimer = undefined;
1651
+ }
1652
+ }
1653
+
1654
+ const pdsComboboxCss = () => `:host{display:block}:host([aria-disabled=true]) .pds-combobox__input-icon{color:var(--pine-color-text-disabled);pointer-events:none}.pds-combobox{position:relative}.pds-combobox__label{color:var(--pine-color-text-label);display:block;font:var(--pine-typography-body-medium);letter-spacing:var(--pine-letter-spacing);-webkit-margin-after:var(--pine-dimension-2xs);margin-block-end:var(--pine-dimension-2xs)}.pds-combobox__input-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;position:relative;width:100%}.pds-combobox__input{background:var(--pine-color-background-container);border:var(--pine-border);border-radius:var(--pine-dimension-125);-webkit-box-sizing:border-box;box-sizing:border-box;color:var(--pine-color-text-strong);-ms-flex:1;flex:1;font:var(--pine-typography-body-medium);padding:var(--pine-dimension-xs) var(--pine-dimension-450) var(--pine-dimension-xs) var(--pine-dimension-150);-webkit-transition:border-color var(--pine-motion-duration-base) ease;transition:border-color var(--pine-motion-duration-base) ease;width:100%}.pds-combobox__input:hover:not(:disabled){border-color:var(--pine-color-border-hover)}.pds-combobox__input:disabled{background:var(--pine-color-background-container-disabled);border-color:var(--pine-color-border-disabled);color:var(--pine-color-text-disabled);cursor:not-allowed}.pds-combobox__input:disabled::-webkit-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::-moz-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled:-ms-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::-ms-input-placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:disabled::placeholder{color:var(--pine-color-text-placeholder-disabled)}.pds-combobox__input:focus-visible{border-color:var(--pine-color-border-active);outline:var(--pine-outline-focus);outline-offset:var(--pine-border-width)}.pds-combobox__input::-webkit-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::-moz-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input:-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input::placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__input.pds-combobox__input--invalid{background:var(--pine-color-red-050);border-color:var(--pine-color-border-danger)}:host-context([data-theme=dark]) .pds-combobox__input.pds-combobox__input--invalid{background:var(--pine-color-red-950)}.pds-combobox__input.pds-combobox__input--invalid:hover:not(:disabled){border-color:var(--pine-color-border-danger)}.pds-combobox__input.pds-combobox__input--invalid:focus-visible{outline-color:var(--pine-color-focus-ring-danger)}.pds-combobox__input-icon{color:var(--pine-color-text-secondary);inset-inline-end:var(--pine-dimension-150);pointer-events:none;position:absolute;z-index:calc(var(--pine-z-index-raised) - 1)}.pds-combobox__helper{color:var(--pine-color-text-message);font:var(--pine-typography-body-sm-medium);-webkit-margin-before:var(--pine-dimension-2xs);margin-block-start:var(--pine-dimension-2xs)}.pds-combobox__error{-ms-flex-align:start;align-items:flex-start;color:var(--pine-color-text-message-danger);display:-ms-flexbox;display:flex;font:var(--pine-typography-body-sm-medium);gap:var(--pine-dimension-2xs);-webkit-margin-before:var(--pine-dimension-2xs);margin-block-start:var(--pine-dimension-2xs)}.pds-combobox__error pds-icon{-ms-flex-negative:0;flex-shrink:0;-webkit-margin-before:var(--pine-dimension-025);margin-block-start:var(--pine-dimension-025)}.pds-combobox__listbox{background:var(--pine-color-background-overlay);border:0;border-radius:var(--pine-dimension-125);-webkit-box-shadow:var(--pine-box-shadow);box-shadow:var(--pine-box-shadow);list-style:none;margin:0;min-width:220px;overflow-y:auto;padding:var(--pine-dimension-xs);position:absolute;z-index:var(--pine-z-index-raised)}.pds-combobox__option{-ms-flex-align:center;align-items:center;background:transparent;border-radius:var(--pine-dimension-125);color:var(--pine-color-text-secondary);cursor:pointer;display:-ms-flexbox;display:flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;padding:var(--pine-dimension-xs) var(--pine-dimension-sm);position:relative;-webkit-transition:background 0.15s;transition:background 0.15s}.pds-combobox__option[aria-selected=true]{background:var(--pine-color-background-muted)}.pds-combobox__option:focus-visible{outline:0}.pds-combobox__option.pds-combobox__option--layout .pds-combobox__option-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__option.pds-combobox__option--chip .pds-combobox__option-chip{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__option:last-child{-webkit-margin-after:0;margin-block-end:0}.pds-combobox__option--highlighted,.pds-combobox__option[selected],.pds-combobox__option--selected{background:var(--pine-color-background-muted)}.pds-combobox__option--disabled,.pds-combobox__group-row--disabled>.pds-combobox__group-row-trigger,.pds-combobox__group-back--disabled>.pds-combobox__group-back-trigger,.pds-combobox__group--disabled>.pds-combobox__group-label{color:var(--pine-color-text-disabled)}.pds-combobox__option--disabled{cursor:not-allowed}.pds-combobox__option--disabled .pds-combobox__option-chip,.pds-combobox__option--disabled .pds-combobox__option-layout-wrapper{opacity:0.5}.pds-combobox__option-check{color:currentColor;font-size:var(--pine-dimension-150);-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__group-label{color:var(--pine-color-text-tertiary);cursor:default;font:var(--pine-typography-heading-caption);-webkit-margin-after:var(--pine-dimension-2xs);margin-block-end:var(--pine-dimension-2xs);-webkit-margin-before:var(--pine-dimension-150);margin-block-start:var(--pine-dimension-150);padding:var(--pine-dimension-2xs) var(--pine-dimension-sm);text-transform:uppercase}.pds-combobox__group-label:first-child{-webkit-margin-before:0;margin-block-start:0}.pds-combobox__group{list-style:none;-webkit-margin-before:var(--pine-dimension-150);margin-block-start:var(--pine-dimension-150)}.pds-combobox__group:first-child{-webkit-margin-before:0;margin-block-start:0}.pds-combobox__group-list{list-style:none;margin:0;padding:0}.pds-combobox__listbox--grouped .pds-combobox__group-list{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--pine-dimension-2xs)}.pds-combobox__group-label--with-icon{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;gap:var(--pine-dimension-xs)}.pds-combobox__group-icon{-ms-flex-negative:0;flex-shrink:0}.pds-combobox__group-row{list-style:none;position:relative}.pds-combobox__group-row-trigger{-ms-flex-align:center;align-items:center;border-radius:var(--pine-dimension-125);color:var(--pine-color-text-secondary);cursor:pointer;display:-ms-flexbox;display:flex;font:var(--pine-typography-body-medium);gap:var(--pine-dimension-xs);-ms-flex-pack:justify;justify-content:space-between;padding:var(--pine-dimension-xs) var(--pine-dimension-sm);-webkit-transition:background 0.15s;transition:background 0.15s}.pds-combobox__group-row--open>.pds-combobox__group-row-trigger,.pds-combobox__group-row--has-selection>.pds-combobox__group-row-trigger,.pds-combobox__group-row--highlighted>.pds-combobox__group-row-trigger,.pds-combobox__group-back--highlighted>.pds-combobox__group-row-trigger,.pds-combobox__group-row-trigger:hover{background:var(--pine-color-background-muted)}.pds-combobox__listbox--drill-in,.pds-combobox__listbox--drill-out{overflow-x:hidden}.pds-combobox__listbox--drill-in>.pds-combobox__group-back{-webkit-animation:pds-combobox-drill-from-end var(--pine-motion-duration-base) var(--pine-motion-easing-out);animation:pds-combobox-drill-from-end var(--pine-motion-duration-base) var(--pine-motion-easing-out)}.pds-combobox__listbox--drill-out>li{-webkit-animation:pds-combobox-drill-from-start var(--pine-motion-duration-base) var(--pine-motion-easing-out);animation:pds-combobox-drill-from-start var(--pine-motion-duration-base) var(--pine-motion-easing-out)}@-webkit-keyframes pds-combobox-drill-from-end{from{opacity:0;-webkit-transform:translateX(var(--pine-dimension-sm));transform:translateX(var(--pine-dimension-sm))}}@keyframes pds-combobox-drill-from-end{from{opacity:0;-webkit-transform:translateX(var(--pine-dimension-sm));transform:translateX(var(--pine-dimension-sm))}}@-webkit-keyframes pds-combobox-drill-from-start{from{opacity:0;-webkit-transform:translateX(calc(var(--pine-dimension-sm) * -1));transform:translateX(calc(var(--pine-dimension-sm) * -1))}}@keyframes pds-combobox-drill-from-start{from{opacity:0;-webkit-transform:translateX(calc(var(--pine-dimension-sm) * -1));transform:translateX(calc(var(--pine-dimension-sm) * -1))}}.pds-combobox__group-row--keyboard>.pds-combobox__group-row-trigger,.pds-combobox__group-back--keyboard>.pds-combobox__group-row-trigger{outline:var(--pine-outline-focus);outline-offset:calc(var(--pine-border-width) * -2)}.pds-combobox__group-row-label{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;gap:var(--pine-dimension-xs);min-width:0}.pds-combobox__group-row-caret{-ms-flex-negative:0;flex-shrink:0}.pds-combobox__listbox--grouped,.pds-combobox__flyout{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--pine-dimension-2xs);padding:var(--pine-dimension-2xs)}.pds-combobox__flyout{background:var(--pine-color-background-overlay);border-radius:var(--pine-dimension-125);-webkit-box-shadow:var(--pine-box-shadow);box-shadow:var(--pine-box-shadow);list-style:none;margin:0;overflow-y:auto;position:fixed;visibility:hidden;width:-webkit-max-content;width:-moz-max-content;width:max-content;z-index:1}.pds-combobox__listbox--with-search{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden;padding:0}.pds-combobox__listbox-options{-ms-flex:1;flex:1;list-style:none;margin:0;min-height:0;overflow-y:auto;padding:var(--pine-dimension-xs)}.pds-combobox__listbox-options.pds-combobox__listbox--grouped{padding:var(--pine-dimension-2xs)}.pds-combobox__panel-search{-ms-flex-align:center;align-items:center;-webkit-border-after:var(--pine-border);border-block-end:var(--pine-border);border-block-end-color:var(--pine-color-border-subtle);display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0;gap:var(--pine-dimension-xs);padding:var(--pine-dimension-xs) var(--pine-dimension-sm)}.pds-combobox__panel-search pds-icon{color:var(--pine-color-text-muted);-ms-flex-negative:0;flex-shrink:0}.pds-combobox__panel-search:focus-within{border-block-end-color:var(--pine-color-border-active)}.pds-combobox__panel-search-input{background:transparent;border:0;color:var(--pine-color-text-strong);-ms-flex:1;flex:1;font:var(--pine-typography-body);letter-spacing:var(--pine-letter-spacing);min-width:0;outline:none}.pds-combobox__panel-search-input::-webkit-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__panel-search-input::-moz-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__panel-search-input:-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__panel-search-input::-ms-input-placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__panel-search-input::placeholder{color:var(--pine-color-text-placeholder)}.pds-combobox__group-back{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--pine-dimension-2xs);list-style:none}.pds-combobox__group-back-trigger{-ms-flex-pack:start;justify-content:flex-start}.pds-combobox__listbox-options--drilled-in.pds-combobox__listbox--grouped{-webkit-padding-before:0;padding-block-start:0}.pds-combobox__listbox-options--drilled-in:focus{outline:none}.pds-combobox__listbox-options--drilled-in:focus .pds-combobox__group-back-trigger{border-block-end-color:var(--pine-color-border-active)}:where(.pds-combobox__listbox-options--drilled-in) .pds-combobox__group-back-trigger{background-color:var(--pine-color-background-overlay);-webkit-border-after:var(--pine-border);border-block-end:var(--pine-border);border-block-end-color:var(--pine-color-border-subtle);border-radius:0;inset-block-start:0;margin-inline:calc(var(--pine-dimension-2xs) * -1);position:-webkit-sticky;position:sticky;z-index:1}.pds-combobox__drill-in-options{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;gap:var(--pine-dimension-2xs);list-style:none;margin:0;padding:0}.visually-hidden{border:0;clip:rect(0 0 0 0);-webkit-clip-path:polygon(0 0, 0 0, 0 0);clip-path:polygon(0 0, 0 0, 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pds-combobox__loading{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding:var(--pine-dimension-150)}.pds-combobox__empty{color:var(--pine-color-text-tertiary);padding:var(--pine-dimension-150) var(--pine-dimension-sm);text-align:center}.pds-combobox__load-more{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding:var(--pine-dimension-150)}.pds-combobox__button-trigger{-ms-flex-align:center;align-items:center;background:var(--color-background-default, var(--pine-color-secondary));border:var(--pine-border);border-radius:var(--pine-border-radius-full);color:var(--color-text-default, var(--pine-color-text-inverse-emphasis));cursor:pointer;display:-ms-flexbox;display:flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;min-height:var(--pine-dimension-450);outline:none;padding:0 var(--pine-dimension-sm);-webkit-transition:border-color 0.15s, background 0.15s, -webkit-box-shadow 0.15s;transition:border-color 0.15s, background 0.15s, -webkit-box-shadow 0.15s;transition:border-color 0.15s, box-shadow 0.15s, background 0.15s;transition:border-color 0.15s, box-shadow 0.15s, background 0.15s, -webkit-box-shadow 0.15s;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.pds-combobox__button-trigger .pds-combobox__button-trigger-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1}.pds-combobox__button-trigger .trigger-content{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__button-trigger:focus-visible{border-color:var(--color-border-focus, var(--pine-color-border));-webkit-box-shadow:0 0 0 2px var(--color-outline, var(--pine-color-focus-ring));box-shadow:0 0 0 2px var(--color-outline, var(--pine-color-focus-ring))}.pds-combobox__button-trigger:hover{background:var(--color-background-hover, var(--pine-color-secondary-hover));border-color:var(--color-border-hover, var(--pine-color-border-hover))}.pds-combobox__button-trigger[aria-disabled=true],.pds-combobox__button-trigger:disabled{background:var(--color-background-disabled, var(--pine-color-secondary-disabled));border-color:var(--color-border-disabled, var(--pine-color-border-disabled));color:var(--color-text-disabled, var(--pine-color-text-secondary-disabled));cursor:not-allowed;opacity:0.6}.pds-combobox__button-trigger-label{color:inherit;-ms-flex:1 1 auto;flex:1 1 auto;text-align:start}.pds-combobox__button-trigger--input-shape{border-radius:var(--pine-dimension-125);min-height:var(--pine-dimension-500)}.pds-combobox__button-trigger-chevron{color:currentColor;-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__button-trigger--primary{--color-background-default:var(--pine-color-primary);--color-background-hover:var(--pine-color-primary-hover);--color-background-disabled:var(--pine-color-primary-disabled);--color-border-default:var(--pine-color-primary);--color-border-hover:var(--pine-color-primary-hover);--color-border-disabled:var(--pine-color-primary-disabled);--color-border-focus:var(--pine-color-primary);--color-text-default:var(--pine-color-text-primary);--color-text-disabled:var(--pine-color-text-primary-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--accent{--color-background-default:var(--pine-color-accent);--color-background-hover:var(--pine-color-accent-hover);--color-background-disabled:var(--pine-color-accent-disabled);--color-border-default:var(--pine-color-accent);--color-border-hover:var(--pine-color-accent-hover);--color-border-disabled:var(--pine-color-accent-disabled);--color-border-focus:var(--pine-color-accent);--color-text-default:var(--pine-color-text-primary);--color-text-disabled:var(--pine-color-text-accent-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--secondary{--color-background-default:var(--pine-color-secondary);--color-background-hover:var(--pine-color-secondary-hover);--color-background-disabled:var(--pine-color-secondary-disabled);--color-border-default:var(--pine-color-border);--color-border-hover:var(--pine-color-border-hover);--color-border-disabled:var(--pine-color-border-disabled);--color-border-focus:var(--pine-color-border);--color-text-default:var(--pine-color-text-secondary);--color-text-disabled:var(--pine-color-text-secondary-disabled);--color-outline:var(--pine-color-focus-ring)}.pds-combobox__button-trigger--destructive{--color-background-default:var(--pine-color-danger);--color-background-hover:var(--pine-color-danger-hover);--color-background-disabled:var(--pine-color-danger-disabled);--color-border-default:var(--pine-color-danger);--color-border-hover:var(--pine-color-danger-hover);--color-border-disabled:var(--pine-color-danger-disabled);--color-border-focus:var(--pine-color-danger);--color-text-default:var(--pine-color-white);--color-text-disabled:var(--pine-color-text-danger-disabled);--color-outline:var(--pine-color-focus-ring-danger)}[data-layout]{border-radius:var(--pine-dimension-125);padding-block:var(--pine-dimension-xs)}.pds-combobox__chip-trigger{-ms-flex-align:center;align-items:center;border-radius:var(--pine-dimension-sm);cursor:pointer;display:-ms-inline-flexbox;display:inline-flex;font:var(--pine-typography-body-medium);-ms-flex-pack:justify;justify-content:space-between;outline:none;padding-block:var(--pine-dimension-025);padding-inline:var(--pine-dimension-150);-webkit-transition:all 0.15s ease;transition:all 0.15s ease;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.pds-combobox__chip-trigger .pds-combobox__chip-trigger-layout-wrapper{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1}.pds-combobox__chip-trigger .trigger-content{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex;width:100%}.pds-combobox__chip-trigger:focus-visible{outline:var(--pine-outline-focus);outline-offset:var(--pine-border-width)}.pds-combobox__chip-trigger[aria-disabled=true]{cursor:not-allowed;opacity:0.6}.pds-combobox__chip-trigger-label{color:inherit;-ms-flex:1 1 auto;flex:1 1 auto;text-align:start}.pds-combobox__chip-trigger-chevron{color:currentColor;-webkit-margin-start:var(--pine-dimension-150);margin-inline-start:var(--pine-dimension-150)}.pds-combobox__chip-trigger-icon{-webkit-margin-end:var(--pine-dimension-2xs);margin-inline-end:var(--pine-dimension-2xs)}.pds-combobox__chip-trigger--neutral,.pds-combobox__chip-trigger--accent,.pds-combobox__chip-trigger--success,.pds-combobox__chip-trigger--warning,.pds-combobox__chip-trigger--danger,.pds-combobox__chip-trigger--info{background:var(--chip-bg);border:var(--pine-border-width) solid var(--chip-border);color:var(--chip-text)}.pds-combobox__chip-trigger--neutral:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--accent:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--success:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--warning:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--danger:hover:not([aria-disabled=true]),.pds-combobox__chip-trigger--info:hover:not([aria-disabled=true]){background:var(--chip-bg-hover)}.pds-combobox__chip-trigger--neutral:focus-visible,.pds-combobox__chip-trigger--accent:focus-visible,.pds-combobox__chip-trigger--success:focus-visible,.pds-combobox__chip-trigger--warning:focus-visible,.pds-combobox__chip-trigger--danger:focus-visible,.pds-combobox__chip-trigger--info:focus-visible{border-color:var(--chip-border)}.pds-combobox__chip-trigger--neutral{--chip-bg:var(--pine-chip-color-neutral);--chip-bg-hover:var(--pine-chip-color-neutral-hover);--chip-border:var(--pine-chip-color-neutral-hover);--chip-text:var(--pine-color-text-neutral)}.pds-combobox__chip-trigger--accent{--chip-bg:var(--pine-chip-color-accent);--chip-bg-hover:var(--pine-chip-color-accent-hover);--chip-border:var(--pine-chip-color-accent-hover);--chip-text:var(--pine-color-text-accent)}.pds-combobox__chip-trigger--success{--chip-bg:var(--pine-chip-color-success);--chip-bg-hover:var(--pine-chip-color-success-hover);--chip-border:var(--pine-chip-color-success-hover);--chip-text:var(--pine-color-text-success)}.pds-combobox__chip-trigger--warning{--chip-bg:var(--pine-chip-color-warning);--chip-bg-hover:var(--pine-chip-color-warning-hover);--chip-border:var(--pine-chip-color-warning-hover);--chip-text:var(--pine-color-text-warning)}.pds-combobox__chip-trigger--danger{--chip-bg:var(--pine-chip-color-danger);--chip-bg-hover:var(--pine-chip-color-danger-hover);--chip-border:var(--pine-chip-color-danger-hover);--chip-text:var(--pine-color-text-danger)}.pds-combobox__chip-trigger--info{--chip-bg:var(--pine-chip-color-info);--chip-bg-hover:var(--pine-chip-color-info-hover);--chip-border:var(--pine-chip-color-info-hover);--chip-text:var(--pine-color-text-info)}.pds-combobox__chip-trigger--brand{background:-webkit-gradient(linear, left top, right top, from(#FF3E14), to(#6B62F2));background:linear-gradient(90deg, #FF3E14 0%, #6B62F2 100%);border:0;color:var(--pine-color-text-neutral);padding:1px;position:relative}.pds-combobox__chip-trigger--brand .pds-combobox__chip-trigger-label{background:rgba(255, 255, 255, 0.9);border-radius:calc(var(--pine-dimension-sm) - 1px);color:var(--pine-color-text-neutral);font-weight:var(--pine-font-weight-medium);padding:var(--pine-dimension-025) var(--pine-dimension-150);position:relative;z-index:1}.pds-combobox__chip-trigger--brand .pds-combobox__chip-trigger-chevron{position:relative;z-index:1}.pds-combobox__chip-trigger--brand:hover:not([aria-disabled=true]) .pds-combobox__chip-trigger-label{background:rgba(255, 255, 255, 0.8)}.pds-combobox__chip-trigger--dropdown:not(.pds-combobox__chip-trigger--brand){padding:var(--pine-dimension-none)}.pds-combobox__chip-trigger--dropdown:not(.pds-combobox__chip-trigger--brand) .pds-combobox__chip-trigger-label{padding:var(--pine-dimension-025) var(--pine-dimension-150)}.pds-combobox__chip-trigger--large .pds-combobox__chip-trigger-label{font-family:var(--pine-font-family-heading);font-size:var(--pine-font-size-heading-6);font-weight:var(--pine-font-weight-medium);letter-spacing:var(--pine-letter-spacing-heading-6)}.pds-combobox__chip-trigger--dot .pds-combobox__chip-trigger-label::before{border:var(--pine-border-width) solid transparent;border-radius:var(--pine-border-radius-full);content:"";display:inline-block;height:var(--pine-dimension-2xs);-webkit-margin-end:var(--pine-dimension-2xs);margin-inline-end:var(--pine-dimension-2xs);width:var(--pine-dimension-2xs)}`;
1393
1655
 
1394
1656
  const PdsCombobox = class {
1395
1657
  constructor(hostRef) {
@@ -1436,6 +1698,35 @@ const PdsCombobox = class {
1436
1698
  * @default 'host'
1437
1699
  */
1438
1700
  this.dropdownMount = 'host';
1701
+ /**
1702
+ * Accessible prefix for the row that returns to the group list when `group-display` is
1703
+ * `drill-in`, read before the open group's label. Pass a translated string to localize it; defaults to English.
1704
+ * @defaultValue 'Back'
1705
+ */
1706
+ this.drillInBackLabel = 'Back';
1707
+ /**
1708
+ * Maximum width of a group's flyout when `group-display` is `flyout`. Any valid CSS width value.
1709
+ * @default '380px'
1710
+ */
1711
+ this.flyoutMaxWidth = '380px';
1712
+ /**
1713
+ * Minimum width of a group's flyout when `group-display` is `flyout`. Any valid CSS width value.
1714
+ * The flyout is as wide as its options, between this and `flyout-max-width`.
1715
+ * @default '280px'
1716
+ */
1717
+ this.flyoutMinWidth = '280px';
1718
+ /**
1719
+ * How option groups (`<optgroup>`, or the `group` field of `options`) are shown in the dropdown.
1720
+ * `inline` lists each group's label above its options. `flyout` lists the groups, and opens a
1721
+ * group's options in a panel beside it on hover or click; while searching, the matching options
1722
+ * are listed under their group labels, and search also matches group labels. `flyout` groups
1723
+ * by `<optgroup>` (or `group`) only: options under a `<pds-text>` heading are listed ungrouped.
1724
+ * `drill-in` lists the groups too, but a click replaces the list with that group's options and a
1725
+ * row back to the groups; use it where nothing can open beside the dropdown, such as a side
1726
+ * panel. `flyout` falls back to `drill-in` when there is no room for a flyout on either side.
1727
+ * @default 'inline'
1728
+ */
1729
+ this.groupDisplay = 'inline';
1439
1730
  /**
1440
1731
  * Visually hides the label text for instances where only the combobox should be displayed.
1441
1732
  * The visible `<label>` is omitted (same pattern as `pds-select`) so label spacing does not reserve layout;
@@ -1449,6 +1740,23 @@ const PdsCombobox = class {
1449
1740
  * @default 'filter'
1450
1741
  */
1451
1742
  this.mode = 'filter';
1743
+ /**
1744
+ * Shows a search field at the top of the dropdown for the `button` and `chip` triggers, which
1745
+ * can't be typed into. Search filters the options the same way typing in the `input` trigger
1746
+ * does; in a grouped display it also matches group labels.
1747
+ * @default false
1748
+ */
1749
+ this.panelSearch = false;
1750
+ /**
1751
+ * Accessible label for the search input inside the dropdown panel (`panel-search`). Pass a translated string to localize it; defaults to English.
1752
+ * @defaultValue 'Search options'
1753
+ */
1754
+ this.searchOptionsLabel = 'Search options';
1755
+ /**
1756
+ * Placeholder text for the search input inside the dropdown panel (`panel-search`). Pass a translated string to localize it; defaults to English.
1757
+ * @defaultValue 'Find...'
1758
+ */
1759
+ this.searchPlaceholder = 'Find...';
1452
1760
  /**
1453
1761
  * Determines the combobox trigger: 'input' (editable input), 'button' (button-like, non-editable), or 'chip' (chip-like, non-editable).
1454
1762
  * @default 'input'
@@ -1521,6 +1829,30 @@ const PdsCombobox = class {
1521
1829
  * Internal state for dropdown open/close
1522
1830
  */
1523
1831
  this.isOpen = false;
1832
+ /**
1833
+ * The optgroup whose flyout is open, when `groupDisplay` is `flyout`.
1834
+ */
1835
+ this.openGroup = null;
1836
+ /**
1837
+ * Which way drill-in just moved, so the list slides that way: `in` to a group, `out` back to the
1838
+ * groups. Cleared once the slide ends, so later renders don't animate.
1839
+ */
1840
+ this.drillDirection = null;
1841
+ /**
1842
+ * The group row highlighted in the grouped panel. It counts only while no option is
1843
+ * highlighted (`highlightedIndex` is -1); see `highlightedGroupRow`.
1844
+ */
1845
+ this.highlightedGroup = null;
1846
+ /** The keys, not the pointer, moved the highlight last; the focus ring shows only then. */
1847
+ this.keyboardNavigating = false;
1848
+ /**
1849
+ * What's typed in the dropdown's own search field (`panelSearch`).
1850
+ */
1851
+ this.panelQuery = '';
1852
+ /**
1853
+ * `groupDisplay` is `flyout` but there's no room beside the dropdown, so groups drill in instead.
1854
+ */
1855
+ this.flyoutFallback = false;
1524
1856
  /**
1525
1857
  * Internal state for the currently selected option
1526
1858
  */
@@ -1550,12 +1882,39 @@ const PdsCombobox = class {
1550
1882
  this.portalEl = null;
1551
1883
  this.bodyPortalAutoUpdateActive = false;
1552
1884
  this.isUpdatingFromSelection = false;
1885
+ this.flyout = new FlyoutController(() => this.openGroup, group => {
1886
+ this.openGroup = group;
1887
+ });
1888
+ /** The groups in the flyout panel's last render, so a row's index finds its optgroup. */
1889
+ this.renderedGroups = [];
1890
+ /** Room for a flyout was checked for this open. */
1891
+ this.flyoutRoomChecked = false;
1892
+ /** The highlighted option sits in a flyout that hasn't rendered yet; focus it after the next render. */
1893
+ this.pendingOptionFocus = false;
1894
+ /** Group rows' DOM ids, stable across renders so `aria-activedescendant` can point at a row. */
1895
+ this.groupIds = new WeakMap();
1896
+ this.groupIdCount = 0;
1553
1897
  /**
1554
1898
  * In filter mode, after choosing an option the input still shows the label and would
1555
1899
  * otherwise filter the list to matching substrings only. While this flag is true,
1556
1900
  * the list shows every option until the user types (then normal filtering applies).
1557
1901
  */
1558
1902
  this.expandFilterListWhileOpen = false;
1903
+ this.onDrillAnimationEnd = (event) => {
1904
+ var _a;
1905
+ // Only the slide's own end: slotted consumer content can animate inside the list too.
1906
+ if ((_a = event.animationName) === null || _a === void 0 ? void 0 : _a.startsWith('pds-combobox-drill'))
1907
+ this.drillDirection = null;
1908
+ };
1909
+ /** `<label for>` only works on the input trigger; for a div trigger a click on the label focuses it. */
1910
+ this.onLabelClick = () => {
1911
+ var _a;
1912
+ if (this.trigger !== 'input' && !this.disabled) {
1913
+ (_a = this.triggerEl) === null || _a === void 0 ? void 0 : _a.focus();
1914
+ }
1915
+ };
1916
+ /** The query behind the options loaded from `async-url`. */
1917
+ this.lastFetchedQuery = '';
1559
1918
  this.handleInput = (e) => {
1560
1919
  const target = e.target;
1561
1920
  this.clearExpandFilterList();
@@ -1592,6 +1951,7 @@ const PdsCombobox = class {
1592
1951
  this.handleKeyDown = (e) => {
1593
1952
  if (!this.isOpen && (e.key === 'ArrowDown' || e.key === 'ArrowUp' || (e.altKey && e.key === 'ArrowDown'))) {
1594
1953
  e.preventDefault();
1954
+ this.keyboardNavigating = true;
1595
1955
  this.isOpen = true;
1596
1956
  this.prepareExpandFilterListOnOpen();
1597
1957
  this.filterOptions();
@@ -1613,75 +1973,53 @@ const PdsCombobox = class {
1613
1973
  if (!this.isOpen) {
1614
1974
  return;
1615
1975
  }
1976
+ if (this.handleGroupedPanelKey(e))
1977
+ return;
1978
+ // The input trigger's text keeps Space, Home and End while the grouped panel shows.
1979
+ if (this.showsGroupedPanel && this.trigger === 'input' && (e.key === ' ' || e.key === 'Home' || e.key === 'End'))
1980
+ return;
1616
1981
  // Get only the option elements (skip group labels) for navigation
1617
1982
  const selectableOptions = this.filteredItems.filter(item => item.tagName === 'OPTION');
1618
1983
  switch (e.key) {
1619
1984
  case 'ArrowDown':
1620
1985
  e.preventDefault();
1621
- // If no option is highlighted and we have options, start at 0
1622
- if (this.highlightedIndex < 0 && selectableOptions.length > 0) {
1623
- this.highlightedIndex = 0;
1624
- }
1625
- else {
1626
- this.highlightedIndex = Math.min(this.highlightedIndex + 1, selectableOptions.length - 1);
1627
- }
1628
- this.updateOptionFocus();
1986
+ // If no option is highlighted, start at the first
1987
+ this.highlightOptionAt(selectableOptions, this.highlightedIndex < 0 ? 0 : this.highlightedIndex + 1);
1629
1988
  break;
1630
1989
  case 'ArrowUp':
1631
1990
  e.preventDefault();
1632
- // If no option is highlighted and we have options, start at last option
1633
- if (this.highlightedIndex < 0 && selectableOptions.length > 0) {
1634
- this.highlightedIndex = selectableOptions.length - 1;
1635
- }
1636
- else {
1637
- this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
1638
- }
1639
- this.updateOptionFocus();
1991
+ // If no option is highlighted, start at the last
1992
+ this.highlightOptionAt(selectableOptions, this.highlightedIndex < 0 ? selectableOptions.length - 1 : this.highlightedIndex - 1);
1640
1993
  break;
1641
1994
  case 'Home':
1642
1995
  e.preventDefault();
1643
- if (selectableOptions.length > 0) {
1644
- this.highlightedIndex = 0;
1645
- this.updateOptionFocus();
1646
- }
1996
+ this.highlightOptionAt(selectableOptions, 0);
1647
1997
  break;
1648
1998
  case 'End':
1649
1999
  e.preventDefault();
1650
- if (selectableOptions.length > 0) {
1651
- this.highlightedIndex = selectableOptions.length - 1;
1652
- this.updateOptionFocus();
1653
- }
2000
+ this.highlightOptionAt(selectableOptions, selectableOptions.length - 1);
1654
2001
  break;
1655
2002
  case 'PageDown':
1656
2003
  e.preventDefault();
1657
- if (selectableOptions.length > 0) {
1658
- const nextIndex = Math.min(this.highlightedIndex + 10, selectableOptions.length - 1);
1659
- this.highlightedIndex = nextIndex;
1660
- this.updateOptionFocus();
1661
- }
2004
+ this.highlightOptionAt(selectableOptions, this.highlightedIndex + 10);
1662
2005
  break;
1663
2006
  case 'PageUp':
1664
2007
  e.preventDefault();
1665
- if (selectableOptions.length > 0) {
1666
- const prevIndex = Math.max(this.highlightedIndex - 10, 0);
1667
- this.highlightedIndex = prevIndex;
1668
- this.updateOptionFocus();
1669
- }
2008
+ this.highlightOptionAt(selectableOptions, this.highlightedIndex - 10);
1670
2009
  break;
1671
2010
  case 'Enter':
2011
+ case ' ': {
1672
2012
  e.preventDefault();
1673
- if (this.highlightedIndex >= 0 && this.highlightedIndex < selectableOptions.length) {
1674
- this.handleOptionClick(selectableOptions[this.highlightedIndex]);
1675
- this.restoreFocusToTrigger();
1676
- }
1677
- break;
1678
- case ' ':
1679
- e.preventDefault();
1680
- if (this.highlightedIndex >= 0 && this.highlightedIndex < selectableOptions.length) {
1681
- this.handleOptionClick(selectableOptions[this.highlightedIndex]);
2013
+ // An option in a flyout the pointer has since closed isn't on screen; don't choose it.
2014
+ if (this.showsGroupedPanel && this.activeDescendantId === undefined)
2015
+ break;
2016
+ const option = selectableOptions[this.highlightedIndex];
2017
+ if (option !== undefined && !isOptionDisabled(option)) {
2018
+ this.handleOptionClick(option);
1682
2019
  this.restoreFocusToTrigger();
1683
2020
  }
1684
2021
  break;
2022
+ }
1685
2023
  case 'Escape':
1686
2024
  e.preventDefault();
1687
2025
  this.isOpen = false;
@@ -1706,12 +2044,53 @@ const PdsCombobox = class {
1706
2044
  const idx = Number(event.currentTarget.getAttribute('data-option-index'));
1707
2045
  const selectableOptions = this.filteredItems.filter(item => item.tagName === 'OPTION');
1708
2046
  const option = selectableOptions[idx];
2047
+ if (isOptionDisabled(option))
2048
+ return;
1709
2049
  this.handleOptionClick(option);
2050
+ // The search field closes with the panel; send focus back to the trigger instead of losing it.
2051
+ // (Enter and Space already restore focus in the key handler.)
2052
+ if (this.usesPanelSearch)
2053
+ this.restoreFocusToTrigger();
1710
2054
  };
1711
2055
  // Event handler for mouse enter on option
1712
2056
  this.onOptionMouseEnter = (event) => {
1713
2057
  const idx = Number(event.currentTarget.getAttribute('data-option-index'));
1714
2058
  this.highlightedIndex = idx;
2059
+ this.keyboardNavigating = false;
2060
+ };
2061
+ this.onGroupRowMouseEnter = (event) => {
2062
+ const group = this.groupFromEvent(event);
2063
+ if (group !== null)
2064
+ this.flyout.enter(group);
2065
+ };
2066
+ this.onGroupRowMouseLeave = (event) => {
2067
+ const group = this.groupFromEvent(event);
2068
+ if (group !== null)
2069
+ this.flyout.leave(group);
2070
+ };
2071
+ // The pointer highlights a group's row as it does an option, so the keys carry on from there.
2072
+ this.onGroupRowTriggerMouseEnter = (event) => {
2073
+ const group = this.groupFromEvent(event);
2074
+ if (group !== null)
2075
+ this.highlightGroupRowByPointer(group);
2076
+ };
2077
+ this.onGroupBackMouseEnter = () => {
2078
+ if (this.openGroup !== null)
2079
+ this.highlightGroupRowByPointer(this.openGroup);
2080
+ };
2081
+ this.onGroupRowClick = (event) => {
2082
+ var _a;
2083
+ const group = this.groupFromEvent(event);
2084
+ if (group === null)
2085
+ return;
2086
+ this.flyout.open(group);
2087
+ // Highlight the group's first option, so the arrow keys carry on from the group just opened
2088
+ // rather than from wherever the highlight was before.
2089
+ const first = (_a = this.renderedGroups.find(entry => entry.optgroup === group)) === null || _a === void 0 ? void 0 : _a.options[0];
2090
+ if (first !== undefined) {
2091
+ this.highlightedIndex = first.index;
2092
+ this.updateAriaActiveDescendant();
2093
+ }
1715
2094
  };
1716
2095
  // Prevent blur on mousedown
1717
2096
  this.onOptionMouseDown = (event) => {
@@ -1728,10 +2107,7 @@ const PdsCombobox = class {
1728
2107
  if (this.isOpen) {
1729
2108
  this.prepareExpandFilterListOnOpen();
1730
2109
  this.filterOptions();
1731
- // Trigger initial fetch if async and no options loaded yet
1732
- if (this.asyncUrl && this.internalOptions.length === 0) {
1733
- this.debouncedFetchAsyncOptions(this.displayText, 1);
1734
- }
2110
+ this.fetchAsyncOptionsOnOpen();
1735
2111
  // Set highlighted index and prepare for keyboard navigation
1736
2112
  this.setInitialHighlightedIndex();
1737
2113
  // For button trigger, prepare for arrow-key navigation mode
@@ -1746,12 +2122,17 @@ const PdsCombobox = class {
1746
2122
  };
1747
2123
  // Handler for button trigger keyboard events
1748
2124
  this.onButtonTriggerKeyDown = (e) => {
2125
+ // Escape closes an open group before the dropdown. Other keys reach the tree through handleKeyDown.
2126
+ if (this.isOpen && e.key === 'Escape' && this.handleGroupedPanelKey(e))
2127
+ return;
1749
2128
  if ((e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown' || e.key === 'ArrowUp') && !this.isOpen) {
1750
2129
  e.preventDefault();
1751
2130
  e.stopPropagation(); // Prevent the event from bubbling and triggering click
2131
+ this.keyboardNavigating = true;
1752
2132
  this.isOpen = true;
1753
2133
  this.prepareExpandFilterListOnOpen();
1754
2134
  this.filterOptions();
2135
+ this.fetchAsyncOptionsOnOpen();
1755
2136
  // Set highlighted index immediately
1756
2137
  this.setInitialHighlightedIndex();
1757
2138
  setTimeout(() => {
@@ -1784,11 +2165,13 @@ const PdsCombobox = class {
1784
2165
  };
1785
2166
  // Close dropdown when focus leaves the combobox
1786
2167
  this.onComboboxFocusOut = (event) => {
1787
- var _a, _b;
2168
+ var _a, _b, _c;
1788
2169
  const relatedTarget = event.relatedTarget;
1789
2170
  const isRelatedTargetInListbox = relatedTarget &&
1790
2171
  (((_a = this.listboxEl) === null || _a === void 0 ? void 0 : _a.contains(relatedTarget)) || ((_b = this.portalEl) === null || _b === void 0 ? void 0 : _b.contains(relatedTarget)));
1791
- const isRelatedTargetInCombobox = this.el.contains(relatedTarget);
2172
+ // `contains` doesn't cross into the shadow root, where the trigger lives; with panel search,
2173
+ // focus leaves the search field for the trigger whenever it's clicked to close.
2174
+ const isRelatedTargetInCombobox = relatedTarget !== null && (this.el.contains(relatedTarget) || !!((_c = this.el.shadowRoot) === null || _c === void 0 ? void 0 : _c.contains(relatedTarget)));
1792
2175
  // Don't close if focus is moving to an option in the listbox or staying within the combobox
1793
2176
  if (!isRelatedTargetInCombobox && !isRelatedTargetInListbox) {
1794
2177
  this.isOpen = false;
@@ -1811,11 +2194,58 @@ const PdsCombobox = class {
1811
2194
  // Load more when near bottom (within 50px)
1812
2195
  if (scrollBottom < 50) {
1813
2196
  this.pdsComboboxLoadOptions.emit({
1814
- query: this.displayText,
2197
+ query: this.activeQuery,
1815
2198
  page: this.currentPage + 1,
1816
2199
  });
1817
- this.debouncedFetchAsyncOptions(this.displayText, this.currentPage + 1);
2200
+ this.debouncedFetchAsyncOptions(this.activeQuery, this.currentPage + 1);
2201
+ }
2202
+ };
2203
+ // A press on the panel's padding, captions or status rows keeps focus in the search field;
2204
+ // otherwise it would blur the field, closing a portaled panel or stranding the keys.
2205
+ this.onPanelMouseDown = (event) => {
2206
+ if (event.target !== this.panelSearchEl)
2207
+ event.preventDefault();
2208
+ };
2209
+ this.onPanelSearchInput = (event) => {
2210
+ this.setPanelQuery(event.target.value);
2211
+ };
2212
+ // Space, Home and End edit the search text rather than moving through the options.
2213
+ this.onPanelSearchKeyDown = (event) => {
2214
+ if (event.key === ' ' || event.key === 'Home' || event.key === 'End')
2215
+ return;
2216
+ if (this.handlePanelTab(event))
2217
+ return;
2218
+ this.handleKeyDown(event);
2219
+ };
2220
+ /**
2221
+ * Keys in the list while a drilled-in group hides the search field. Backspace, like ArrowLeft,
2222
+ * steps back to the groups; a character starts a search of the whole list. Characters typed
2223
+ * before the search field renders and takes focus still land on the list, so they add to the
2224
+ * query rather than starting it again.
2225
+ */
2226
+ this.onPanelTreeKeyDown = (event) => {
2227
+ if (this.handlePanelTab(event))
2228
+ return;
2229
+ if (event.key === 'Backspace') {
2230
+ event.preventDefault();
2231
+ if (!this.leaveDrilledInGroup() && this.panelQuery !== '')
2232
+ this.setPanelQuery(this.panelQuery.slice(0, -1));
2233
+ return;
1818
2234
  }
2235
+ // AltGr (Ctrl+Alt on Windows) and Option on macOS type characters too; Meta and Ctrl alone are
2236
+ // shortcuts.
2237
+ if (event.key.length === 1 && event.key !== ' ' && !event.metaKey && (!event.ctrlKey || event.altKey)) {
2238
+ event.preventDefault();
2239
+ this.flyout.reset();
2240
+ // The query first, so leaving the group reads as search results, not a slide back.
2241
+ this.setPanelQuery(this.panelQuery + event.key);
2242
+ this.openGroup = null;
2243
+ return;
2244
+ }
2245
+ this.handleKeyDown(event);
2246
+ };
2247
+ this.onGroupBackClick = () => {
2248
+ this.leaveDrilledInGroup();
1819
2249
  };
1820
2250
  }
1821
2251
  connectedCallback() {
@@ -1852,15 +2282,106 @@ const PdsCombobox = class {
1852
2282
  this.deferredPortalTeardownId = undefined;
1853
2283
  }
1854
2284
  (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
2285
+ cancelDebouncedEvent(this.pdsComboboxSearch);
1855
2286
  this.clearAsyncFetchState();
1856
2287
  this.removeBodyPortal();
2288
+ this.flyout.reset();
1857
2289
  }
1858
2290
  componentDidRender() {
2291
+ var _a;
1859
2292
  if (this.usesBodyPortal && this.isOpen) {
1860
2293
  this.syncBodyPortal();
1861
2294
  }
2295
+ const row = (_a = this.listboxEl) === null || _a === void 0 ? void 0 : _a.querySelector('.pds-combobox__group-row--open');
2296
+ const flyoutEl = row === null || row === void 0 ? void 0 : row.querySelector('.pds-combobox__flyout');
2297
+ if (this.isOpen && this.listboxEl && row && flyoutEl) {
2298
+ this.flyout.position(row, this.listboxEl, flyoutEl);
2299
+ }
2300
+ else {
2301
+ this.flyout.stopPositioning();
2302
+ }
2303
+ // The row back is sticky over the group's options; scrolling an option into view stops below
2304
+ // it. Set before any scroll below, and when it first applies, scroll the highlighted option
2305
+ // again: the list keeps its offset on drilling in, and an earlier scroll had no padding.
2306
+ if (this.panelTreeEl) {
2307
+ const header = this.hidesPanelSearch ? this.panelTreeEl.querySelector('.pds-combobox__group-back-trigger') : null;
2308
+ const padding = header ? `${header.offsetHeight}px` : '';
2309
+ if (this.panelTreeEl.style.scrollPaddingBlockStart !== padding) {
2310
+ this.panelTreeEl.style.scrollPaddingBlockStart = padding;
2311
+ if (padding !== '' && this.highlightedIndex >= 0)
2312
+ this.pendingOptionFocus = true;
2313
+ }
2314
+ }
2315
+ if (this.pendingOptionFocus) {
2316
+ this.pendingOptionFocus = false;
2317
+ this.updateOptionFocus();
2318
+ }
2319
+ // Panel search keeps focus in the search field, or in the list while a group hides the field.
2320
+ const panelFocusEl = this.hidesPanelSearch ? this.panelTreeEl : this.panelSearchEl;
2321
+ if (this.isOpen && this.usesPanelSearch && panelFocusEl && panelFocusEl !== this.panelFocusEl) {
2322
+ this.focusPanel(panelFocusEl);
2323
+ }
2324
+ }
2325
+ focusPanel(el) {
2326
+ var _a, _b;
2327
+ this.panelFocusEl = el;
2328
+ // Before the dropdown is positioned it sits in the page's flow; don't scroll to it.
2329
+ el.focus({ preventScroll: true });
2330
+ // A search started by typing in the list carries its first character; type on after it.
2331
+ if (el === this.panelSearchEl && this.panelQuery !== '') {
2332
+ (_b = (_a = this.panelSearchEl).setSelectionRange) === null || _b === void 0 ? void 0 : _b.call(_a, this.panelQuery.length, this.panelQuery.length);
2333
+ }
2334
+ this.updateAriaActiveDescendant();
2335
+ }
2336
+ /** Switching display mode leaves no flyout or hover timer from the last one. */
2337
+ groupDisplayChanged() {
2338
+ this.flyout.reset();
2339
+ this.openGroup = null;
2340
+ // The reset isn't a drill-out, so it doesn't slide either.
2341
+ this.drillDirection = null;
2342
+ }
2343
+ openGroupChanged(next, previous) {
2344
+ this.handPanelFocusToList();
2345
+ // Only moves between the drill-in panel's views slide; search results don't.
2346
+ if (!this.isOpen || this.effectiveGroupDisplay !== 'drill-in' || !this.showsGroupedPanel)
2347
+ return;
2348
+ if (next !== null && previous === null)
2349
+ this.drillDirection = 'in';
2350
+ else if (next === null && previous !== null)
2351
+ this.drillDirection = 'out';
2352
+ }
2353
+ /** A flyout with no room beside the dropdown drills in, which can hide the focused search field too. */
2354
+ flyoutFallbackChanged() {
2355
+ this.handPanelFocusToList();
2356
+ }
2357
+ /**
2358
+ * Drilling into a group hides the search field, so focus moves to the list before the field
2359
+ * unmounts: focus lost with it would leave the combobox and close the dropdown.
2360
+ */
2361
+ handPanelFocusToList() {
2362
+ if (this.isOpen && this.hidesPanelSearch && this.panelTreeEl)
2363
+ this.focusPanel(this.panelTreeEl);
1862
2364
  }
1863
2365
  isOpenChanged(isOpen) {
2366
+ if (!isOpen) {
2367
+ this.drillDirection = null;
2368
+ this.openGroup = null;
2369
+ this.highlightedGroup = null;
2370
+ this.keyboardNavigating = false;
2371
+ this.flyout.reset();
2372
+ if (this.panelQuery !== '') {
2373
+ // The field reopens empty, so tell consumers who filter `options` from this event.
2374
+ this.panelQuery = '';
2375
+ this.pdsComboboxSearch.emit({ query: '' });
2376
+ }
2377
+ // And with `async-url`, start loading the unsearched list now, so it's ready by the reopen.
2378
+ if (this.usesPanelSearch && this.asyncUrl && this.lastFetchedQuery !== '') {
2379
+ this.debouncedFetchAsyncOptions('', 1);
2380
+ }
2381
+ this.panelFocusEl = undefined;
2382
+ this.flyoutRoomChecked = false;
2383
+ this.flyoutFallback = false;
2384
+ }
1864
2385
  if (isOpen && this.deferredPortalTeardownId !== undefined) {
1865
2386
  clearTimeout(this.deferredPortalTeardownId);
1866
2387
  this.deferredPortalTeardownId = undefined;
@@ -1893,17 +2414,52 @@ const PdsCombobox = class {
1893
2414
  get usesBodyPortal() {
1894
2415
  return this.dropdownMount === 'body';
1895
2416
  }
2417
+ get labelId() {
2418
+ return `${this.componentId}-label`;
2419
+ }
2420
+ /** One check for "the `<label>` is rendered", so the label and the reference to it can't disagree. */
2421
+ get hasVisibleLabel() {
2422
+ return Boolean(this.label) && !this.hideLabel;
2423
+ }
2424
+ /**
2425
+ * The button and chip triggers are `div`s, which `<label for>` can't name, so they point at the
2426
+ * visible label instead. With `hide-label` there is no visible label and `aria-label` names them.
2427
+ * With panel search the trigger is a button, which has no value, so its own text (the selection
2428
+ * or placeholder) joins the label in its name.
2429
+ */
2430
+ get triggerLabelledBy() {
2431
+ if (!this.hasVisibleLabel)
2432
+ return undefined;
2433
+ return this.usesPanelSearch ? `${this.labelId} ${this.componentId}` : this.labelId;
2434
+ }
2435
+ /** The div triggers' `aria-label` when the label is hidden; with panel search it names the selection too. */
2436
+ get triggerAriaLabel() {
2437
+ if (!this.hideLabel)
2438
+ return undefined;
2439
+ const shown = this.selectedLabel || this.placeholder;
2440
+ return this.usesPanelSearch && shown ? `${this.label}, ${shown}` : this.label;
2441
+ }
1896
2442
  get listboxId() {
1897
2443
  return `${this.componentId}-listbox`;
1898
2444
  }
1899
2445
  optionDomId(optionIndex) {
1900
2446
  return `${this.componentId}-option-${optionIndex}`;
1901
2447
  }
2448
+ groupDomId(optgroup) {
2449
+ let id = this.groupIds.get(optgroup);
2450
+ if (id === undefined) {
2451
+ id = `${this.componentId}-group-${this.groupIdCount++}`;
2452
+ this.groupIds.set(optgroup, id);
2453
+ }
2454
+ return id;
2455
+ }
1902
2456
  setupDebounce() {
1903
2457
  const { pdsComboboxSearch, debounce, originalSearchEmitter } = this;
1904
2458
  this.pdsComboboxSearch = debounce === undefined
1905
2459
  ? originalSearchEmitter !== null && originalSearchEmitter !== void 0 ? originalSearchEmitter : pdsComboboxSearch
1906
2460
  : debounceEvent(pdsComboboxSearch, debounce);
2461
+ // After the swap, so an emit made while flushing goes to the new emitter, not the old one.
2462
+ flushDebouncedEvent(pdsComboboxSearch);
1907
2463
  }
1908
2464
  optionsChanged() {
1909
2465
  if (this.options) {
@@ -2050,6 +2606,8 @@ const PdsCombobox = class {
2050
2606
  });
2051
2607
  if (page === 1) {
2052
2608
  this.internalOptions = formattedResults;
2609
+ // Only once its results have loaded: a failed or aborted fetch leaves the last query's.
2610
+ this.lastFetchedQuery = query;
2053
2611
  }
2054
2612
  else {
2055
2613
  this.internalOptions = [...this.internalOptions, ...formattedResults];
@@ -2074,26 +2632,76 @@ const PdsCombobox = class {
2074
2632
  }
2075
2633
  }
2076
2634
  updateOptionsFromAsync() {
2635
+ var _a;
2077
2636
  if (!this.asyncUrl && !this.options)
2078
2637
  return;
2079
2638
  // Clear existing slot-based options when using async
2080
2639
  this.optionEls = [];
2081
2640
  this.allItems = [];
2082
- // Create option elements from async data
2641
+ // Create option elements from async data. Grouped options are nested in an optgroup, as
2642
+ // slotted markup would be, so grouping, filtering and labels work the same either way. Each
2643
+ // group is listed where it first appears with all of its options, even when the data
2644
+ // interleaves groups, so an option never renders under another group's label. Ungrouped
2645
+ // options come first, so none reads as part of the group above it.
2083
2646
  const asyncOptions = this.options || this.internalOptions;
2647
+ const groups = new Map();
2648
+ const ungrouped = [];
2649
+ const groupEntries = [];
2084
2650
  asyncOptions.forEach(opt => {
2085
2651
  const optionEl = document.createElement('option');
2086
2652
  optionEl.value = String(opt.id);
2087
2653
  optionEl.textContent = opt.text;
2088
- this.optionEls.push(optionEl);
2089
- this.allItems.push(optionEl);
2654
+ if (opt.disabled === true)
2655
+ optionEl.setAttribute('disabled', '');
2656
+ // Only strings group an option or name an icon; anything else from JS is ignored, not coerced.
2657
+ if (typeof opt.group !== 'string' || opt.group === '') {
2658
+ ungrouped.push(optionEl);
2659
+ return;
2660
+ }
2661
+ let optgroup = groups.get(opt.group);
2662
+ if (!optgroup) {
2663
+ optgroup = document.createElement('optgroup');
2664
+ optgroup.label = opt.group;
2665
+ groups.set(opt.group, optgroup);
2666
+ groupEntries.push(optgroup);
2667
+ }
2668
+ if (!optgroup.hasAttribute('data-icon') && typeof opt.groupIcon === 'string' && opt.groupIcon !== '') {
2669
+ optgroup.setAttribute('data-icon', opt.groupIcon);
2670
+ }
2671
+ optgroup.appendChild(optionEl);
2672
+ });
2673
+ [...ungrouped, ...groupEntries].forEach(entry => {
2674
+ if (entry.tagName === 'OPTGROUP') {
2675
+ this.allItems.push(entry);
2676
+ Array.from(entry.children).forEach(child => {
2677
+ this.optionEls.push(child);
2678
+ this.allItems.push(child);
2679
+ });
2680
+ }
2681
+ else {
2682
+ this.optionEls.push(entry);
2683
+ this.allItems.push(entry);
2684
+ }
2090
2685
  });
2091
- // Re-apply preselection if a value is set but no option has been selected yet.
2092
- // This handles the case where `value` is set before async options have loaded.
2093
- if (this.value && !this.selectedOption) {
2686
+ // A rebuild replaces every optgroup. Follow the open group to its new element by label, so the
2687
+ // flyout stays open across reloads and pagination, or close it if the group is gone. The hover
2688
+ // timers still hold the old element, so they're cleared either way. filterOptions, below,
2689
+ // resets the highlight.
2690
+ if (this.openGroup !== null && !groupEntries.includes(this.openGroup)) {
2691
+ this.flyout.reset();
2692
+ this.openGroup = (_a = groups.get(this.openGroup.label)) !== null && _a !== void 0 ? _a : null;
2693
+ }
2694
+ // Re-apply the selection to the rebuilt options: when `value` is set before async options have
2695
+ // loaded, and after any rebuild, which detaches the previously selected option element.
2696
+ if (this.value && (!this.selectedOption || !this.optionEls.includes(this.selectedOption))) {
2094
2697
  const matchingOption = this.optionEls.find(opt => opt.value === this.value);
2095
2698
  if (matchingOption) {
2699
+ // Relinking a selection keeps the same value, so it keeps any text being typed too, which
2700
+ // the selectedOption watcher would otherwise reset to the label.
2701
+ const typed = this.selectedOption ? this.displayText : undefined;
2096
2702
  this.setSelectedOption(matchingOption);
2703
+ if (typed !== undefined)
2704
+ this.displayText = typed;
2097
2705
  }
2098
2706
  }
2099
2707
  this.filterOptions();
@@ -2144,11 +2752,12 @@ const PdsCombobox = class {
2144
2752
  }
2145
2753
  }
2146
2754
  // For chip triggers, ensure we always have a selected option
2147
- if (!initialSelected && this.trigger === 'chip' && this.optionEls.length > 0) {
2148
- initialSelected = this.optionEls[0]; // Select first option as default
2755
+ const firstEnabled = this.optionEls.find(opt => !isOptionDisabled(opt));
2756
+ if (initialSelected === null && this.trigger === 'chip' && firstEnabled !== undefined) {
2757
+ initialSelected = firstEnabled;
2149
2758
  this.value = initialSelected.value;
2150
2759
  this.displayText = this.getOptionLabel(initialSelected);
2151
- console.warn('PDS Combobox: Chip triggers should always have a selected option. Automatically selected the first option.');
2760
+ console.warn('PDS Combobox: Chip triggers should always have a selected option. Automatically selected the first enabled option.');
2152
2761
  }
2153
2762
  // Update selection if we found a different selected option or if we don't have one
2154
2763
  if (initialSelected && initialSelected !== this.selectedOption) {
@@ -2236,16 +2845,26 @@ const PdsCombobox = class {
2236
2845
  }
2237
2846
  }
2238
2847
  filterOptions() {
2848
+ // A new list replaces the rows a slide was animating, so its end event may never come.
2849
+ this.drillDirection = null;
2239
2850
  // Ensure allItems includes optionEls if not already populated (for edge cases)
2240
2851
  if (this.allItems.length === 0 && this.optionEls.length > 0) {
2241
2852
  this.allItems = [...this.optionEls];
2242
2853
  }
2243
- if (this.mode === 'select-only' || this.expandFilterListWhileOpen) {
2854
+ const searchesPanel = this.usesPanelSearch;
2855
+ if ((this.mode === 'select-only' && !searchesPanel) || this.expandFilterListWhileOpen || (searchesPanel && this.panelQuery === '')) {
2244
2856
  this.filteredItems = [...this.allItems];
2245
2857
  }
2246
2858
  else {
2247
- const val = this.displayText.toLowerCase();
2859
+ const val = (searchesPanel ? this.panelQuery : this.displayText).toLowerCase();
2248
2860
  const filteredOptions = this.optionEls.filter(option => {
2861
+ // Outside inline mode a group's label is part of what search matches, so "tag" finds
2862
+ // every option in the Tag group.
2863
+ if (this.groupDisplay !== 'inline') {
2864
+ const groupLabel = groupLabelOf(option);
2865
+ if (groupLabel !== null && groupLabel.toLowerCase().includes(val))
2866
+ return true;
2867
+ }
2249
2868
  // For layout options, search both text content and data-search-text attribute
2250
2869
  if (this.isOptionLayout(option)) {
2251
2870
  const searchText = option.getAttribute('data-search-text') || option.textContent || '';
@@ -2280,6 +2899,7 @@ const PdsCombobox = class {
2280
2899
  });
2281
2900
  }
2282
2901
  this.highlightedIndex = -1;
2902
+ this.highlightedGroup = null;
2283
2903
  }
2284
2904
  clearExpandFilterList() {
2285
2905
  this.expandFilterListWhileOpen = false;
@@ -2309,7 +2929,8 @@ const PdsCombobox = class {
2309
2929
  this.listboxEl.style.width = this.dropdownWidth;
2310
2930
  if (this.maxHeight) {
2311
2931
  this.listboxEl.style.maxHeight = this.maxHeight;
2312
- this.listboxEl.style.overflowY = 'auto';
2932
+ // With panel search, the options list scrolls under a fixed search field.
2933
+ this.listboxEl.style.overflowY = this.usesPanelSearch ? 'hidden' : 'auto';
2313
2934
  }
2314
2935
  return computePosition(this.triggerEl, this.listboxEl, {
2315
2936
  placement: this.dropdownPlacement,
@@ -2325,8 +2946,30 @@ const PdsCombobox = class {
2325
2946
  position: strategy,
2326
2947
  zIndex,
2327
2948
  });
2949
+ this.checkFlyoutRoom();
2328
2950
  });
2329
2951
  }
2952
+ /**
2953
+ * Once per open, after the dropdown is placed: with no room for a flyout on either side of it,
2954
+ * `flyout` drills in instead. `flyout-min-width` is resolved through CSS, so any length works.
2955
+ */
2956
+ checkFlyoutRoom() {
2957
+ if (!this.isOpen || this.groupDisplay !== 'flyout' || this.flyoutRoomChecked || !this.listboxEl)
2958
+ return;
2959
+ this.flyoutRoomChecked = true;
2960
+ const probe = document.createElement('div');
2961
+ // Fixed, like the flyout, so a percentage resolves against the viewport as the flyout's does.
2962
+ probe.style.cssText = 'position:fixed;visibility:hidden;width:0;';
2963
+ probe.style.minWidth = this.flyoutMinWidth;
2964
+ this.listboxEl.appendChild(probe);
2965
+ const needed = parseFloat(getComputedStyle(probe).minWidth);
2966
+ probe.remove();
2967
+ const rect = this.listboxEl.getBoundingClientRect();
2968
+ const room = Math.max(window.innerWidth - rect.right, rect.left);
2969
+ const fallback = Number.isFinite(needed) && needed > 0 && rect.width > 0 && room < needed;
2970
+ if (fallback !== this.flyoutFallback)
2971
+ this.flyoutFallback = fallback;
2972
+ }
2330
2973
  openDropdownPositioning() {
2331
2974
  if (!this.triggerEl || !this.listboxEl) {
2332
2975
  return;
@@ -2429,6 +3072,130 @@ const PdsCombobox = class {
2429
3072
  this.listboxEl = undefined;
2430
3073
  }
2431
3074
  }
3075
+ /**
3076
+ * The tree keys in the grouped panel. Up, Down, Home, End, PageUp and PageDown move within one
3077
+ * level; Right, Enter or Space opens a group at its first option; Left, or Escape, closes the
3078
+ * open group back to its row. Returns false for keys the listbox handling covers, such as
3079
+ * Enter on an option.
3080
+ */
3081
+ handleGroupedPanelKey(e) {
3082
+ if (!this.showsGroupedPanel)
3083
+ return false;
3084
+ this.keyboardNavigating = true;
3085
+ // In the input trigger, Left and Right still move the caret through typed text, and Space,
3086
+ // Home and End edit it, as they do in the panel's search field.
3087
+ if (this.trigger === 'input') {
3088
+ if ((e.key === 'ArrowLeft' || e.key === 'ArrowRight') && this.displayText !== '')
3089
+ return false;
3090
+ if (e.key === ' ' || e.key === 'Home' || e.key === 'End')
3091
+ return false;
3092
+ }
3093
+ const entries = buildPanelEntries(this.filteredItems);
3094
+ const drilledIn = this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null;
3095
+ const current = this.currentPanelItem();
3096
+ const column = panelColumn(entries, this.openGroup, current, drilledIn);
3097
+ if (column.length === 0)
3098
+ return false;
3099
+ const position = current === null ? -1 : column.indexOf(current);
3100
+ const moveTo = (to) => {
3101
+ e.preventDefault();
3102
+ this.highlightPanelItem(column[Math.max(0, Math.min(column.length - 1, to))]);
3103
+ return true;
3104
+ };
3105
+ switch (e.key) {
3106
+ case 'ArrowDown':
3107
+ return moveTo(position < 0 ? 0 : position + 1);
3108
+ case 'ArrowUp':
3109
+ return moveTo(position < 0 ? column.length - 1 : position - 1);
3110
+ case 'Home':
3111
+ return moveTo(0);
3112
+ case 'End':
3113
+ return moveTo(column.length - 1);
3114
+ case 'PageDown':
3115
+ return moveTo(position < 0 ? 0 : position + 10);
3116
+ case 'PageUp':
3117
+ return moveTo(position < 0 ? column.length - 1 : position - 10);
3118
+ case 'ArrowRight':
3119
+ case 'Enter':
3120
+ case ' ': {
3121
+ if (current === null || typeof current === 'number')
3122
+ return false;
3123
+ e.preventDefault();
3124
+ if (!drilledIn || current !== this.openGroup) {
3125
+ this.expandGroup(entries, current);
3126
+ }
3127
+ else if (e.key === 'ArrowRight') {
3128
+ // On the row back of a drilled-in group: down into its options.
3129
+ if (column.length > 1)
3130
+ this.highlightPanelItem(column[1]);
3131
+ }
3132
+ else {
3133
+ this.leaveDrilledInGroup();
3134
+ }
3135
+ return true;
3136
+ }
3137
+ case 'ArrowLeft':
3138
+ case 'Escape': {
3139
+ // Escape with no group open closes the panel, through the listbox handling.
3140
+ if (this.openGroup === null)
3141
+ return false;
3142
+ e.preventDefault();
3143
+ this.collapseToGroup(this.openGroup);
3144
+ return true;
3145
+ }
3146
+ }
3147
+ return false;
3148
+ }
3149
+ /**
3150
+ * Where the keyboard is in the grouped panel. An option highlighted in a group that has since
3151
+ * closed (the pointer left its flyout) counts as its group's row, so the keys carry on from
3152
+ * what's showing rather than from an option that isn't.
3153
+ */
3154
+ currentPanelItem() {
3155
+ if (this.highlightedIndex < 0)
3156
+ return this.highlightedGroup;
3157
+ const selectable = this.filteredItems.filter(item => item.tagName === 'OPTION');
3158
+ const group = parentOptgroupOf(selectable[this.highlightedIndex]);
3159
+ return group !== null && group !== this.openGroup ? group : this.highlightedIndex;
3160
+ }
3161
+ /**
3162
+ * Highlights the option at `index`, kept within the list. Disabled options can be highlighted,
3163
+ * so assistive tech announces them as unavailable, but not chosen.
3164
+ */
3165
+ highlightOptionAt(options, index) {
3166
+ if (options.length === 0)
3167
+ return;
3168
+ this.highlightedIndex = Math.max(0, Math.min(options.length - 1, index));
3169
+ this.updateOptionFocus();
3170
+ }
3171
+ /** Highlights a group row or an option, opening or closing flyouts to match. */
3172
+ highlightPanelItem(item) {
3173
+ if (typeof item === 'number') {
3174
+ this.highlightedIndex = item;
3175
+ }
3176
+ else {
3177
+ this.highlightedIndex = -1;
3178
+ this.highlightedGroup = item;
3179
+ }
3180
+ this.updateOptionFocus();
3181
+ }
3182
+ expandGroup(entries, optgroup) {
3183
+ var _a;
3184
+ this.flyout.open(optgroup);
3185
+ const first = (_a = findGroup(entries, optgroup)) === null || _a === void 0 ? void 0 : _a.options[0];
3186
+ if (first !== undefined)
3187
+ this.highlightPanelItem(first.index);
3188
+ // Its options render after this change; scroll to the first one then.
3189
+ this.pendingOptionFocus = true;
3190
+ }
3191
+ /** Closes the open group and highlights its row, as a tree's Left does from a child. */
3192
+ collapseToGroup(optgroup) {
3193
+ this.flyout.reset();
3194
+ this.openGroup = null;
3195
+ this.highlightPanelItem(optgroup);
3196
+ // The row renders after this change (in drill-in it replaces the row back); scroll to it then.
3197
+ this.pendingOptionFocus = true;
3198
+ }
2432
3199
  /**
2433
3200
  * Sets focus on the native input element.
2434
3201
  */
@@ -2442,8 +3209,9 @@ const PdsCombobox = class {
2442
3209
  }
2443
3210
  }
2444
3211
  /**
2445
- * Sets the initial highlighted index when dropdown opens.
2446
- * If there's a selected option, highlight it. Otherwise, highlight the first option.
3212
+ * Sets the initial highlighted index when dropdown opens. Highlights the selected option unless
3213
+ * it's disabled. Otherwise highlights the first enabled option, or, in the grouped panel, the
3214
+ * first row with something to choose, or nothing when every option is disabled.
2447
3215
  */
2448
3216
  setInitialHighlightedIndex() {
2449
3217
  const selectableOptions = this.filteredItems.filter(item => item.tagName === 'OPTION');
@@ -2451,16 +3219,33 @@ const PdsCombobox = class {
2451
3219
  this.highlightedIndex = -1;
2452
3220
  return;
2453
3221
  }
2454
- // If there's a selected option, find its index in the filtered options
2455
- if (this.selectedOption) {
3222
+ // If there's a selected option, find its index in the filtered options. A disabled one can be
3223
+ // the value, as in a native select, but it isn't highlighted.
3224
+ if (this.selectedOption && !isOptionDisabled(this.selectedOption)) {
2456
3225
  const selectedIndex = selectableOptions.findIndex(option => option === this.selectedOption);
2457
3226
  if (selectedIndex >= 0) {
2458
3227
  this.highlightedIndex = selectedIndex;
3228
+ // In the grouped panel, open on the selection's group, however the dropdown was opened, and
3229
+ // scroll the selection into view once its group has rendered.
3230
+ if (this.showsGroupedPanel) {
3231
+ this.openGroup = parentOptgroupOf(this.selectedOption);
3232
+ // Opening on the selection isn't drilling in, so it doesn't slide.
3233
+ this.drillDirection = null;
3234
+ this.pendingOptionFocus = true;
3235
+ }
2459
3236
  return;
2460
3237
  }
2461
3238
  }
2462
- // No selected option or selected option not in filtered results, highlight first option
2463
- this.highlightedIndex = 0;
3239
+ // In the grouped panel, the first row with something to choose: a group stays closed until
3240
+ // it's opened.
3241
+ if (this.showsGroupedPanel) {
3242
+ const first = buildPanelEntries(this.filteredItems).find(entry => entry.kind === 'group' ? !isGroupDisabled(entry.group) : !isOptionDisabled(entry.option));
3243
+ this.highlightedIndex = (first === null || first === void 0 ? void 0 : first.kind) === 'option' ? first.index : -1;
3244
+ this.highlightedGroup = (first === null || first === void 0 ? void 0 : first.kind) === 'group' ? first.group.optgroup : null;
3245
+ return;
3246
+ }
3247
+ // No selected option or selected option not in filtered results, highlight the first enabled option
3248
+ this.highlightedIndex = selectableOptions.findIndex(option => !isOptionDisabled(option));
2464
3249
  }
2465
3250
  /**
2466
3251
  * Focus management helper - moves focus to the first option when dropdown opens
@@ -2496,19 +3281,9 @@ const PdsCombobox = class {
2496
3281
  const selectableOptions = this.filteredItems.filter(item => item.tagName === 'OPTION');
2497
3282
  if (selectableOptions.length > 0) {
2498
3283
  this.setInitialHighlightedIndex();
2499
- if (this.listboxEl) {
2500
- const optionElements = this.listboxEl.querySelectorAll('[role="option"]');
2501
- const highlightedOption = optionElements[this.highlightedIndex];
2502
- if (highlightedOption) {
2503
- optionElements.forEach(option => {
2504
- option.setAttribute('tabindex', '-1');
2505
- });
2506
- highlightedOption.setAttribute('tabindex', '0');
2507
- highlightedOption.focus();
2508
- highlightedOption.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
2509
- }
2510
- }
2511
- this.updateAriaActiveDescendant();
3284
+ // By index, through the same path as arrowing: it opens the option's flyout group first
3285
+ // when it isn't rendered, and highlights it once it is.
3286
+ this.updateOptionFocus();
2512
3287
  }
2513
3288
  }
2514
3289
  /**
@@ -2516,14 +3291,58 @@ const PdsCombobox = class {
2516
3291
  * Note: We don't actually focus the option to prevent focusout events that close the dropdown
2517
3292
  */
2518
3293
  updateOptionFocus() {
2519
- if (!this.listboxEl || this.highlightedIndex < 0)
3294
+ var _a;
3295
+ if (this.listboxEl === undefined || this.listboxEl === null)
3296
+ return;
3297
+ // A row highlighted outright; an option highlighted in a closed group opens it below instead.
3298
+ const groupRow = this.showsGroupedPanel && this.highlightedIndex < 0 ? this.highlightedGroup : null;
3299
+ if (groupRow !== null) {
3300
+ // Arrowing onto another row closes a flyout that hover left open.
3301
+ if (this.effectiveGroupDisplay === 'flyout' && this.openGroup !== null && this.openGroup !== groupRow) {
3302
+ this.flyout.reset();
3303
+ this.openGroup = null;
3304
+ }
3305
+ // Matched by id, not a selector: componentId is consumer text and may not be selector-safe.
3306
+ const id = this.groupDomId(groupRow);
3307
+ (_a = Array.from(this.listboxEl.querySelectorAll('[role="treeitem"]'))
3308
+ .find(row => row.id === id)) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'nearest' });
3309
+ this.updateAriaActiveDescendant();
2520
3310
  return;
3311
+ }
3312
+ if (this.highlightedIndex < 0)
3313
+ return;
3314
+ // In the flyout panel only the open group's options are rendered: open the highlighted
3315
+ // option's group, and finish once it has rendered. Through the controller, so a hover timer
3316
+ // left running by the pointer can't close or switch the group the keys just moved into.
3317
+ if (this.showsGroupedPanel) {
3318
+ const selectable = this.filteredItems.filter(item => item.tagName === 'OPTION');
3319
+ const group = parentOptgroupOf(selectable[this.highlightedIndex]);
3320
+ const changed = group !== this.openGroup;
3321
+ if (group !== null) {
3322
+ this.flyout.open(group);
3323
+ }
3324
+ else {
3325
+ this.flyout.reset();
3326
+ this.openGroup = null;
3327
+ }
3328
+ if (changed) {
3329
+ this.pendingOptionFocus = true;
3330
+ return;
3331
+ }
3332
+ }
2521
3333
  const optionElements = this.listboxEl.querySelectorAll('[role="option"]');
2522
- const currentOption = optionElements[this.highlightedIndex];
3334
+ // By index, not position: the flyout panel renders only some options.
3335
+ const currentOption = this.listboxEl.querySelector(`[data-option-index="${this.highlightedIndex}"]`);
2523
3336
  if (currentOption) {
2524
3337
  // Check if any option currently has focus OR if we're in arrow-key navigation mode
2525
3338
  const hasOptionFocus = Array.from(optionElements).some(el => el === document.activeElement);
2526
- const shouldFocusOption = !this.usesBodyPortal && (hasOptionFocus || this.isArrowKeyNavigationMode);
3339
+ // The panel's search field keeps focus and points at the option with aria-activedescendant,
3340
+ // and so does the trigger over the grouped panel, whose group rows can't take focus and
3341
+ // whose options are hidden while a flyout is placed.
3342
+ const shouldFocusOption = !this.usesBodyPortal &&
3343
+ !this.usesPanelSearch &&
3344
+ !this.showsGroupedPanel &&
3345
+ (hasOptionFocus || this.isArrowKeyNavigationMode);
2527
3346
  if (shouldFocusOption) {
2528
3347
  optionElements.forEach(option => {
2529
3348
  option.setAttribute('tabindex', '-1');
@@ -2531,21 +3350,64 @@ const PdsCombobox = class {
2531
3350
  currentOption.setAttribute('tabindex', '0');
2532
3351
  currentOption.focus();
2533
3352
  }
2534
- // Always scroll the option into view
2535
- currentOption.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
3353
+ // Always scroll the option into view; in a flyout, by scrolling the flyout alone.
3354
+ const flyout = currentOption.closest('.pds-combobox__flyout');
3355
+ if (flyout) {
3356
+ this.flyout.reveal(flyout, currentOption);
3357
+ }
3358
+ else {
3359
+ currentOption.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
3360
+ }
2536
3361
  }
2537
3362
  // Always update aria-activedescendant on the trigger element
2538
3363
  this.updateAriaActiveDescendant();
2539
3364
  }
3365
+ /** The highlighted group row in the grouped panel, or null while an option is highlighted. */
3366
+ get highlightedGroupRow() {
3367
+ if (!this.showsGroupedPanel)
3368
+ return null;
3369
+ if (this.highlightedIndex < 0)
3370
+ return this.highlightedGroup;
3371
+ // An option left highlighted in a flyout that has since closed shows as its group's row.
3372
+ const current = this.currentPanelItem();
3373
+ return typeof current === 'number' ? null : current;
3374
+ }
2540
3375
  /**
2541
- * Updates aria-activedescendant on the trigger element
3376
+ * The id of the highlighted option or group row, only while it's rendered. In the flyout panel
3377
+ * an option in a closed group isn't in the DOM, and drilled into a group the other groups' rows
3378
+ * aren't; `aria-activedescendant` must not point at a missing element.
2542
3379
  */
3380
+ get activeDescendantId() {
3381
+ if (!this.isOpen)
3382
+ return undefined;
3383
+ const groupRow = this.highlightedGroupRow;
3384
+ if (groupRow !== null) {
3385
+ const drilledIntoAnother = this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null && this.openGroup !== groupRow;
3386
+ return drilledIntoAnother ? undefined : this.groupDomId(groupRow);
3387
+ }
3388
+ if (this.highlightedIndex < 0)
3389
+ return undefined;
3390
+ if (this.showsGroupedPanel) {
3391
+ const selectable = this.filteredItems.filter(item => item.tagName === 'OPTION');
3392
+ const group = parentOptgroupOf(selectable[this.highlightedIndex]);
3393
+ if (group !== null && group !== this.openGroup)
3394
+ return undefined;
3395
+ }
3396
+ return this.optionDomId(this.highlightedIndex);
3397
+ }
3398
+ /** Points the focused element's aria-activedescendant at the highlighted option, or clears it. */
2543
3399
  updateAriaActiveDescendant() {
2544
- if (this.triggerEl && this.highlightedIndex >= 0) {
2545
- this.triggerEl.setAttribute('aria-activedescendant', this.optionDomId(this.highlightedIndex));
3400
+ // With panel search, the element with focus owns it, not the trigger: the search field, or
3401
+ // the list while a drilled-in group hides the field.
3402
+ const target = this.usesPanelSearch ? (this.hidesPanelSearch ? this.panelTreeEl : this.panelSearchEl) : this.triggerEl;
3403
+ if (!target)
3404
+ return;
3405
+ const id = this.activeDescendantId;
3406
+ if (id !== undefined) {
3407
+ target.setAttribute('aria-activedescendant', id);
2546
3408
  }
2547
- else if (this.triggerEl) {
2548
- this.triggerEl.removeAttribute('aria-activedescendant');
3409
+ else {
3410
+ target.removeAttribute('aria-activedescendant');
2549
3411
  }
2550
3412
  }
2551
3413
  /**
@@ -2581,6 +3443,17 @@ const PdsCombobox = class {
2581
3443
  this.pdsComboboxChange.emit({ value: '' });
2582
3444
  }
2583
3445
  }
3446
+ // Group rows in the flyout panel carry their group's index, as options carry theirs.
3447
+ groupFromEvent(event) {
3448
+ var _a, _b;
3449
+ const index = Number(event.currentTarget.getAttribute('data-group-index'));
3450
+ return (_b = (_a = this.renderedGroups[index]) === null || _a === void 0 ? void 0 : _a.optgroup) !== null && _b !== void 0 ? _b : null;
3451
+ }
3452
+ highlightGroupRowByPointer(group) {
3453
+ this.highlightedIndex = -1;
3454
+ this.highlightedGroup = group;
3455
+ this.keyboardNavigating = false;
3456
+ }
2584
3457
  // Get the label of the selected option
2585
3458
  get selectedLabel() {
2586
3459
  return this.displayText || '';
@@ -2693,7 +3566,24 @@ const PdsCombobox = class {
2693
3566
  // Fallback: Use component props
2694
3567
  return this.chipDot;
2695
3568
  }
3569
+ /**
3570
+ * With `async-url`, fetches when the button trigger opens: the first page if nothing has loaded.
3571
+ * The panel's search field opens empty, so results left from the last search are refetched for
3572
+ * an empty query.
3573
+ */
3574
+ fetchAsyncOptionsOnOpen() {
3575
+ if (!this.asyncUrl)
3576
+ return;
3577
+ if (this.usesPanelSearch && (this.internalOptions.length === 0 || this.lastFetchedQuery !== '')) {
3578
+ this.debouncedFetchAsyncOptions('', 1);
3579
+ }
3580
+ else if (this.internalOptions.length === 0) {
3581
+ this.debouncedFetchAsyncOptions(this.displayText, 1);
3582
+ }
3583
+ }
2696
3584
  handleOptionClick(option) {
3585
+ if (isOptionDisabled(option))
3586
+ return;
2697
3587
  // Update reactive state - single source of truth
2698
3588
  // The @Watch('selectedOption') will handle displayText, value, and form internals
2699
3589
  this.setSelectedOption(option);
@@ -2707,33 +3597,242 @@ const PdsCombobox = class {
2707
3597
  }
2708
3598
  const hasSlottedEmpty = !this.usesBodyPortal && !!this.el.querySelector('[slot="empty"]');
2709
3599
  const hasSlottedLoading = !this.usesBodyPortal && !!this.el.querySelector('[slot="loading"]');
2710
- let optionIndex = 0;
2711
3600
  const selectableOptions = this.filteredItems.filter(item => item.tagName === 'OPTION');
2712
- return (h("ul", { class: "pds-combobox__listbox", role: "listbox", id: this.listboxId, "aria-label": this.label || 'Options', "aria-multiselectable": "false", ref: el => (this.listboxEl = el), onScroll: this.handleScroll }, this.loading && (h("li", { class: "pds-combobox__loading", role: "presentation" }, hasSlottedLoading ? (h("slot", { name: "loading" })) : (h("pds-loader", { size: "small" })))), !this.loading && this.filteredItems.length === 0 && (h("li", { class: "pds-combobox__empty", role: "presentation" }, hasSlottedEmpty ? (h("slot", { name: "empty" })) : (h("span", null, "No options found")))), this.filteredItems.map((item, itemIdx) => {
3601
+ const withSearch = this.usesPanelSearch;
3602
+ // While a drilled-in group hides the search field, the list takes focus in its place.
3603
+ const listTakesFocus = this.hidesPanelSearch;
3604
+ const list = (h("ul", { key: "panel-list", class: {
3605
+ 'pds-combobox__listbox': !withSearch,
3606
+ 'pds-combobox__listbox-options': withSearch,
3607
+ 'pds-combobox__listbox-options--drilled-in': listTakesFocus,
3608
+ 'pds-combobox__listbox--grouped': this.groupDisplay !== 'inline',
3609
+ 'pds-combobox__listbox--drill-in': this.drillDirection === 'in',
3610
+ 'pds-combobox__listbox--drill-out': this.drillDirection === 'out',
3611
+ }, onAnimationEnd: this.onDrillAnimationEnd, role: this.showsGroupedPanel ? 'tree' : 'listbox', id: this.listboxId, "aria-label": this.label || 'Options', "aria-multiselectable": "false",
3612
+ // Focusable but out of the tab order with panel search, so it can take focus when a
3613
+ // drilled-in group hides the field. Dropping it while focused would blur the list and close.
3614
+ tabIndex: withSearch ? -1 : undefined, "aria-activedescendant": listTakesFocus ? this.activeDescendantId : undefined, onKeyDown: withSearch ? this.onPanelTreeKeyDown : undefined, ref: el => {
3615
+ if (withSearch)
3616
+ this.panelTreeEl = el;
3617
+ else
3618
+ this.listboxEl = el;
3619
+ }, onScroll: this.handleScroll }, this.loading && (h("li", { class: "pds-combobox__loading", role: "presentation" }, hasSlottedLoading ? (h("slot", { name: "loading" })) : (h("pds-loader", { size: "small" })))), !this.loading && this.filteredItems.length === 0 && (h("li", { class: "pds-combobox__empty", role: "presentation" }, hasSlottedEmpty ? (h("slot", { name: "empty" })) : (h("span", null, "No options found")))), this.showsGroupedPanel ? this.renderGroupedPanel() : this.renderListboxItems(selectableOptions.length), this.hasMore && !this.loading && (h("li", { class: "pds-combobox__load-more", role: "presentation" }, h("pds-loader", { size: "small" })))));
3620
+ if (!withSearch)
3621
+ return list;
3622
+ // The search field sits above the list; the wrapper is what's positioned and portaled.
3623
+ return (h("div", { class: "pds-combobox__listbox pds-combobox__listbox--with-search", ref: el => (this.listboxEl = el), onMouseDown: this.onPanelMouseDown,
3624
+ // Portaled, the panel sits outside .pds-combobox, so its focusout wouldn't reach that handler.
3625
+ onFocusout: this.usesBodyPortal ? this.onComboboxFocusOut : undefined }, !listTakesFocus && this.renderPanelSearch(), list));
3626
+ }
3627
+ /**
3628
+ * The listbox's items. Each optgroup's options sit in a `group` named for it, as in
3629
+ * `pds-multiselect`, so assistive tech announces the group on entering it; a `pds-text` label
3630
+ * stays a caption above the options that follow it.
3631
+ */
3632
+ renderListboxItems(setSize) {
3633
+ const rendered = [];
3634
+ let optionIndex = 0;
3635
+ let group = null;
3636
+ const closeGroup = () => {
3637
+ if (group === null)
3638
+ return;
3639
+ const { optgroup, key, options, members } = group;
3640
+ const groupIcon = groupIconOf(optgroup);
3641
+ // As in the grouped displays: disabled when there's nothing left in it to choose.
3642
+ const disabled = members.length > 0 && members.every(member => isOptionDisabled(member));
3643
+ rendered.push(h("li", { key: key, class: { 'pds-combobox__group': true, 'pds-combobox__group--disabled': disabled }, role: "group", "aria-label": optgroup.label, "aria-disabled": disabled ? 'true' : undefined }, h("div", { class: { 'pds-combobox__group-label': true, 'pds-combobox__group-label--with-icon': groupIcon !== null }, "aria-hidden": "true" }, groupIcon !== null && (
3644
+ // `name`, not `icon`: `icon` also loads URLs and data: SVGs, unsanitized.
3645
+ h("pds-icon", { name: groupIcon, size: "small", "aria-hidden": "true", class: "pds-combobox__group-icon" })), optgroup.label), h("ul", { class: "pds-combobox__group-list", role: "presentation" }, options)));
3646
+ group = null;
3647
+ };
3648
+ this.filteredItems.forEach((item, itemIdx) => {
2713
3649
  if (item.tagName === 'OPTGROUP') {
2714
- const optgroup = item;
2715
- return (h("li", { key: `optgroup-${itemIdx}`, class: "pds-combobox__group-label", role: "presentation", "aria-label": optgroup.label }, optgroup.label));
3650
+ closeGroup();
3651
+ group = { optgroup: item, key: `optgroup-${itemIdx}`, options: [], members: [] };
2716
3652
  }
2717
3653
  else if (item.tagName === 'PDS-TEXT') {
2718
- const pdsText = item;
2719
- return (h("li", { key: `pds-text-${itemIdx}`, class: "pds-combobox__group-label", role: "presentation" }, pdsText.textContent));
3654
+ closeGroup();
3655
+ rendered.push(h("li", { key: `pds-text-${itemIdx}`, class: "pds-combobox__group-label", role: "presentation" }, item.textContent));
2720
3656
  }
2721
3657
  else if (item.tagName === 'OPTION') {
2722
3658
  const option = item;
2723
- const isSelected = this.isOptionSelected(option);
2724
- const isHighlighted = this.highlightedIndex === optionIndex;
2725
- const isLayout = this.isOptionLayout(option);
2726
- const isChip = this.isOptionChip(option);
2727
- const currentOptionIndex = optionIndex++;
2728
- return (h("li", { key: option.value, id: this.optionDomId(currentOptionIndex), role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-setsize": selectableOptions.length, "aria-posinset": currentOptionIndex + 1, "aria-label": isLayout || isChip ? option.getAttribute('aria-label') || this.getOptionLabel(option) : undefined, tabindex: this.usesBodyPortal ? '-1' : isHighlighted ? '0' : '-1', class: {
2729
- 'pds-combobox__option': true,
2730
- 'pds-combobox__option--highlighted': isHighlighted,
2731
- 'pds-combobox__option--layout': isLayout,
2732
- 'pds-combobox__option--chip': isChip,
2733
- }, "data-option-index": currentOptionIndex, onMouseDown: this.onOptionMouseDown, onClick: this.onOptionClick, onMouseEnter: this.onOptionMouseEnter, onKeyDown: this.onOptionKeyDown }, isLayout ? (h("pds-box", { class: "pds-combobox__option-layout-wrapper", innerHTML: this.getOptionLayoutContent(option) })) : isChip ? (this.renderOptionChip(option)) : (this.getOptionLabel(option)), isSelected && h("pds-icon", { icon: "check", size: "regular", class: "pds-combobox__option-check" })));
3659
+ if (group !== null && parentOptgroupOf(option) !== group.optgroup)
3660
+ closeGroup();
3661
+ const rendering = this.renderOption(option, optionIndex, { posinset: optionIndex + 1, setsize: setSize });
3662
+ optionIndex++;
3663
+ if (group !== null) {
3664
+ group.options.push(rendering);
3665
+ group.members.push(option);
3666
+ }
3667
+ else {
3668
+ rendered.push(rendering);
3669
+ }
2734
3670
  }
2735
- return null;
2736
- }), this.hasMore && !this.loading && (h("li", { class: "pds-combobox__load-more", role: "presentation" }, h("pds-loader", { size: "small" })))));
3671
+ });
3672
+ closeGroup();
3673
+ return rendered;
3674
+ }
3675
+ /** `panelSearch` applies to the triggers that can't be typed into. */
3676
+ get usesPanelSearch() {
3677
+ return this.panelSearch && this.trigger !== 'input';
3678
+ }
3679
+ /** `groupDisplay`, with `flyout` drilling in when there's no room beside the dropdown. */
3680
+ get effectiveGroupDisplay() {
3681
+ return this.groupDisplay === 'flyout' && this.flyoutFallback ? 'drill-in' : this.groupDisplay;
3682
+ }
3683
+ /**
3684
+ * The popup's role, for the triggers' `aria-haspopup`: a `tree` while the grouped panel shows
3685
+ * groups, and a `listbox` of options otherwise, search results included.
3686
+ */
3687
+ get popupRole() {
3688
+ return this.showsGroupedPanel ? 'tree' : 'listbox';
3689
+ }
3690
+ /**
3691
+ * The input trigger's `aria-haspopup`. While closed it names what opening shows: the full list,
3692
+ * so the grouped panel in a grouped display, even though the input still holds the selection's
3693
+ * label.
3694
+ */
3695
+ get inputPopupRole() {
3696
+ if (this.isOpen)
3697
+ return this.popupRole;
3698
+ return this.effectiveGroupDisplay === 'inline' ? 'listbox' : 'tree';
3699
+ }
3700
+ /**
3701
+ * The button and chip triggers' `aria-haspopup`. With panel search the trigger opens the panel,
3702
+ * which starts as a tree in a grouped display, so typing in the panel doesn't change it.
3703
+ */
3704
+ get triggerPopupRole() {
3705
+ if (!this.usesPanelSearch)
3706
+ return this.popupRole;
3707
+ return this.groupDisplay === 'inline' ? 'listbox' : 'tree';
3708
+ }
3709
+ /**
3710
+ * Drilled into a group with panel search: the group's row back takes the search field's place,
3711
+ * since one group's options don't need searching. Typing searches the whole list again.
3712
+ */
3713
+ get hidesPanelSearch() {
3714
+ return this.usesPanelSearch && this.showsGroupedPanel && this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null;
3715
+ }
3716
+ /** The grouped panel is showing groups rather than search results. */
3717
+ get showsGroupedPanel() {
3718
+ if (this.effectiveGroupDisplay === 'inline')
3719
+ return false;
3720
+ const searching = this.usesPanelSearch
3721
+ ? this.panelQuery !== ''
3722
+ : this.mode === 'filter' && !this.expandFilterListWhileOpen && this.displayText !== '';
3723
+ return !searching;
3724
+ }
3725
+ setPanelQuery(query) {
3726
+ this.panelQuery = query;
3727
+ this.clearExpandFilterList();
3728
+ this.filterOptions();
3729
+ this.pdsComboboxSearch.emit({ query: this.panelQuery });
3730
+ if (this.asyncUrl !== undefined && this.asyncUrl !== '') {
3731
+ this.debouncedFetchAsyncOptions(this.panelQuery, 1);
3732
+ }
3733
+ // The list changes size, so place the dropdown again, as typing in the input trigger does.
3734
+ setTimeout(() => this.openDropdownPositioning(), 0);
3735
+ }
3736
+ /** What's being searched: the panel's field, or the input trigger's text. */
3737
+ get activeQuery() {
3738
+ return this.usesPanelSearch ? this.panelQuery : this.displayText;
3739
+ }
3740
+ // Tab closes the dropdown and lands on the trigger, as Escape does: the focused field or list is
3741
+ // about to unmount, so the browser can't tab on from it. The next Tab continues from the trigger.
3742
+ handlePanelTab(event) {
3743
+ if (event.key !== 'Tab')
3744
+ return false;
3745
+ event.preventDefault();
3746
+ this.handleKeyDown(event);
3747
+ this.restoreFocusToTrigger();
3748
+ return true;
3749
+ }
3750
+ /** Returns from a drilled-in group to the group list; false when not drilled in. */
3751
+ leaveDrilledInGroup() {
3752
+ if (!this.showsGroupedPanel || this.effectiveGroupDisplay !== 'drill-in' || this.openGroup === null)
3753
+ return false;
3754
+ this.collapseToGroup(this.openGroup);
3755
+ return true;
3756
+ }
3757
+ renderPanelSearch() {
3758
+ return (h("div", { key: "panel-search", class: "pds-combobox__panel-search" }, h("pds-icon", { name: "search", size: "small", "aria-hidden": "true" }), h("input", { ref: el => (this.panelSearchEl = el), type: "text", class: "pds-combobox__panel-search-input", placeholder: this.searchPlaceholder, value: this.panelQuery, role: "combobox", "aria-label": this.searchOptionsLabel, "aria-haspopup": this.popupRole, "aria-controls": this.listboxId, "aria-autocomplete": "list", "aria-expanded": "true", "aria-activedescendant": this.activeDescendantId, autocomplete: "off", onInput: this.onPanelSearchInput, onKeyDown: this.onPanelSearchKeyDown })));
3759
+ }
3760
+ /**
3761
+ * An option, as a listbox `option` or, given a tree `level`, a `treeitem`. `posinset` and
3762
+ * `setsize` place it among its siblings.
3763
+ */
3764
+ renderOption(option, index, { posinset, setsize, level }) {
3765
+ const isSelected = this.isOptionSelected(option);
3766
+ const isHighlighted = this.highlightedIndex === index;
3767
+ const isLayout = this.isOptionLayout(option);
3768
+ const isChip = this.isOptionChip(option);
3769
+ const isDisabled = isOptionDisabled(option);
3770
+ const tree = level !== undefined;
3771
+ return (h("li", { key: option.value, id: this.optionDomId(index), role: tree ? 'treeitem' : 'option', "aria-selected": isSelected ? 'true' : tree ? undefined : 'false', "aria-disabled": isDisabled ? 'true' : undefined, "aria-level": level, "aria-setsize": setsize, "aria-posinset": posinset, "aria-label": isLayout || isChip ? option.getAttribute('aria-label') || this.getOptionLabel(option) : undefined, tabindex: this.usesBodyPortal || this.usesPanelSearch || tree ? '-1' : isHighlighted ? '0' : '-1', class: {
3772
+ 'pds-combobox__option': true,
3773
+ 'pds-combobox__option--highlighted': isHighlighted,
3774
+ 'pds-combobox__option--layout': isLayout,
3775
+ 'pds-combobox__option--chip': isChip,
3776
+ 'pds-combobox__option--disabled': isDisabled,
3777
+ }, "data-option-index": index, onMouseDown: this.onOptionMouseDown, onClick: this.onOptionClick, onMouseEnter: this.onOptionMouseEnter, onKeyDown: this.onOptionKeyDown }, isLayout ? (h("pds-box", { class: "pds-combobox__option-layout-wrapper", innerHTML: this.getOptionLayoutContent(option) })) : isChip ? (this.renderOptionChip(option)) : (this.getOptionLabel(option)), isSelected && h("pds-icon", { icon: "check", size: "regular", class: "pds-combobox__option-check" })));
3778
+ }
3779
+ /**
3780
+ * `flyout`: one row per group, its options in a flyout beside it. `drill-in`: the same rows, and
3781
+ * an opened group replaces them with its row, drawn as a row back, above its options. Either way
3782
+ * it's a tree: the rows and ungrouped options are level 1, a group's options level 2.
3783
+ */
3784
+ renderGroupedPanel() {
3785
+ const entries = buildPanelEntries(this.filteredItems);
3786
+ const setsize = entries.length;
3787
+ if (this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null) {
3788
+ const position = entries.findIndex(entry => entry.kind === 'group' && entry.group.optgroup === this.openGroup);
3789
+ const open = entries[position];
3790
+ if ((open === null || open === void 0 ? void 0 : open.kind) === 'group')
3791
+ return this.renderGroupBackRow(open.group, { posinset: position + 1, setsize });
3792
+ }
3793
+ this.renderedGroups = [];
3794
+ return entries.map((entry, position) => {
3795
+ const placement = { posinset: position + 1, setsize };
3796
+ if (entry.kind === 'option')
3797
+ return this.renderOption(entry.option, entry.index, Object.assign(Object.assign({}, placement), { level: 1 }));
3798
+ this.renderedGroups.push(entry.group);
3799
+ return this.renderGroupRow(entry.group, this.renderedGroups.length - 1, placement);
3800
+ });
3801
+ }
3802
+ /** A group's options, as its children in the tree. */
3803
+ renderGroupOptions(group) {
3804
+ return group.options.map(({ option, index }, position) => this.renderOption(option, index, { posinset: position + 1, setsize: group.options.length, level: 2 }));
3805
+ }
3806
+ /**
3807
+ * Drilled into a group: its treeitem, expanded. Its row reads as a way back ("Back: Tag") and
3808
+ * leads its options.
3809
+ */
3810
+ renderGroupBackRow(group, { posinset, setsize }) {
3811
+ const id = this.groupDomId(group.optgroup);
3812
+ const disabled = isGroupDisabled(group);
3813
+ return (h("li", { key: "group-back", id: id, class: {
3814
+ 'pds-combobox__group-back': true,
3815
+ 'pds-combobox__group-back--disabled': disabled,
3816
+ 'pds-combobox__group-back--highlighted': this.highlightedGroupRow === group.optgroup,
3817
+ 'pds-combobox__group-back--keyboard': this.keyboardNavigating && this.highlightedGroupRow === group.optgroup,
3818
+ }, role: "treeitem", "aria-expanded": "true", "aria-disabled": disabled ? 'true' : undefined, "aria-level": 1, "aria-posinset": posinset, "aria-setsize": setsize, "aria-labelledby": `${id}-label` }, h("div", { class: "pds-combobox__group-row-trigger pds-combobox__group-back-trigger", onMouseDown: this.onOptionMouseDown, onMouseEnter: this.onGroupBackMouseEnter, onClick: this.onGroupBackClick }, h("span", { class: "pds-combobox__group-row-label", id: `${id}-label` }, h("pds-icon", { name: "caret-left", size: "regular", "aria-hidden": "true", class: "pds-combobox__group-row-caret" }), h("span", { class: "visually-hidden" }, this.drillInBackLabel, ": "), group.label)), h("ul", { class: "pds-combobox__drill-in-options", role: "group", "aria-label": group.label }, this.renderGroupOptions(group))));
3819
+ }
3820
+ renderGroupRow(group, groupIndex, { posinset, setsize }) {
3821
+ const flyout = this.effectiveGroupDisplay === 'flyout';
3822
+ const isOpen = flyout && this.openGroup === group.optgroup;
3823
+ const hasSelection = group.options.some(({ option }) => this.isOptionSelected(option));
3824
+ const disabled = isGroupDisabled(group);
3825
+ const id = this.groupDomId(group.optgroup);
3826
+ return (h("li", { key: `group-${groupIndex}`, id: id, class: {
3827
+ 'pds-combobox__group-row': true,
3828
+ 'pds-combobox__group-row--open': isOpen,
3829
+ 'pds-combobox__group-row--has-selection': hasSelection,
3830
+ 'pds-combobox__group-row--highlighted': this.highlightedGroupRow === group.optgroup,
3831
+ 'pds-combobox__group-row--keyboard': this.keyboardNavigating && this.highlightedGroupRow === group.optgroup,
3832
+ 'pds-combobox__group-row--disabled': disabled,
3833
+ }, role: "treeitem", "aria-expanded": isOpen ? 'true' : 'false', "aria-disabled": disabled ? 'true' : undefined, "aria-level": 1, "aria-posinset": posinset, "aria-setsize": setsize, "aria-labelledby": `${id}-label`, "data-group-index": groupIndex, onMouseEnter: flyout ? this.onGroupRowMouseEnter : undefined, onMouseLeave: flyout ? this.onGroupRowMouseLeave : undefined }, h("div", { class: "pds-combobox__group-row-trigger", "data-group-index": groupIndex, onMouseDown: this.onOptionMouseDown, onMouseEnter: this.onGroupRowTriggerMouseEnter, onClick: this.onGroupRowClick }, h("span", { class: "pds-combobox__group-row-label", id: `${id}-label` }, group.icon !== null && (
3834
+ // `name`, not `icon`: `icon` also loads URLs and data: SVGs, unsanitized.
3835
+ h("pds-icon", { name: group.icon, size: "regular", "aria-hidden": "true", class: "pds-combobox__group-icon" })), group.label), h("pds-icon", { name: "caret-right", size: "regular", "aria-hidden": "true", class: "pds-combobox__group-row-caret" })), isOpen && (h("ul", { class: "pds-combobox__flyout", role: "group", "aria-label": group.label, style: { minWidth: this.flyoutMinWidth, maxWidth: this.flyoutMaxWidth } }, this.renderGroupOptions(group)))));
2737
3836
  }
2738
3837
  // Helper method to render the caret icon
2739
3838
  renderCaretIcon() {
@@ -2870,17 +3969,26 @@ const PdsCombobox = class {
2870
3969
  ]
2871
3970
  .filter(Boolean)
2872
3971
  .join(' ');
2873
- return (h(Host, { key: 'a39df3c86a29028344943bd3a2828d5e99106d77', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: '32cdb8ce31f9d7c9eac8f995cd233fe6f4d9dfc3', class: "pds-combobox", tabIndex: -1, onFocusout: this.onComboboxFocusOut, part: "combobox" }, this.label && !this.hideLabel && (h("label", { key: '64ed7fe37082e2f895daae0090ae3dfac472e3c3', htmlFor: this.componentId, class: "pds-combobox__label" }, this.label)), this.trigger === 'input' ? (h("div", { class: "pds-combobox__input-wrapper", style: { width: this.triggerWidth } }, h("input", { ref: el => {
3972
+ return (h(Host, { key: 'd709320411c4d1706133376ea716756c3e1c1471', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: '455a02fa764524c95fe0bbfd024eba7134b3ac34', class: "pds-combobox", tabIndex: -1, onFocusout: this.onComboboxFocusOut, part: "combobox" }, this.hasVisibleLabel && (h("label", { key: '0d243157491934d823156841e97bfd369e12c2d5', htmlFor: this.trigger === 'input' ? this.componentId : undefined, id: this.labelId, class: "pds-combobox__label", onClick: this.onLabelClick }, this.label)), this.trigger === 'input' ? (h("div", { class: "pds-combobox__input-wrapper", style: { width: this.triggerWidth } }, h("input", { ref: el => {
2874
3973
  this.inputEl = el;
2875
3974
  this.triggerEl = el;
2876
3975
  }, class: {
2877
3976
  'pds-combobox__input': true,
2878
3977
  'pds-combobox__input--invalid': this.isInvalid(),
2879
- }, type: "text", role: "combobox", "aria-autocomplete": "list", "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.isOpen && this.highlightedIndex >= 0 ? this.optionDomId(this.highlightedIndex) : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, value: this.displayText, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput, onClick: this.handleInputClick, onKeyDown: this.handleKeyDown, autocomplete: "off", part: "input" }), h("pds-icon", { icon: "enlarge", "aria-hidden": "true", class: "pds-combobox__input-icon" }))) : this.trigger === 'chip' ? (h("div", { class: this.getChipTriggerClass(), style: { width: this.triggerWidth }, role: "combobox", "aria-haspopup": "listbox", "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.isOpen && this.highlightedIndex >= 0 ? this.optionDomId(this.highlightedIndex) : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "chip-trigger" }, this.renderChipTriggerContent())) : (h("div", { class: triggerClass, style: { width: this.triggerWidth }, role: "combobox", "aria-haspopup": "listbox", "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.isOpen && this.highlightedIndex >= 0 ? this.optionDomId(this.highlightedIndex) : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "button-trigger" }, this.renderButtonTriggerContent())), this.renderMessages(), h("div", { key: '48041c41a39987f2f4093bd048d6c495ea69514b', style: { display: 'none' } }, h("slot", { key: '5f4d95fefbd3dbdb33ecb25af593c9429df0e10b', onSlotchange: () => this.updateOptions() })), this.renderDropdown())));
3978
+ }, type: "text", role: "combobox", "aria-autocomplete": "list", "aria-haspopup": this.inputPopupRole === 'tree' ? 'tree' : undefined, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, value: this.displayText, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput, onClick: this.handleInputClick, onKeyDown: this.handleKeyDown, autocomplete: "off", part: "input" }), h("pds-icon", { icon: "enlarge", "aria-hidden": "true", class: "pds-combobox__input-icon" }))) : this.trigger === 'chip' ? (h("div", { class: this.getChipTriggerClass(), style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "chip-trigger" }, this.renderChipTriggerContent())) : (h("div", { class: triggerClass, style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "button-trigger" }, this.renderButtonTriggerContent())), this.renderMessages(), h("div", { key: 'fd1eb34561f56df05e2f44c7acecde0e56b5e714', style: { display: 'none' } }, h("slot", { key: '68e11626a00175d0926c54086ae815be157e6bf0', onSlotchange: () => this.updateOptions() })), this.renderDropdown(), this.groupDisplay !== 'inline' && (h("span", { key: '6f3c60c3400d411abbed08ddc6e596db097bb097', class: "visually-hidden", role: "status", "aria-live": "polite" }, this.isOpen && this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null ? this.openGroup.label : '')))));
2880
3979
  }
2881
3980
  static get formAssociated() { return true; }
2882
3981
  get el() { return getElement(this); }
2883
3982
  static get watchers() { return {
3983
+ "groupDisplay": [{
3984
+ "groupDisplayChanged": 0
3985
+ }],
3986
+ "openGroup": [{
3987
+ "openGroupChanged": 0
3988
+ }],
3989
+ "flyoutFallback": [{
3990
+ "flyoutFallbackChanged": 0
3991
+ }],
2884
3992
  "isOpen": [{
2885
3993
  "isOpenChanged": 0
2886
3994
  }],