@pine-ds/core 4.9.0 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/components/mock-pds-modal.js +1 -1
  2. package/components/pds-checkbox2.js +1 -1
  3. package/components/pds-chip2.js +1 -1
  4. package/components/pds-combobox.js +2 -2
  5. package/components/pds-datepicker.js +1 -1
  6. package/components/pds-dropdown-menu.js +1 -1
  7. package/components/pds-icon2.js +1 -1
  8. package/components/pds-link2.js +1 -1
  9. package/components/pds-modal2.js +1 -1
  10. package/components/pds-multiselect.js +1 -1
  11. package/components/pds-radio-group.js +1 -1
  12. package/components/pds-text2.js +1 -1
  13. package/components/pds-tooltip.js +1 -1
  14. package/components/portal-target.js +1 -0
  15. package/components/tabbable.js +1 -1
  16. package/components/truncation-tooltip.js +1 -1
  17. package/dist/cjs/{index-Do70atou.js → index-BDnbr0DK.js} +1 -1
  18. package/dist/cjs/{index-BsWY_xEJ.js → index-D9iJuJCP.js} +12 -0
  19. package/dist/cjs/loader.cjs.js +2 -2
  20. package/dist/cjs/mock-pds-modal.cjs.entry.js +2 -2
  21. package/dist/cjs/pds-accordion.cjs.entry.js +2 -2
  22. package/dist/cjs/pds-alert.cjs.entry.js +1 -1
  23. package/dist/cjs/pds-avatar.cjs.entry.js +2 -2
  24. package/dist/cjs/pds-box.cjs.entry.js +1 -1
  25. package/dist/cjs/pds-button.cjs.entry.js +2 -2
  26. package/dist/cjs/pds-checkbox.cjs.entry.js +3 -3
  27. package/dist/cjs/pds-chip.cjs.entry.js +9 -9
  28. package/dist/cjs/pds-combobox.cjs.entry.js +102 -16
  29. package/dist/cjs/pds-container.cjs.entry.js +1 -1
  30. package/dist/cjs/pds-copytext.cjs.entry.js +4 -3
  31. package/dist/cjs/pds-datepicker.cjs.entry.js +4 -41
  32. package/dist/cjs/pds-divider.cjs.entry.js +1 -1
  33. package/dist/cjs/pds-drawer-content.cjs.entry.js +1 -1
  34. package/dist/cjs/pds-drawer-footer.cjs.entry.js +1 -1
  35. package/dist/cjs/pds-drawer-header.cjs.entry.js +1 -1
  36. package/dist/cjs/pds-drawer.cjs.entry.js +1 -1
  37. package/dist/cjs/pds-dropdown-menu-item.cjs.entry.js +1 -1
  38. package/dist/cjs/pds-dropdown-menu-separator.cjs.entry.js +1 -1
  39. package/dist/cjs/pds-dropdown-menu.cjs.entry.js +59 -47
  40. package/dist/cjs/pds-filter.cjs.entry.js +2 -2
  41. package/dist/cjs/pds-filters.cjs.entry.js +1 -1
  42. package/dist/cjs/pds-icon.cjs.entry.js +54 -21
  43. package/dist/cjs/pds-image.cjs.entry.js +1 -1
  44. package/dist/cjs/pds-input.cjs.entry.js +2 -2
  45. package/dist/cjs/pds-link.cjs.entry.js +3 -3
  46. package/dist/cjs/pds-loader.cjs.entry.js +1 -1
  47. package/dist/cjs/pds-modal-content.cjs.entry.js +1 -1
  48. package/dist/cjs/pds-modal-footer.cjs.entry.js +1 -1
  49. package/dist/cjs/pds-modal-header.cjs.entry.js +1 -1
  50. package/dist/cjs/pds-modal.cjs.entry.js +3 -3
  51. package/dist/cjs/pds-multiselect.cjs.entry.js +11 -5
  52. package/dist/cjs/pds-popover.cjs.entry.js +2 -2
  53. package/dist/cjs/pds-progress.cjs.entry.js +1 -1
  54. package/dist/cjs/pds-property.cjs.entry.js +1 -1
  55. package/dist/cjs/pds-radio-group.cjs.entry.js +66 -5
  56. package/dist/cjs/pds-radio.cjs.entry.js +2 -2
  57. package/dist/cjs/pds-row.cjs.entry.js +1 -1
  58. package/dist/cjs/pds-select.cjs.entry.js +2 -2
  59. package/dist/cjs/pds-sortable-item.cjs.entry.js +2 -2
  60. package/dist/cjs/pds-sortable.cjs.entry.js +1 -1
  61. package/dist/cjs/pds-switch.cjs.entry.js +2 -2
  62. package/dist/cjs/pds-tab.cjs.entry.js +1 -1
  63. package/dist/cjs/pds-table-body.cjs.entry.js +1 -1
  64. package/dist/cjs/pds-table-cell.cjs.entry.js +3 -2
  65. package/dist/cjs/pds-table-head-cell.cjs.entry.js +2 -2
  66. package/dist/cjs/pds-table-head.cjs.entry.js +1 -1
  67. package/dist/cjs/pds-table-row.cjs.entry.js +1 -1
  68. package/dist/cjs/pds-table.cjs.entry.js +1 -1
  69. package/dist/cjs/pds-tabpanel.cjs.entry.js +1 -1
  70. package/dist/cjs/pds-tabs.cjs.entry.js +1 -1
  71. package/dist/cjs/pds-text.cjs.entry.js +29 -3
  72. package/dist/cjs/pds-textarea.cjs.entry.js +2 -2
  73. package/dist/cjs/pds-toast.cjs.entry.js +1 -1
  74. package/dist/cjs/pds-tooltip.cjs.entry.js +16 -5
  75. package/dist/cjs/pine-core.cjs.js +2 -2
  76. package/dist/cjs/portal-target-e8WQ6dLx.js +70 -0
  77. package/dist/cjs/{tabbable-CddSt_Hi.js → tabbable-BrrrGvdG.js} +2 -1
  78. package/dist/cjs/{truncation-tooltip-O5nQmXPw.js → truncation-tooltip-Bikp7n9I.js} +43 -3
  79. package/dist/collection/components/pds-checkbox/pds-checkbox.css +20 -14
  80. package/dist/collection/components/pds-chip/pds-chip.js +5 -6
  81. package/dist/collection/components/pds-combobox/grouped-options-panel.js +39 -1
  82. package/dist/collection/components/pds-combobox/pds-combobox.css +37 -1
  83. package/dist/collection/components/pds-combobox/pds-combobox.js +62 -14
  84. package/dist/collection/components/pds-combobox/stories/pds-combobox.stories.js +48 -0
  85. package/dist/collection/components/pds-datepicker/calendar-portal.js +1 -38
  86. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js +64 -46
  87. package/dist/collection/components/pds-link/pds-link.css +1 -1
  88. package/dist/collection/components/pds-link/stories/pds-link.stories.js +48 -0
  89. package/dist/collection/components/pds-modal/pds-modal.css +1 -1
  90. package/dist/collection/components/pds-multiselect/pds-multiselect.js +9 -3
  91. package/dist/collection/components/pds-radio-group/pds-radio-group.js +65 -4
  92. package/dist/collection/components/pds-text/pds-text.js +28 -3
  93. package/dist/collection/components/pds-text/stories/pds-text.stories.js +16 -0
  94. package/dist/collection/components/pds-tooltip/pds-tooltip.css +11 -0
  95. package/dist/collection/components/pds-tooltip/pds-tooltip.js +14 -3
  96. package/dist/collection/components/pds-tooltip/stories/pds-tooltip.stories.js +30 -0
  97. package/dist/collection/utils/portal-target.js +64 -0
  98. package/dist/collection/utils/tabbable.js +2 -1
  99. package/dist/collection/utils/truncation-tooltip.js +42 -3
  100. package/dist/docs.json +9 -3
  101. package/dist/esm/{index-BFSwd-GQ.js → index-4_RRPJTO.js} +12 -1
  102. package/dist/esm/{index-m3pqpeWg.js → index-DvN3tyZp.js} +1 -1
  103. package/dist/esm/loader.js +3 -3
  104. package/dist/esm/mock-pds-modal.entry.js +2 -2
  105. package/dist/esm/pds-accordion.entry.js +2 -2
  106. package/dist/esm/pds-alert.entry.js +1 -1
  107. package/dist/esm/pds-avatar.entry.js +2 -2
  108. package/dist/esm/pds-box.entry.js +1 -1
  109. package/dist/esm/pds-button.entry.js +2 -2
  110. package/dist/esm/pds-checkbox.entry.js +3 -3
  111. package/dist/esm/pds-chip.entry.js +8 -8
  112. package/dist/esm/pds-combobox.entry.js +102 -16
  113. package/dist/esm/pds-container.entry.js +1 -1
  114. package/dist/esm/pds-copytext.entry.js +4 -3
  115. package/dist/esm/pds-datepicker.entry.js +3 -40
  116. package/dist/esm/pds-divider.entry.js +1 -1
  117. package/dist/esm/pds-drawer-content.entry.js +1 -1
  118. package/dist/esm/pds-drawer-footer.entry.js +1 -1
  119. package/dist/esm/pds-drawer-header.entry.js +1 -1
  120. package/dist/esm/pds-drawer.entry.js +1 -1
  121. package/dist/esm/pds-dropdown-menu-item.entry.js +1 -1
  122. package/dist/esm/pds-dropdown-menu-separator.entry.js +1 -1
  123. package/dist/esm/pds-dropdown-menu.entry.js +59 -47
  124. package/dist/esm/pds-filter.entry.js +2 -2
  125. package/dist/esm/pds-filters.entry.js +1 -1
  126. package/dist/esm/pds-icon.entry.js +54 -21
  127. package/dist/esm/pds-image.entry.js +1 -1
  128. package/dist/esm/pds-input.entry.js +2 -2
  129. package/dist/esm/pds-link.entry.js +3 -3
  130. package/dist/esm/pds-loader.entry.js +1 -1
  131. package/dist/esm/pds-modal-content.entry.js +1 -1
  132. package/dist/esm/pds-modal-footer.entry.js +1 -1
  133. package/dist/esm/pds-modal-header.entry.js +1 -1
  134. package/dist/esm/pds-modal.entry.js +3 -3
  135. package/dist/esm/pds-multiselect.entry.js +11 -5
  136. package/dist/esm/pds-popover.entry.js +2 -2
  137. package/dist/esm/pds-progress.entry.js +1 -1
  138. package/dist/esm/pds-property.entry.js +1 -1
  139. package/dist/esm/pds-radio-group.entry.js +66 -5
  140. package/dist/esm/pds-radio.entry.js +2 -2
  141. package/dist/esm/pds-row.entry.js +1 -1
  142. package/dist/esm/pds-select.entry.js +2 -2
  143. package/dist/esm/pds-sortable-item.entry.js +2 -2
  144. package/dist/esm/pds-sortable.entry.js +1 -1
  145. package/dist/esm/pds-switch.entry.js +2 -2
  146. package/dist/esm/pds-tab.entry.js +1 -1
  147. package/dist/esm/pds-table-body.entry.js +1 -1
  148. package/dist/esm/pds-table-cell.entry.js +3 -2
  149. package/dist/esm/pds-table-head-cell.entry.js +2 -2
  150. package/dist/esm/pds-table-head.entry.js +1 -1
  151. package/dist/esm/pds-table-row.entry.js +1 -1
  152. package/dist/esm/pds-table.entry.js +1 -1
  153. package/dist/esm/pds-tabpanel.entry.js +1 -1
  154. package/dist/esm/pds-tabs.entry.js +1 -1
  155. package/dist/esm/pds-text.entry.js +29 -3
  156. package/dist/esm/pds-textarea.entry.js +2 -2
  157. package/dist/esm/pds-toast.entry.js +1 -1
  158. package/dist/esm/pds-tooltip.entry.js +16 -5
  159. package/dist/esm/pine-core.js +3 -3
  160. package/dist/esm/portal-target-CKRzRKdO.js +66 -0
  161. package/dist/esm/{tabbable-DCKBKRUy.js → tabbable-C6ZWpp3v.js} +2 -1
  162. package/dist/esm/{truncation-tooltip-D_gvhB9r.js → truncation-tooltip-DBcPipr9.js} +43 -4
  163. package/dist/esm-es5/{index-BFSwd-GQ.js → index-4_RRPJTO.js} +1 -1
  164. package/dist/esm-es5/loader.js +1 -1
  165. package/dist/esm-es5/mock-pds-modal.entry.js +1 -1
  166. package/dist/esm-es5/pds-accordion.entry.js +1 -1
  167. package/dist/esm-es5/pds-alert.entry.js +1 -1
  168. package/dist/esm-es5/pds-avatar.entry.js +1 -1
  169. package/dist/esm-es5/pds-box.entry.js +1 -1
  170. package/dist/esm-es5/pds-button.entry.js +1 -1
  171. package/dist/esm-es5/pds-checkbox.entry.js +1 -1
  172. package/dist/esm-es5/pds-chip.entry.js +1 -1
  173. package/dist/esm-es5/pds-combobox.entry.js +2 -2
  174. package/dist/esm-es5/pds-container.entry.js +1 -1
  175. package/dist/esm-es5/pds-copytext.entry.js +1 -1
  176. package/dist/esm-es5/pds-datepicker.entry.js +1 -1
  177. package/dist/esm-es5/pds-divider.entry.js +1 -1
  178. package/dist/esm-es5/pds-drawer-content.entry.js +1 -1
  179. package/dist/esm-es5/pds-drawer-footer.entry.js +1 -1
  180. package/dist/esm-es5/pds-drawer-header.entry.js +1 -1
  181. package/dist/esm-es5/pds-drawer.entry.js +1 -1
  182. package/dist/esm-es5/pds-dropdown-menu-item.entry.js +1 -1
  183. package/dist/esm-es5/pds-dropdown-menu-separator.entry.js +1 -1
  184. package/dist/esm-es5/pds-dropdown-menu.entry.js +1 -1
  185. package/dist/esm-es5/pds-filter.entry.js +1 -1
  186. package/dist/esm-es5/pds-filters.entry.js +1 -1
  187. package/dist/esm-es5/pds-icon.entry.js +1 -1
  188. package/dist/esm-es5/pds-image.entry.js +1 -1
  189. package/dist/esm-es5/pds-input.entry.js +1 -1
  190. package/dist/esm-es5/pds-link.entry.js +1 -1
  191. package/dist/esm-es5/pds-loader.entry.js +1 -1
  192. package/dist/esm-es5/pds-modal-content.entry.js +1 -1
  193. package/dist/esm-es5/pds-modal-footer.entry.js +1 -1
  194. package/dist/esm-es5/pds-modal-header.entry.js +1 -1
  195. package/dist/esm-es5/pds-modal.entry.js +1 -1
  196. package/dist/esm-es5/pds-multiselect.entry.js +1 -1
  197. package/dist/esm-es5/pds-popover.entry.js +1 -1
  198. package/dist/esm-es5/pds-progress.entry.js +1 -1
  199. package/dist/esm-es5/pds-property.entry.js +1 -1
  200. package/dist/esm-es5/pds-radio-group.entry.js +1 -1
  201. package/dist/esm-es5/pds-radio.entry.js +1 -1
  202. package/dist/esm-es5/pds-row.entry.js +1 -1
  203. package/dist/esm-es5/pds-select.entry.js +1 -1
  204. package/dist/esm-es5/pds-sortable-item.entry.js +1 -1
  205. package/dist/esm-es5/pds-sortable.entry.js +1 -1
  206. package/dist/esm-es5/pds-switch.entry.js +1 -1
  207. package/dist/esm-es5/pds-tab.entry.js +1 -1
  208. package/dist/esm-es5/pds-table-body.entry.js +1 -1
  209. package/dist/esm-es5/pds-table-cell.entry.js +1 -1
  210. package/dist/esm-es5/pds-table-head-cell.entry.js +1 -1
  211. package/dist/esm-es5/pds-table-head.entry.js +1 -1
  212. package/dist/esm-es5/pds-table-row.entry.js +1 -1
  213. package/dist/esm-es5/pds-table.entry.js +1 -1
  214. package/dist/esm-es5/pds-tabpanel.entry.js +1 -1
  215. package/dist/esm-es5/pds-tabs.entry.js +1 -1
  216. package/dist/esm-es5/pds-text.entry.js +1 -1
  217. package/dist/esm-es5/pds-textarea.entry.js +1 -1
  218. package/dist/esm-es5/pds-toast.entry.js +1 -1
  219. package/dist/esm-es5/pds-tooltip.entry.js +1 -1
  220. package/dist/esm-es5/pine-core.js +1 -1
  221. package/dist/esm-es5/portal-target-CKRzRKdO.js +1 -0
  222. package/dist/esm-es5/tabbable-C6ZWpp3v.js +1 -0
  223. package/dist/esm-es5/truncation-tooltip-DBcPipr9.js +1 -0
  224. package/dist/pine-core/{p-7a19477e.system.entry.js → p-01f1cdaf.system.entry.js} +1 -1
  225. package/dist/pine-core/{p-ee449a4b.entry.js → p-07323107.entry.js} +1 -1
  226. package/dist/pine-core/{p-14d872d3.entry.js → p-08b8e941.entry.js} +1 -1
  227. package/dist/pine-core/p-0b7b3fc2.system.entry.js +3 -0
  228. package/dist/pine-core/p-0d5f0ab5.system.entry.js +1 -0
  229. package/dist/pine-core/p-124a0a24.entry.js +1 -0
  230. package/dist/pine-core/p-128c04e7.entry.js +1 -0
  231. package/dist/pine-core/{p-3cc19ea8.system.entry.js → p-1415c988.system.entry.js} +1 -1
  232. package/dist/pine-core/{p-de176bd9.entry.js → p-143b33a6.entry.js} +1 -1
  233. package/dist/pine-core/{p-e9a53a88.system.entry.js → p-14dedf01.system.entry.js} +1 -1
  234. package/dist/pine-core/{p-60d27247.system.entry.js → p-19cf1d91.system.entry.js} +1 -1
  235. package/dist/pine-core/{p-bcf57566.entry.js → p-1ca8d183.entry.js} +1 -1
  236. package/dist/pine-core/{p-11e7d660.entry.js → p-1e3ef425.entry.js} +1 -1
  237. package/dist/pine-core/{p-98cc327b.entry.js → p-1f62bb71.entry.js} +2 -2
  238. package/dist/pine-core/{p-6f34ad9c.entry.js → p-2a18852f.entry.js} +1 -1
  239. package/dist/pine-core/{p-3ce7e72e.system.entry.js → p-2b9622c1.system.entry.js} +1 -1
  240. package/dist/pine-core/{p-9fbcba0d.entry.js → p-2dd30d12.entry.js} +1 -1
  241. package/dist/pine-core/{p-8b97dd57.system.entry.js → p-3306dc5a.system.entry.js} +1 -1
  242. package/dist/pine-core/{p-ce554098.entry.js → p-3610cb3b.entry.js} +1 -1
  243. package/dist/pine-core/{p-079c39d1.entry.js → p-39276663.entry.js} +1 -1
  244. package/dist/pine-core/{p-89fefe36.entry.js → p-39e57657.entry.js} +1 -1
  245. package/dist/pine-core/p-3a1dc752.system.entry.js +1 -0
  246. package/dist/pine-core/{p-ef4d8fea.entry.js → p-3c229091.entry.js} +1 -1
  247. package/dist/pine-core/{p-d8bedb58.system.entry.js → p-3f8bd3fb.system.entry.js} +1 -1
  248. package/dist/pine-core/{p-6845867f.system.entry.js → p-42d43c3f.system.entry.js} +1 -1
  249. package/dist/pine-core/{p-4ee44585.system.entry.js → p-42f70f93.system.entry.js} +1 -1
  250. package/dist/pine-core/{p-0bd61097.system.entry.js → p-4a90b9c8.system.entry.js} +1 -1
  251. package/dist/pine-core/{p-64283f7b.entry.js → p-4cfe922b.entry.js} +1 -1
  252. package/dist/pine-core/p-4d47023c.system.entry.js +1 -0
  253. package/dist/pine-core/{p-b037dcbd.system.entry.js → p-4d98bc0c.system.entry.js} +1 -1
  254. package/dist/pine-core/{p-3556f6ad.entry.js → p-50ddadbf.entry.js} +1 -1
  255. package/dist/pine-core/{p-1e5648bf.system.entry.js → p-548bce53.system.entry.js} +1 -1
  256. package/dist/pine-core/{p-92a8cf7d.entry.js → p-590df41a.entry.js} +1 -1
  257. package/dist/pine-core/{p-f549f2bc.entry.js → p-5946203c.entry.js} +1 -1
  258. package/dist/pine-core/{p-d7db749a.system.entry.js → p-5f181694.system.entry.js} +1 -1
  259. package/dist/pine-core/{p-9713d6a5.system.entry.js → p-60a30975.system.entry.js} +1 -1
  260. package/dist/pine-core/{p-d94ebe84.entry.js → p-61cfdbb2.entry.js} +1 -1
  261. package/dist/pine-core/p-62aa6a78.system.entry.js +1 -0
  262. package/dist/pine-core/p-639acef8.system.entry.js +1 -0
  263. package/dist/pine-core/{p-cb560aab.system.entry.js → p-63f85859.system.entry.js} +1 -1
  264. package/dist/pine-core/{p-001d4b86.entry.js → p-64bcb378.entry.js} +1 -1
  265. package/dist/pine-core/{p-bdde1e53.entry.js → p-67999353.entry.js} +1 -1
  266. package/dist/pine-core/{p-be3b4f12.system.entry.js → p-67f795d5.system.entry.js} +1 -1
  267. package/dist/pine-core/{p-6b6ae1be.entry.js → p-6a1aa8d3.entry.js} +1 -1
  268. package/dist/pine-core/p-6f4ab1ea.system.entry.js +1 -0
  269. package/dist/pine-core/{p-110b4051.system.entry.js → p-724baba3.system.entry.js} +1 -1
  270. package/dist/pine-core/p-72659a0e.system.entry.js +1 -0
  271. package/dist/pine-core/p-7a51f15e.entry.js +1 -0
  272. package/dist/pine-core/p-7b978fff.system.entry.js +1 -0
  273. package/dist/pine-core/p-8436cbfb.entry.js +1 -0
  274. package/dist/pine-core/{p-ced6a814.system.entry.js → p-849ec281.system.entry.js} +1 -1
  275. package/dist/pine-core/p-87a32ded.system.entry.js +1 -0
  276. package/dist/pine-core/{p-f09f27ab.system.entry.js → p-89d38a82.system.entry.js} +1 -1
  277. package/dist/pine-core/{p-6602b4d0.entry.js → p-8ade17ce.entry.js} +1 -1
  278. package/dist/pine-core/{p-ebf0c51b.system.entry.js → p-8afd5f5b.system.entry.js} +1 -1
  279. package/dist/pine-core/{p-9fe4a64a.entry.js → p-8e7f75e6.entry.js} +1 -1
  280. package/dist/pine-core/{p-b9d71b76.entry.js → p-8fb520df.entry.js} +1 -1
  281. package/dist/pine-core/{p-3b5b8f73.entry.js → p-92115e88.entry.js} +1 -1
  282. package/dist/pine-core/{p-239774c9.entry.js → p-947582e1.entry.js} +1 -1
  283. package/dist/pine-core/{p-98843402.system.entry.js → p-94c9b7d1.system.entry.js} +1 -1
  284. package/dist/pine-core/p-97356d4b.entry.js +1 -0
  285. package/dist/pine-core/p-973c3ac0.entry.js +1 -0
  286. package/dist/pine-core/p-97653e60.entry.js +1 -0
  287. package/dist/pine-core/{p-7073146f.entry.js → p-97b73359.entry.js} +1 -1
  288. package/dist/pine-core/{p-bfdfbe9f.entry.js → p-99530cb5.entry.js} +1 -1
  289. package/dist/pine-core/{p-50af67ea.system.entry.js → p-9b32727a.system.entry.js} +1 -1
  290. package/dist/pine-core/{p-CjRCtzPD.system.js → p-BK1sLRfg.system.js} +1 -1
  291. package/dist/pine-core/p-BZVUD2on.js +1 -0
  292. package/dist/pine-core/p-C6ZWpp3v.js +1 -0
  293. package/dist/pine-core/p-CKRzRKdO.js +1 -0
  294. package/dist/pine-core/p-Dj-z_ugg.system.js +1 -0
  295. package/dist/pine-core/{p-BplEmwUQ.js → p-M31tvpDN.js} +2 -2
  296. package/dist/pine-core/p-XK45dzWR.system.js +1 -0
  297. package/dist/pine-core/{p-d9243653.system.entry.js → p-a09c9c5e.system.entry.js} +1 -1
  298. package/dist/pine-core/{p-55fce29e.entry.js → p-a4ce12ef.entry.js} +1 -1
  299. package/dist/pine-core/{p-dea2a254.entry.js → p-a594c41f.entry.js} +1 -1
  300. package/dist/pine-core/{p-2d5b1deb.entry.js → p-a9d96e22.entry.js} +1 -1
  301. package/dist/pine-core/{p-e1fdd53a.system.entry.js → p-ad5208a4.system.entry.js} +1 -1
  302. package/dist/pine-core/p-afc2f165.entry.js +1 -0
  303. package/dist/pine-core/{p-25bf2f26.system.entry.js → p-bcc378ba.system.entry.js} +2 -2
  304. package/dist/pine-core/{p-3f62581a.system.entry.js → p-bd7dc317.system.entry.js} +1 -1
  305. package/dist/pine-core/p-bfa34194.entry.js +1 -0
  306. package/dist/pine-core/{p-5c46553f.system.entry.js → p-c2afe4f3.system.entry.js} +1 -1
  307. package/dist/pine-core/{p-17fc76e7.system.entry.js → p-c5e1eb3c.system.entry.js} +1 -1
  308. package/dist/pine-core/p-c6a9e62c.system.entry.js +1 -0
  309. package/dist/pine-core/{p-7a14473e.entry.js → p-c7a53c4f.entry.js} +1 -1
  310. package/dist/pine-core/{p-5967d9fa.system.entry.js → p-c8a0b562.system.entry.js} +1 -1
  311. package/dist/pine-core/{p-735b3631.entry.js → p-c9ae7964.entry.js} +1 -1
  312. package/dist/pine-core/{p-b243767b.system.entry.js → p-cb9baf78.system.entry.js} +1 -1
  313. package/dist/pine-core/{p-6d64e6c7.entry.js → p-ce9fa14b.entry.js} +1 -1
  314. package/dist/pine-core/{p-68fdfb8f.system.entry.js → p-d018dc60.system.entry.js} +1 -1
  315. package/dist/pine-core/p-d47b2a6a.system.entry.js +1 -0
  316. package/dist/pine-core/{p-0790dd0d.system.entry.js → p-d48fe5a0.system.entry.js} +1 -1
  317. package/dist/pine-core/{p-414faecf.entry.js → p-d6f338e0.entry.js} +1 -1
  318. package/dist/pine-core/{p-b7cbd913.system.entry.js → p-d920d759.system.entry.js} +1 -1
  319. package/dist/pine-core/{p-87642228.entry.js → p-d9719e37.entry.js} +1 -1
  320. package/dist/pine-core/p-da8b864a.entry.js +2 -0
  321. package/dist/pine-core/{p-f2c487e6.entry.js → p-db7fb5a3.entry.js} +1 -1
  322. package/dist/pine-core/p-dd7ded84.entry.js +1 -0
  323. package/dist/pine-core/p-de455073.system.entry.js +1 -0
  324. package/dist/pine-core/{p-a7d25143.entry.js → p-e1d1b5d8.entry.js} +1 -1
  325. package/dist/pine-core/p-e3de6a1d.entry.js +1 -0
  326. package/dist/pine-core/{p-2c0047cd.entry.js → p-e7002cee.entry.js} +1 -1
  327. package/dist/pine-core/{p-5133e8be.system.entry.js → p-e82f758f.system.entry.js} +1 -1
  328. package/dist/pine-core/p-e84fa9ed.entry.js +1 -0
  329. package/dist/pine-core/{p-9dbc017f.system.entry.js → p-eb4f0daa.system.entry.js} +1 -1
  330. package/dist/pine-core/p-eb56af4a.system.entry.js +1 -0
  331. package/dist/pine-core/p-eeYeEogd.system.js +1 -0
  332. package/dist/pine-core/{p-b33ad96e.system.entry.js → p-eecd9ad8.system.entry.js} +1 -1
  333. package/dist/pine-core/{p-06279b93.system.entry.js → p-ef0eba9b.system.entry.js} +1 -1
  334. package/dist/pine-core/{p-0c60f577.system.entry.js → p-ef3a855f.system.entry.js} +1 -1
  335. package/dist/pine-core/{p-6dad76cb.system.entry.js → p-f11cce27.system.entry.js} +1 -1
  336. package/dist/pine-core/p-f354dbac.entry.js +1 -0
  337. package/dist/pine-core/{p-bda7e3be.entry.js → p-f6f4fd42.entry.js} +1 -1
  338. package/dist/pine-core/{p-7fcf3d37.entry.js → p-f71d71ca.entry.js} +1 -1
  339. package/dist/pine-core/p-f834cb07.system.entry.js +1 -0
  340. package/dist/pine-core/p-f9063262.system.entry.js +1 -0
  341. package/dist/pine-core/p-f99bd77f.entry.js +1 -0
  342. package/dist/pine-core/p-wB2y8gR7.system.js +1 -0
  343. package/dist/pine-core/pine-core.esm.js +1 -1
  344. package/dist/pine-core/pine-core.js +1 -1
  345. package/dist/types/components/pds-combobox/combobox-interface.d.ts +26 -0
  346. package/dist/types/components/pds-combobox/grouped-options-panel.d.ts +17 -0
  347. package/dist/types/components/pds-combobox/pds-combobox.d.ts +12 -2
  348. package/dist/types/components/pds-datepicker/calendar-portal.d.ts +0 -7
  349. package/dist/types/components/pds-dropdown-menu/pds-dropdown-menu.d.ts +4 -0
  350. package/dist/types/components/pds-radio-group/pds-radio-group.d.ts +8 -0
  351. package/dist/types/components/pds-text/pds-text.d.ts +4 -0
  352. package/dist/types/components/pds-tooltip/pds-tooltip.d.ts +1 -0
  353. package/dist/types/components.d.ts +2 -2
  354. package/dist/types/utils/portal-target.d.ts +17 -0
  355. package/dist/types/utils/truncation-tooltip.d.ts +5 -2
  356. package/dist/vscode.html-data.json +3 -3
  357. package/hydrate/index.js +422 -146
  358. package/hydrate/index.mjs +422 -146
  359. package/package.json +2 -2
  360. package/dist/esm-es5/tabbable-DCKBKRUy.js +0 -1
  361. package/dist/esm-es5/truncation-tooltip-D_gvhB9r.js +0 -1
  362. package/dist/pine-core/p-07b4524e.entry.js +0 -1
  363. package/dist/pine-core/p-08bbd3e6.system.entry.js +0 -1
  364. package/dist/pine-core/p-22ae92f7.system.entry.js +0 -1
  365. package/dist/pine-core/p-272b24ad.system.entry.js +0 -1
  366. package/dist/pine-core/p-38b87aa2.system.entry.js +0 -1
  367. package/dist/pine-core/p-3afb1208.entry.js +0 -1
  368. package/dist/pine-core/p-463a29fa.entry.js +0 -1
  369. package/dist/pine-core/p-568a9a79.system.entry.js +0 -1
  370. package/dist/pine-core/p-5ce5836e.system.entry.js +0 -1
  371. package/dist/pine-core/p-5f3242c8.system.entry.js +0 -1
  372. package/dist/pine-core/p-60e3b1af.entry.js +0 -1
  373. package/dist/pine-core/p-7d3a20ba.entry.js +0 -1
  374. package/dist/pine-core/p-9201b497.system.entry.js +0 -1
  375. package/dist/pine-core/p-94597b73.entry.js +0 -1
  376. package/dist/pine-core/p-97be00f4.system.entry.js +0 -1
  377. package/dist/pine-core/p-9a8971e2.system.entry.js +0 -1
  378. package/dist/pine-core/p-9a8d2985.system.entry.js +0 -3
  379. package/dist/pine-core/p-CirzxZ33.js +0 -1
  380. package/dist/pine-core/p-D52aRqFx.system.js +0 -1
  381. package/dist/pine-core/p-DCKBKRUy.js +0 -1
  382. package/dist/pine-core/p-DXO1yd32.system.js +0 -1
  383. package/dist/pine-core/p-a2078add.entry.js +0 -1
  384. package/dist/pine-core/p-a48b025a.system.entry.js +0 -1
  385. package/dist/pine-core/p-ad3b1ec3.entry.js +0 -1
  386. package/dist/pine-core/p-b017eb99.system.entry.js +0 -1
  387. package/dist/pine-core/p-b6edfdfe.entry.js +0 -2
  388. package/dist/pine-core/p-c02a32ec.entry.js +0 -1
  389. package/dist/pine-core/p-c1da80e5.entry.js +0 -1
  390. package/dist/pine-core/p-c233866c.system.entry.js +0 -1
  391. package/dist/pine-core/p-d7930540.entry.js +0 -1
  392. package/dist/pine-core/p-dfadfcd1.entry.js +0 -1
  393. package/dist/pine-core/p-e70cb112.system.entry.js +0 -1
  394. package/dist/pine-core/p-eb93cc6e.entry.js +0 -1
  395. package/dist/pine-core/p-ebf74c43.system.entry.js +0 -1
  396. package/dist/pine-core/p-fc743f6e.entry.js +0 -1
  397. package/dist/pine-core/p-wXfuz0Bd.system.js +0 -1
  398. /package/dist/esm-es5/{index-m3pqpeWg.js → index-DvN3tyZp.js} +0 -0
  399. /package/dist/pine-core/{p-m3pqpeWg.js → p-DvN3tyZp.js} +0 -0
  400. /package/dist/pine-core/{p-DaCT2ssj.system.js → p-vFsJv75D.system.js} +0 -0
@@ -1,4 +1,5 @@
1
- import { Host, h } from "@stencil/core";
1
+ import { Host, h, forceUpdate } from "@stencil/core";
2
+ import { HostStylingKeeper } from "../../utils/attributes";
2
3
  import { messageId } from "../../utils/form";
3
4
  import { danger } from "@pine-ds/icons/icons";
4
5
  /**
@@ -32,6 +33,7 @@ export class PdsRadioGroup {
32
33
  * @defaultValue false
33
34
  */
34
35
  this.required = false;
36
+ this.hostKeeper = new HostStylingKeeper();
35
37
  }
36
38
  handlePropsChange() {
37
39
  this.updateChildRadios();
@@ -83,6 +85,29 @@ export class PdsRadioGroup {
83
85
  }
84
86
  });
85
87
  }
88
+ connectedCallback() {
89
+ this.hostKeeper.connect(this.el);
90
+ // A name set while the group was detached never reaches the observer.
91
+ this.syncName();
92
+ if (typeof MutationObserver === 'undefined')
93
+ return;
94
+ // Consumers can name the group after render (a prop change, an i18n swap, a morph); re-render so their name wins.
95
+ this.hostAriaObserver = new MutationObserver(() => this.syncName());
96
+ this.hostAriaObserver.observe(this.el, { attributeFilter: ['aria-label', 'aria-labelledby'] });
97
+ }
98
+ disconnectedCallback() {
99
+ var _a;
100
+ this.hostKeeper.disconnect();
101
+ (_a = this.hostAriaObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
102
+ this.hostAriaObserver = undefined;
103
+ }
104
+ // Re-renders only when the group's name would change, so its own aria-labelledby write doesn't loop back.
105
+ syncName() {
106
+ if (this._groupId === undefined)
107
+ return;
108
+ if (this.getAriaLabelledBy() !== this.renderedLabelledBy)
109
+ forceUpdate(this);
110
+ }
86
111
  componentWillLoad() {
87
112
  // Generate stable group ID once during initialization
88
113
  // This ensures DOM stability and accessibility relationships remain consistent across re-renders
@@ -96,6 +121,18 @@ export class PdsRadioGroup {
96
121
  : `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
97
122
  this._groupId = `radio-group-${uniqueId}`;
98
123
  }
124
+ // A restored or cloned host still carries the id and ARIA references an earlier instance wrote, pointing at
125
+ // that instance's label and messages. Drop them so this render writes its own: on first load, Stencil keeps a
126
+ // host attribute that's already there.
127
+ const previousId = this.el.getAttribute('id');
128
+ if (previousId && previousId !== this._groupId) {
129
+ ['aria-labelledby', 'aria-describedby'].forEach((name) => {
130
+ var _a, _b;
131
+ const ids = (_b = (_a = this.el.getAttribute(name)) === null || _a === void 0 ? void 0 : _a.split(/\s+/)) !== null && _b !== void 0 ? _b : [];
132
+ if (ids.some((id) => id.startsWith(`${previousId}__`)))
133
+ this.el.removeAttribute(name);
134
+ });
135
+ }
99
136
  }
100
137
  componentDidLoad() {
101
138
  if (!this.name) {
@@ -148,6 +185,20 @@ export class PdsRadioGroup {
148
185
  // Otherwise, assume it's a dimension token like "100", "200", etc.
149
186
  return `var(--pine-dimension-${this.gap})`;
150
187
  }
188
+ get labelId() {
189
+ return `${this._groupId}__label`;
190
+ }
191
+ // Names the group from its visible label, unless the consumer named it with their own aria-label or aria-labelledby.
192
+ // A blank aria-label (an empty translation, say) names nothing, so it falls back to groupLabel.
193
+ getAriaLabelledBy() {
194
+ var _a;
195
+ const hostLabelledBy = this.el.getAttribute('aria-labelledby');
196
+ if ((hostLabelledBy === null || hostLabelledBy === void 0 ? void 0 : hostLabelledBy.trim()) && hostLabelledBy !== this.labelId)
197
+ return hostLabelledBy;
198
+ if ((_a = this.el.getAttribute('aria-label')) === null || _a === void 0 ? void 0 : _a.trim())
199
+ return undefined;
200
+ return this.groupLabel ? this.labelId : undefined;
201
+ }
151
202
  getAriaDescribedBy() {
152
203
  const messageIds = [];
153
204
  if (this.errorMessage) {
@@ -161,13 +212,23 @@ export class PdsRadioGroup {
161
212
  render() {
162
213
  const gapValue = this.getGapValue();
163
214
  const ariaDescribedBy = this.getAriaDescribedBy();
164
- return (h(Host, { key: 'aaf53113f06a0f49706e53735701fba64e79cb4d', class: this.classNames(), id: this._groupId, role: "group", "aria-describedby": ariaDescribedBy, style: {
215
+ const ariaLabelledBy = this.getAriaLabelledBy();
216
+ const hostClass = this.classNames();
217
+ this.renderedLabelledBy = ariaLabelledBy;
218
+ // A DOM morph strips what the component wrote on its host; put back its role, name and description.
219
+ // Only its own aria-labelledby, so a consumer's that the server dropped stays dropped.
220
+ this.hostKeeper.record(hostClass, { '--pds-radio-group-gap': gapValue }, {
221
+ role: 'radiogroup',
222
+ 'aria-describedby': ariaDescribedBy,
223
+ 'aria-labelledby': ariaLabelledBy === this.labelId ? ariaLabelledBy : undefined,
224
+ });
225
+ return (h(Host, { key: '0fe381f99dddae0aeb9189a13b0e2195f1c79886', class: hostClass, id: this._groupId, role: "radiogroup", "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, style: {
165
226
  '--pds-radio-group-gap': gapValue,
166
- } }, this.groupLabel && (h("div", { key: '4be5e43146bf348929e45498107862aaca161644', class: "pds-radio-group__label" }, this.groupLabel)), h("div", { key: 'b4a1b870c1a7167b8dcbcf0a11808bbd9a8cec4e', class: {
227
+ } }, this.groupLabel && (h("div", { key: '4967dc22fa0265dbfbabf94a49b182b8c06d0bd5', class: "pds-radio-group__label", id: this.labelId }, this.groupLabel)), h("div", { key: '7a782a6920de7eda76ab0060c7512f093671ad41', class: {
167
228
  'pds-radio-group__radios': true,
168
229
  'pds-radio-group__radios--row': this.direction === 'row',
169
230
  'pds-radio-group__radios--column': this.direction === 'column',
170
- } }, h("slot", { key: '2d841cc69c35a4f9da933bbb33c1384ca343e077', onSlotchange: () => this.updateChildRadios() })), this.helperMessage && (h("div", { key: 'a09bb9e739570c06dc1907cb4e2dceecca36f7d3', class: "pds-radio-group__message", id: messageId(this._groupId, 'helper') }, this.helperMessage)), this.errorMessage && (h("div", { key: 'b8fe891cc4b8683d18c19b3b4ddb70212185b954', class: "pds-radio-group__message pds-radio-group__message--error", id: messageId(this._groupId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: '9a15d81d8303eeb5a928b96c760f6b15e536e0dc', "aria-hidden": "true", icon: danger, size: "small" }), this.errorMessage))));
231
+ } }, h("slot", { key: '48a8d2d74961a402e3a1b053b2f0314e74b4b289', onSlotchange: () => this.updateChildRadios() })), this.helperMessage && (h("div", { key: '58db96d62b8d89f03ab245990d2d6bbd3b1b5f85', class: "pds-radio-group__message", id: messageId(this._groupId, 'helper') }, this.helperMessage)), this.errorMessage && (h("div", { key: 'ad3aafe5f7ed45853c36b537525a8fff68452f55', class: "pds-radio-group__message pds-radio-group__message--error", id: messageId(this._groupId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: '80ce92868703c5e01434e7e83a7668e320bcbee1', "aria-hidden": "true", icon: danger, size: "small" }), this.errorMessage))));
171
232
  }
172
233
  static get is() { return "pds-radio-group"; }
173
234
  static get encapsulation() { return "scoped"; }
@@ -1,7 +1,10 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { setColor } from "../../utils/utils";
3
- import { setupTruncationTooltip } from "../../utils/truncation-tooltip";
3
+ import { FOCUSABLE_WRAPPER, setupTruncationTooltip } from "../../utils/truncation-tooltip";
4
4
  import { TEXT_SIZES } from "../../utils/types";
5
+ // Re-runs setup for each text bound to its wrapping control, keyed by host, so a truncated
6
+ // text that joins the same control later can take that control's focus away from it.
7
+ const textsUsingWrapper = new WeakMap();
5
8
  /**
6
9
  * @part content - The text content container
7
10
  */
@@ -55,17 +58,39 @@ export class PdsText {
55
58
  this.destroyTruncationTooltip();
56
59
  }
57
60
  initTruncationTooltip() {
61
+ var _a;
58
62
  // Clean up any existing tooltip before setting up a new one
59
63
  this.destroyTruncationTooltip();
60
64
  if (this.contentEl) {
65
+ const wrapper = this.el.closest(FOCUSABLE_WRAPPER);
66
+ // A pds-chip with a max width binds its tooltip to the wrapper too.
67
+ const others = wrapper === null ? [] : wrapper.querySelectorAll('pds-text, pds-chip');
68
+ // One focus on a shared wrapper would open every clipped text's tooltip at once, so texts sharing one each keep
69
+ // their own stop, and a text bound before this one joined lets go: this one's focus bubbles to the wrapper too.
70
+ let sharesWrapper = false;
71
+ for (let i = 0; i < others.length; i++) {
72
+ const other = others[i];
73
+ // The property counts too: setting `truncate` runs setup before the next render reflects the attribute.
74
+ if (other !== this.el && (other.truncate || other.maxWidth || other.hasAttribute('truncate') || other.hasAttribute('max-width'))) {
75
+ sharesWrapper = true;
76
+ (_a = textsUsingWrapper.get(other)) === null || _a === void 0 ? void 0 : _a();
77
+ }
78
+ }
79
+ const usesWrapper = wrapper !== null && !sharesWrapper;
61
80
  this.truncationCleanup = setupTruncationTooltip({
62
81
  hostEl: this.el,
63
82
  contentEl: this.contentEl,
64
83
  getTooltipText: () => this.el.textContent || '',
84
+ // A wrapping link or button already takes focus, so its focus reveals the text instead of a nested tab stop.
85
+ manageTabIndex: !usesWrapper,
86
+ focusEl: usesWrapper ? wrapper : this.el,
65
87
  });
88
+ if (usesWrapper)
89
+ textsUsingWrapper.set(this.el, () => this.initTruncationTooltip());
66
90
  }
67
91
  }
68
92
  destroyTruncationTooltip() {
93
+ textsUsingWrapper.delete(this.el);
69
94
  if (this.truncationCleanup) {
70
95
  this.truncationCleanup();
71
96
  this.truncationCleanup = null;
@@ -91,7 +116,7 @@ export class PdsText {
91
116
  ? `pds-text--decoration-${this.decoration}`
92
117
  : ''}
93
118
  `;
94
- return (h(Tag, { key: 'b79a6e67f11024cb025cb26bbf77231547bd63a4', ref: (el) => (this.contentEl = el), style: this.color && setColor(this.color), class: typeClasses, part: "content" }, h("slot", { key: 'ae1f8ca39899894541eac3c07fb21ead4ab98f40' })));
119
+ return (h(Tag, { key: '30566c7810d3fd7f76ae281ae6d9a7e66803f0a3', ref: (el) => (this.contentEl = el), style: this.color && setColor(this.color), class: typeClasses, part: "content" }, h("slot", { key: 'f5113458aa9295803fc1c0bc552f9f92602cacba' })));
95
120
  }
96
121
  static get is() { return "pds-text"; }
97
122
  static get encapsulation() { return "shadow"; }
@@ -279,7 +304,7 @@ export class PdsText {
279
304
  "optional": true,
280
305
  "docs": {
281
306
  "tags": [],
282
- "text": "If set or `true`, the text will be truncated. Must add a `width` to the element.\nWhen text overflows, a tooltip showing the full text will appear on hover/focus.\nNote: While the text is overflowing, the element receives tabindex=\"0\" so the\ntooltip can be reached by keyboard. Text that fits is left out of the tab order."
307
+ "text": "If set or `true`, the text will be truncated. Must add a `width` to the element.\nWhen text overflows, a tooltip showing the full text will appear on hover/focus.\nNote: While the text is overflowing, the element receives tabindex=\"0\" so the\ntooltip can be reached by keyboard. Text that fits is left out of the tab order.\nInside a link or button (including `pds-button`, `pds-link`, `pds-tab`, and\n`pds-dropdown-menu-item`) that holds no other truncated text or `pds-chip` with a\n`max-width`, no tab stop is added; the tooltip appears when that control receives\nkeyboard focus."
283
308
  },
284
309
  "getter": false,
285
310
  "setter": false,
@@ -123,3 +123,19 @@ Truncate.args = {
123
123
  truncate: true,
124
124
  width: '250px',
125
125
  };
126
+
127
+ const TruncateInLinkTemplate = (args) => html`
128
+ <div style="width: ${args.width || '250px'};">
129
+ <a href="#">
130
+ <pds-text tag="${args.tag}" ?truncate="${args.truncate}">${args.slot}</pds-text>
131
+ </a>
132
+ </div>
133
+ <pds-text tag="p" size="xs" color="secondary" gutter="sm">Tab to the link to see the full content in a tooltip. The truncated text adds no tab stop of its own.</pds-text>`;
134
+
135
+ export const TruncateInLink = TruncateInLinkTemplate.bind();
136
+ TruncateInLink.args = {
137
+ slot: 'Id irure id magna ipsum voluptate irure esse eu nulla. Ullamco officia adipisicing qui nulla non sint.',
138
+ tag: 'p',
139
+ truncate: true,
140
+ width: '250px',
141
+ };
@@ -8,6 +8,17 @@
8
8
  --tooltip-dimension-max-width: 320px;
9
9
  }
10
10
 
11
+ :is(dialog, [popover]) > .pds-tooltip {
12
+ font-style: normal;
13
+ font-weight: normal;
14
+ letter-spacing: normal;
15
+ text-align: start;
16
+ text-indent: 0;
17
+ text-transform: none;
18
+ white-space: normal;
19
+ word-spacing: normal;
20
+ }
21
+
11
22
  .pds-tooltip__content {
12
23
  background-color: var(--pine-color-primary);
13
24
  border-radius: calc(var(--pine-dimension-xs) * 1.25);
@@ -1,5 +1,6 @@
1
1
  import { Host, h } from "@stencil/core";
2
2
  import { classNamesOf, isStencilClass } from "../../utils/keep-hydrated";
3
+ import { findPortalTarget, isTopLayerInDocument, onTopLayerClose } from "../../utils/portal-target";
3
4
  import { autoUpdate, computePosition, flip, offset, shift, } from "@floating-ui/dom";
4
5
  /**
5
6
  * @slot (default) - The tooltip's target element
@@ -23,6 +24,7 @@ export class PdsTooltip {
23
24
  this.currentPathname = '';
24
25
  this.pathnameCheckInterval = null;
25
26
  this.stopAutoUpdate = null;
27
+ this.stopWatchingPortalHost = null;
26
28
  /**
27
29
  * Determines whether or not the tooltip has an arrow
28
30
  * @defaultValue true
@@ -272,7 +274,12 @@ export class PdsTooltip {
272
274
  this.lastCopiedHtml = this.strippedHtml(initialCopy);
273
275
  this.contentDiv.append(...Array.from(initialCopy.childNodes));
274
276
  this.portalEl.appendChild(this.contentDiv);
275
- document.body.appendChild(this.portalEl);
277
+ // Nothing in the body paints above a modal dialog or open popover, so the portal goes inside one.
278
+ const portalHost = findPortalTarget(this.el, isTopLayerInDocument);
279
+ portalHost.appendChild(this.portalEl);
280
+ // Closing that host moves no pointer, so a tooltip opened by touch would outlive it unseen.
281
+ if (portalHost !== document.body)
282
+ this.stopWatchingPortalHost = onTopLayerClose(portalHost, this.handleHide);
276
283
  this.repositionPortal().catch(error => {
277
284
  console.warn('Failed to position tooltip on creation:', error);
278
285
  });
@@ -385,6 +392,10 @@ export class PdsTooltip {
385
392
  this.stopAutoUpdate();
386
393
  this.stopAutoUpdate = null;
387
394
  }
395
+ if (this.stopWatchingPortalHost !== null) {
396
+ this.stopWatchingPortalHost();
397
+ this.stopWatchingPortalHost = null;
398
+ }
388
399
  // Stop pathname change detection
389
400
  if (this.pathnameCheckInterval !== null) {
390
401
  clearInterval(this.pathnameCheckInterval);
@@ -415,9 +426,9 @@ export class PdsTooltip {
415
426
  }
416
427
  render() {
417
428
  const hostId = this.componentId || undefined;
418
- return (h(Host, { key: '067eda3089732c6a23032bb087182e6dcd0330fa', id: hostId, class: { 'pds-tooltip--is-open': this.opened } }, h("span", { key: '54f6f233c937f048f119df969630af530b10de25', class: "pds-tooltip__trigger", onMouseEnter: this.handleShow, onMouseLeave: this.handleHide,
429
+ return (h(Host, { key: '475ff12d4be035e3effa894353e7948b42a23489', id: hostId, class: { 'pds-tooltip--is-open': this.opened } }, h("span", { key: '3375dfb5bb86ba373bc5d617f4a53171505631d1', class: "pds-tooltip__trigger", onMouseEnter: this.handleShow, onMouseLeave: this.handleHide,
419
430
  /* focusin/out bubble; ensure keyboard users see tooltips */
420
- onFocusin: this.handleShow, onFocusout: this.handleHide, ref: el => this.triggerEl = el }, h("slot", { key: 'f8019985ad9fd27deb388e35c43bf2e227ff9c02' })), h("div", { key: '072c4e578aebb99cd213901369a57d7c74734ad9', class: "pds-tooltip__content-slot-wrapper", hidden: true }, h("slot", { key: '22bc45dfb56567f53a608ce2033b062363793450', name: "content" }))));
431
+ onFocusin: this.handleShow, onFocusout: this.handleHide, ref: el => this.triggerEl = el }, h("slot", { key: 'a3392ad415f5ac7f3883100bf914484ffcc8e536' })), h("div", { key: '774ac2c4808e96649b1536569aaf8cf8a6e3abc2', class: "pds-tooltip__content-slot-wrapper", hidden: true }, h("slot", { key: '672c64b4acdb365623885ac2105a9b90b1dcfa6b', name: "content" }))));
421
432
  }
422
433
  static get is() { return "pds-tooltip"; }
423
434
  static get originalStyleUrls() {
@@ -20,6 +20,29 @@ const HTMLContentTemplate = (args) => html`
20
20
  <pds-button variant="secondary">Hover</pds-button>
21
21
  </pds-tooltip>`;
22
22
 
23
+ const InModalTemplate = (args) => html`
24
+ <pds-button onclick="document.querySelector('#tooltip-modal').open = true">Open modal</pds-button>
25
+ <pds-modal id="tooltip-modal" component-id="tooltip-modal" size="sm">
26
+ <pds-modal-header>
27
+ <pds-box padding="md">
28
+ <pds-text tag="h2" size="h3">Publish changes</pds-text>
29
+ </pds-box>
30
+ </pds-modal-header>
31
+ <pds-modal-content>
32
+ <pds-box padding-inline-start="md" padding-inline-end="md">
33
+ <pds-text tag="p">Hover or focus Publish: its tooltip shows above the open modal.</pds-text>
34
+ </pds-box>
35
+ </pds-modal-content>
36
+ <pds-modal-footer>
37
+ <pds-box fit gap="sm" justify-content="end" padding="md">
38
+ <pds-button variant="secondary" onclick="document.querySelector('#tooltip-modal').open = false">Cancel</pds-button>
39
+ <pds-tooltip content=${args.content} ?has-arrow=${args.hasArrow} placement=${args.placement}>
40
+ <pds-button variant="primary">Publish</pds-button>
41
+ </pds-tooltip>
42
+ </pds-box>
43
+ </pds-modal-footer>
44
+ </pds-modal>`;
45
+
23
46
  const PositionTemplate = (args) => html`
24
47
  <div class="demo-container" style="min-height: 50vh; width: 100%; display: flex; align-items: center; justify-content: center;">
25
48
  <div class="position-demo-grid">
@@ -99,3 +122,10 @@ NoArrow.args = {
99
122
  placement: "bottom-start",
100
123
  slot: "target text"
101
124
  };
125
+
126
+ export const InModal = InModalTemplate.bind({});
127
+ InModal.args = {
128
+ content: "Fix the errors on the page to publish",
129
+ hasArrow: true,
130
+ placement: "top",
131
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The native `<dialog>` or open `popover` (as pds-filter's) an element sits in, so a popup portaled
3
+ * there shares its top layer and a click in it isn't outside it; otherwise `document.body`.
4
+ * `closest()` stops at shadow boundaries and misses one that only wraps slotted content, so this
5
+ * walks assigned slots and shadow hosts, as pds-combobox does. `isHost` picks which ancestor counts.
6
+ */
7
+ export function findPortalTarget(from, isHost = isOpenDialogOrPopover) {
8
+ const seen = new Set();
9
+ let current = from;
10
+ while (current && !seen.has(current)) {
11
+ seen.add(current);
12
+ if (current.nodeType === Node.ELEMENT_NODE && isHost(current)) {
13
+ return current;
14
+ }
15
+ const assigned = current.nodeType === Node.ELEMENT_NODE ? current.assignedSlot : null;
16
+ if (assigned) {
17
+ current = assigned;
18
+ continue;
19
+ }
20
+ const parent = current.parentNode;
21
+ current = parent instanceof ShadowRoot ? parent.host : parent;
22
+ }
23
+ return document.body;
24
+ }
25
+ /**
26
+ * A modal dialog or open popover, which paints in the top layer above anything in the body, that
27
+ * sits in the document itself: the document's stylesheets don't reach into a shadow root.
28
+ */
29
+ export function isTopLayerInDocument(el) {
30
+ if (el.getRootNode() !== el.ownerDocument)
31
+ return false;
32
+ return matchesSafely(el, ':modal') || matchesSafely(el, ':popover-open');
33
+ }
34
+ /**
35
+ * Calls `onClose` once `host` leaves the top layer (its dialog closes or its popover hides), and
36
+ * returns a function that stops listening.
37
+ */
38
+ export function onTopLayerClose(host, onClose) {
39
+ const check = () => {
40
+ if (!isTopLayerInDocument(host))
41
+ onClose();
42
+ };
43
+ host.addEventListener('close', check);
44
+ host.addEventListener('toggle', check);
45
+ return () => {
46
+ host.removeEventListener('close', check);
47
+ host.removeEventListener('toggle', check);
48
+ };
49
+ }
50
+ function isOpenDialogOrPopover(el) {
51
+ // Only an open dialog: inside a closed one, the popup would be hidden with it.
52
+ if (el.localName === 'dialog')
53
+ return el.open;
54
+ return el.hasAttribute('popover') && matchesSafely(el, ':popover-open');
55
+ }
56
+ function matchesSafely(el, selector) {
57
+ try {
58
+ return el.matches(selector);
59
+ }
60
+ catch (_a) {
61
+ // A browser without the selector (no Popover API, or no :modal): no top layer to share.
62
+ return false;
63
+ }
64
+ }
@@ -24,7 +24,8 @@ function collectTabbable(root, found) {
24
24
  const isTabStop = (el) => { var _a; return el.tabIndex >= 0 || (el.isContentEditable && !el.hasAttribute('tabindex') && !((_a = el.parentElement) === null || _a === void 0 ? void 0 : _a.isContentEditable)); };
25
25
  function visitTabbable(el, found) {
26
26
  var _a, _b, _c, _d;
27
- if (el.hasAttribute('inert'))
27
+ // A tooltip portaled into a dialog only describes the control that has focus; it's never a stop of its own.
28
+ if (el.hasAttribute('inert') || el.getAttribute('role') === 'tooltip')
28
29
  return;
29
30
  if (el.localName === 'slot') {
30
31
  const slot = el;
@@ -1,4 +1,8 @@
1
1
  import { computePosition, flip, offset, shift, } from "@floating-ui/dom";
2
+ import { findPortalTarget, isTopLayerInDocument, onTopLayerClose } from "./portal-target";
3
+ // Controls that clipped text can sit inside that already take focus, so the text adds no tab stop of its own.
4
+ // Not any `[tabindex]`: a focusable scroll region full of chips would show every chip's tooltip at once.
5
+ export const FOCUSABLE_WRAPPER = 'a[href], button, summary, pds-button, pds-link, pds-tab, pds-dropdown-menu-item, [role="option"], [role="treeitem"]';
2
6
  /** CSS class prefix used for truncation tooltip portal elements */
3
7
  const TOOLTIP_CLASS = 'pds-truncation-tooltip';
4
8
  /**
@@ -8,7 +12,8 @@ const TOOLTIP_CLASS = 'pds-truncation-tooltip';
8
12
  *
9
13
  * Z-Index Strategy:
10
14
  * Uses --pine-z-index-nuclear (9999) to ensure tooltips appear above all other UI elements.
11
- * This is necessary because tooltips are portaled to document.body and must overlay:
15
+ * This is necessary because tooltips are portaled to document.body, or into the modal dialog or
16
+ * open popover around the host (the top layer, which no z-index reaches from the body), and must overlay:
12
17
  * - Modal dialogs
13
18
  * - Dropdown menus
14
19
  * - Other floating UI elements
@@ -48,6 +53,15 @@ function injectStyles() {
48
53
  opacity: 1;
49
54
  visibility: visible;
50
55
  }
56
+ :is(dialog, [popover]) > .${TOOLTIP_CLASS} {
57
+ font-style: normal;
58
+ font-weight: normal;
59
+ text-align: start;
60
+ text-indent: 0;
61
+ text-transform: none;
62
+ white-space: normal;
63
+ word-spacing: normal;
64
+ }
51
65
  `;
52
66
  document.head.appendChild(style);
53
67
  }
@@ -74,7 +88,8 @@ function isFocusVisible(el) {
74
88
  *
75
89
  * When the element's text overflows, hovering the host element or giving it
76
90
  * keyboard focus will display a tooltip showing the full text content. The
77
- * tooltip is rendered as a portal on document.body and positioned with Floating UI.
91
+ * tooltip is rendered as a portal on document.body, or in the modal dialog or open popover around
92
+ * the host, and positioned with Floating UI.
78
93
  *
79
94
  * Also owns the element's `tabindex` while it is clipped — see syncTabIndex.
80
95
  *
@@ -84,6 +99,7 @@ export function setupTruncationTooltip(options) {
84
99
  const { hostEl, contentEl, getTooltipText, placement = 'top', reference = hostEl, manageTabIndex = true, focusEl = hostEl } = options;
85
100
  injectStyles();
86
101
  let portalEl = null;
102
+ let stopWatchingPortalHost = null;
87
103
  let isHovering = false;
88
104
  let isHoveringPortal = false;
89
105
  let isFocused = false;
@@ -162,7 +178,11 @@ export function setupTruncationTooltip(options) {
162
178
  contentDiv.className = `${TOOLTIP_CLASS}__content`;
163
179
  contentDiv.textContent = text.trim();
164
180
  portalEl.appendChild(contentDiv);
165
- document.body.appendChild(portalEl);
181
+ const portalHost = findPortalTarget(hostEl, isTopLayerInDocument);
182
+ portalHost.appendChild(portalEl);
183
+ // Closing that host moves no pointer, so a tooltip opened by touch would outlive it unseen.
184
+ if (portalHost !== document.body)
185
+ stopWatchingPortalHost = onTopLayerClose(portalHost, closeWithPortalHost);
166
186
  // Allow the user to hover into the tooltip to select/copy text
167
187
  portalEl.addEventListener('mouseenter', handlePortalMouseEnter);
168
188
  portalEl.addEventListener('mouseleave', handlePortalMouseLeave);
@@ -201,6 +221,10 @@ export function setupTruncationTooltip(options) {
201
221
  }
202
222
  }
203
223
  function removePortal() {
224
+ if (stopWatchingPortalHost !== null) {
225
+ stopWatchingPortalHost();
226
+ stopWatchingPortalHost = null;
227
+ }
204
228
  if (portalEl) {
205
229
  portalEl.removeEventListener('mouseenter', handlePortalMouseEnter);
206
230
  portalEl.removeEventListener('mouseleave', handlePortalMouseLeave);
@@ -234,6 +258,14 @@ export function setupTruncationTooltip(options) {
234
258
  return;
235
259
  removePortal();
236
260
  }
261
+ // Hover and focus can't outlast a host that's no longer shown, so none of them keeps it open.
262
+ function closeWithPortalHost() {
263
+ isHovering = false;
264
+ isHoveringPortal = false;
265
+ isFocused = false;
266
+ cancelHideTimeout();
267
+ removePortal();
268
+ }
237
269
  /**
238
270
  * Schedules tooltip removal after a short delay.
239
271
  *
@@ -265,11 +297,18 @@ export function setupTruncationTooltip(options) {
265
297
  isHoveringPortal = false;
266
298
  scheduleHide();
267
299
  }
300
+ // A second tab stop inside focusEl, such as another clipped text, bubbles its focus here too. Its event.target is
301
+ // retargeted to the stop's outermost element in focusEl's tree, which sits beside hostEl rather than around or in it.
302
+ function isFocusForHost(target) {
303
+ return focusEl === hostEl || target === focusEl || target.contains(hostEl) || hostEl.contains(target);
304
+ }
268
305
  // Keyboard focus only: focus from a click would pin the tooltip open after the pointer leaves.
269
306
  // Events from inside a shadow root arrive retargeted to its host, so test the innermost target.
270
307
  function showForVisibleFocus(event) {
271
308
  if (!isFocusVisible(event.composedPath()[0]))
272
309
  return;
310
+ if (!isFocusForHost(event.target))
311
+ return;
273
312
  isFocused = true;
274
313
  showTooltip();
275
314
  }
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-10-29T23:00:11",
2
+ "timestamp": "2026-11-06T15:29:44",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -17370,6 +17370,12 @@
17370
17370
  "capture": true,
17371
17371
  "passive": false
17372
17372
  },
17373
+ {
17374
+ "event": "keydown",
17375
+ "target": "document",
17376
+ "capture": true,
17377
+ "passive": false
17378
+ },
17373
17379
  {
17374
17380
  "event": "keydown",
17375
17381
  "target": "window",
@@ -26924,7 +26930,7 @@
26924
26930
  "mutable": false,
26925
26931
  "attr": "truncate",
26926
26932
  "reflectToAttr": true,
26927
- "docs": "If set or `true`, the text will be truncated. Must add a `width` to the element.\nWhen text overflows, a tooltip showing the full text will appear on hover/focus.\nNote: While the text is overflowing, the element receives tabindex=\"0\" so the\ntooltip can be reached by keyboard. Text that fits is left out of the tab order.",
26933
+ "docs": "If set or `true`, the text will be truncated. Must add a `width` to the element.\nWhen text overflows, a tooltip showing the full text will appear on hover/focus.\nNote: While the text is overflowing, the element receives tabindex=\"0\" so the\ntooltip can be reached by keyboard. Text that fits is left out of the tab order.\nInside a link or button (including `pds-button`, `pds-link`, `pds-tab`, and\n`pds-dropdown-menu-item`) that holds no other truncated text or `pds-chip` with a\n`max-width`, no tab stop is added; the tooltip appears when that control receives\nkeyboard focus.",
26928
26934
  "docsTags": [],
26929
26935
  "values": [
26930
26936
  {
@@ -28271,7 +28277,7 @@
28271
28277
  "path": "src/utils/types.ts"
28272
28278
  },
28273
28279
  "src/components/pds-combobox/combobox-interface.ts::ComboboxOption": {
28274
- "declaration": "export interface ComboboxOption {\n id: string | number;\n text: string;\n /**\n * Label of the group this option belongs to. Options sharing a group are rendered together\n * under one group label, where the group first appears, the same as slotted `<optgroup>`\n * markup. With `group-display=\"inline\"`, options without a group are listed before every group;\n * with `flyout` and `drill-in`, options without a group and groups keep the array's order.\n */\n group?: string;\n /**\n * Pine icon name shown beside the group's label (letters, digits and hyphens, for example\n * `hashtag`); URLs and file paths are not accepted. The first option in the group that sets\n * one wins, the same as `data-icon` on a slotted `<optgroup>`.\n */\n groupIcon?: string;\n /**\n * Pine icon name shown before the option's text (letters, digits and hyphens, for example\n * `hashtag`); URLs and file paths are not accepted. The same as `data-icon` on a slotted `<option>`.\n * Once the option is chosen, the `button` trigger shows it too.\n */\n icon?: string;\n /**\n * When `true`, the option stays reachable by the arrow keys and the pointer, so assistive tech\n * announces it as unavailable, but it cannot be selected.\n */\n disabled?: boolean;\n [key: string]: unknown;\n}",
28280
+ "declaration": "export interface ComboboxOption {\n id: string | number;\n text: string;\n /**\n * Label of the group this option belongs to. Options sharing a group are rendered together\n * under one group label, where the group first appears, the same as slotted `<optgroup>`\n * markup. With `group-display=\"inline\"`, options without a group are listed before every group;\n * with `flyout` and `drill-in`, options without a group and groups keep the array's order.\n */\n group?: string;\n /**\n * Pine icon name shown beside the group's label (letters, digits and hyphens, for example\n * `hashtag`); URLs and file paths are not accepted. The first option in the group that sets\n * one wins, the same as `data-icon` on a slotted `<optgroup>`.\n */\n groupIcon?: string;\n /**\n * A small chip after the group's label, such as \"Premium\". `label` is its text; `sentiment` is a\n * `pds-chip` sentiment (`neutral` when unset or unknown); `icon` is a Pine icon name (letters,\n * digits and hyphens, for example `premium`); URLs and file paths are not accepted. The first\n * option in the group that sets one wins, the same as `data-badge`, `data-badge-sentiment` and\n * `data-badge-icon` on a slotted `<optgroup>`. It isn't matched by search, and screen readers\n * read it as part of the group's name. It isn't shown on a drilled-in group's row back.\n */\n groupBadge?: { label: string; sentiment?: string; icon?: string };\n /**\n * Pine icon name shown before the option's text (letters, digits and hyphens, for example\n * `hashtag`); URLs and file paths are not accepted. The same as `data-icon` on a slotted `<option>`.\n * Once the option is chosen, the `button` trigger shows it too.\n */\n icon?: string;\n /**\n * A small chip after the option's text, such as \"New\". `label` is its text; `sentiment` is a\n * `pds-chip` sentiment (`neutral` when unset or unknown); `icon` is a Pine icon name (letters,\n * digits and hyphens, for example `star`); URLs and file paths are not accepted. The same as\n * `data-badge`, `data-badge-sentiment` and `data-badge-icon` on a slotted `<option>`. It isn't\n * shown in the trigger or matched by search, and screen readers read it as part of the option's\n * name. Options that are chips or custom layouts don't show it.\n */\n badge?: { label: string; sentiment?: string; icon?: string };\n /**\n * When `true`, the option stays reachable by the arrow keys and the pointer, so assistive tech\n * announces it as unavailable, but it cannot be selected.\n */\n disabled?: boolean;\n [key: string]: unknown;\n}",
28275
28281
  "docstring": "",
28276
28282
  "path": "src/components/pds-combobox/combobox-interface.ts"
28277
28283
  },
@@ -2253,6 +2253,17 @@ var postUpdateComponent = (hostRef) => {
2253
2253
  hostRef.$flags$ &= -517;
2254
2254
  }
2255
2255
  };
2256
+ var forceUpdate = (ref) => {
2257
+ var _a;
2258
+ {
2259
+ const hostRef = getHostRef(ref);
2260
+ const isConnected = (_a = hostRef == null ? void 0 : hostRef.$hostElement$) == null ? void 0 : _a.isConnected;
2261
+ if (isConnected && (hostRef.$flags$ & (2 /* hasRendered */ | 16 /* isQueuedForUpdate */)) === 2 /* hasRendered */) {
2262
+ scheduleUpdate(hostRef, false);
2263
+ }
2264
+ return isConnected;
2265
+ }
2266
+ };
2256
2267
  var appDidLoad = (who) => {
2257
2268
  var _a;
2258
2269
  nextTick(() => emitEvent(win, "appload", { detail: { namespace: NAMESPACE } }));
@@ -2924,4 +2935,4 @@ function transformTag(tag) {
2924
2935
  return tag;
2925
2936
  }
2926
2937
 
2927
- export { Fragment as F, Host as H, getElement as a, bootstrapLazy as b, createEvent as c, globalScripts as g, h, promiseResolve as p, registerInstance as r, setNonce as s };
2938
+ export { Fragment as F, Host as H, getElement as a, bootstrapLazy as b, createEvent as c, forceUpdate as f, globalScripts as g, h, promiseResolve as p, registerInstance as r, setNonce as s };
@@ -1,4 +1,4 @@
1
- /* pds-icons v10.7.0, ES Modules */
1
+ /* pds-icons v10.8.0, ES Modules */
2
2
 
3
3
  const addCircle = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' class='pdsicon'><path fill-rule='evenodd' d='M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12m11-5a1 1 0 0 1 1 1v3h3a1 1 0 1 1 0 2h-3v3a1 1 0 1 1-2 0v-3H8a1 1 0 1 1 0-2h3V8a1 1 0 0 1 1-1'/></svg>";
4
4
  const calendarSimple = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' class='pdsicon'><path fill-rule='evenodd' d='M8 1a1 1 0 0 1 1 1v1h6V2a1 1 0 1 1 2 0v1.002c.476.003.891.013 1.252.042.562.046 1.079.145 1.564.392a4 4 0 0 1 1.748 1.748c.247.485.346 1.002.392 1.564C22 7.29 22 7.954 22 8.758v8.483c0 .805 0 1.47-.044 2.01-.046.563-.145 1.08-.392 1.565a4 4 0 0 1-1.748 1.748c-.485.247-1.002.346-1.564.392-.541.044-1.206.044-2.01.044H7.758c-.805 0-1.47 0-2.01-.044-.563-.046-1.08-.145-1.565-.392a4 4 0 0 1-1.748-1.748c-.247-.485-.346-1.002-.392-1.564C2 18.71 2 18.046 2 17.242V8.758c0-.805 0-1.47.044-2.01.046-.563.145-1.08.392-1.565a4 4 0 0 1 1.748-1.748c.485-.247 1.002-.346 1.564-.392.361-.03.777-.04 1.252-.042V2a1 1 0 0 1 1-1M7 5.002c-.446.003-.795.012-1.089.036-.438.035-.663.1-.819.18a2 2 0 0 0-.874.874c-.08.156-.145.38-.18.819C4 7.361 4 7.943 4 8.8V9h16v-.2c0-.857 0-1.439-.038-1.889-.035-.438-.1-.663-.18-.819a2 2 0 0 0-.874-.874c-.156-.08-.38-.145-.819-.18A15 15 0 0 0 17 5.002V6a1 1 0 1 1-2 0V5H9v1a1 1 0 1 1-2 0zM20 11H4v6.2c0 .857 0 1.439.038 1.889.035.438.1.663.18.819a2 2 0 0 0 .874.874c.156.08.38.145.819.18C6.361 21 6.943 21 7.8 21h8.4c.857 0 1.439 0 1.889-.038.438-.035.663-.1.819-.18a2 2 0 0 0 .874-.874c.08-.156.145-.38.18-.819.037-.45.038-1.032.038-1.889z'/></svg>";