@pine-ds/core 3.29.0 → 3.31.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 (212) hide show
  1. package/components/form.js +1 -1
  2. package/components/pds-avatar.js +1 -1
  3. package/components/pds-checkbox2.js +1 -1
  4. package/components/pds-combobox.js +2 -2
  5. package/components/pds-input.js +1 -1
  6. package/components/pds-modal-content.js +1 -1
  7. package/components/pds-modal-footer.js +1 -1
  8. package/components/pds-modal-header.js +1 -1
  9. package/components/pds-modal.js +1 -1
  10. package/components/pds-multiselect.js +1 -1
  11. package/components/pds-radio-group.js +1 -1
  12. package/components/pds-radio.js +1 -1
  13. package/components/pds-select.js +1 -1
  14. package/components/pds-sortable-item.js +1 -1
  15. package/components/pds-switch.js +1 -1
  16. package/components/pds-tab.js +1 -1
  17. package/components/pds-tabpanel.js +1 -1
  18. package/components/pds-textarea.js +1 -1
  19. package/components/pds-tooltip.js +1 -1
  20. package/components/reconnected-content.js +1 -0
  21. package/dist/cjs/{form-CpM5Z8q7.js → form-MhwfKTuo.js} +11 -7
  22. package/dist/cjs/loader.cjs.js +1 -1
  23. package/dist/cjs/pds-avatar.cjs.entry.js +2 -2
  24. package/dist/cjs/pds-checkbox.cjs.entry.js +4 -4
  25. package/dist/cjs/pds-combobox.cjs.entry.js +34 -4
  26. package/dist/cjs/pds-input.cjs.entry.js +3 -3
  27. package/dist/cjs/pds-modal-content.cjs.entry.js +7 -2
  28. package/dist/cjs/pds-modal-footer.cjs.entry.js +7 -1
  29. package/dist/cjs/pds-modal-header.cjs.entry.js +7 -1
  30. package/dist/cjs/pds-modal.cjs.entry.js +40 -5
  31. package/dist/cjs/pds-multiselect.cjs.entry.js +5 -5
  32. package/dist/cjs/pds-radio-group.cjs.entry.js +20 -4
  33. package/dist/cjs/pds-radio.cjs.entry.js +17 -5
  34. package/dist/cjs/pds-select.cjs.entry.js +8 -3
  35. package/dist/cjs/pds-sortable-item.cjs.entry.js +14 -1
  36. package/dist/cjs/pds-switch.cjs.entry.js +4 -4
  37. package/dist/cjs/pds-tab.cjs.entry.js +5 -0
  38. package/dist/cjs/pds-tabpanel.cjs.entry.js +6 -1
  39. package/dist/cjs/pds-textarea.cjs.entry.js +4 -4
  40. package/dist/cjs/pds-tooltip.cjs.entry.js +32 -2
  41. package/dist/cjs/pine-core.cjs.js +1 -1
  42. package/dist/cjs/reconnected-content-CpnEQcTp.js +29 -0
  43. package/dist/collection/components/pds-avatar/pds-avatar.js +3 -2
  44. package/dist/collection/components/pds-checkbox/pds-checkbox.js +3 -3
  45. package/dist/collection/components/pds-combobox/pds-combobox.css +33 -1
  46. package/dist/collection/components/pds-combobox/pds-combobox.js +107 -3
  47. package/dist/collection/components/pds-combobox/stories/pds-combobox.stories.js +60 -0
  48. package/dist/collection/components/pds-input/pds-input.css +1 -1
  49. package/dist/collection/components/pds-input/pds-input.js +1 -1
  50. package/dist/collection/components/pds-modal/pds-modal-content/pds-modal-content.js +7 -2
  51. package/dist/collection/components/pds-modal/pds-modal-footer/pds-modal-footer.js +7 -1
  52. package/dist/collection/components/pds-modal/pds-modal-header/pds-modal-header.js +7 -1
  53. package/dist/collection/components/pds-modal/pds-modal.js +63 -5
  54. package/dist/collection/components/pds-modal/stories/pds-modal.stories.js +77 -0
  55. package/dist/collection/components/pds-multiselect/pds-multiselect.css +2 -2
  56. package/dist/collection/components/pds-multiselect/pds-multiselect.js +3 -3
  57. package/dist/collection/components/pds-radio/pds-radio.css +6 -0
  58. package/dist/collection/components/pds-radio/pds-radio.js +15 -3
  59. package/dist/collection/components/pds-radio-group/pds-radio-group.js +19 -3
  60. package/dist/collection/components/pds-select/pds-select.css +1 -1
  61. package/dist/collection/components/pds-select/pds-select.js +7 -2
  62. package/dist/collection/components/pds-sortable/pds-sortable-item/pds-sortable-item.js +14 -1
  63. package/dist/collection/components/pds-switch/pds-switch.js +3 -3
  64. package/dist/collection/components/pds-tabs/pds-tab/pds-tab.js +5 -0
  65. package/dist/collection/components/pds-tabs/pds-tabpanel/pds-tabpanel.js +6 -1
  66. package/dist/collection/components/pds-textarea/pds-textarea.js +3 -3
  67. package/dist/collection/components/pds-tooltip/pds-tooltip.js +32 -2
  68. package/dist/collection/utils/form.js +11 -7
  69. package/dist/collection/utils/reconnected-content.js +25 -0
  70. package/dist/collection/utils/test/reconnect-safety.js +31 -0
  71. package/dist/docs.json +129 -1
  72. package/dist/esm/{form-C3xDZBme.js → form-BuRbS7Hp.js} +11 -7
  73. package/dist/esm/loader.js +1 -1
  74. package/dist/esm/pds-avatar.entry.js +2 -2
  75. package/dist/esm/pds-checkbox.entry.js +4 -4
  76. package/dist/esm/pds-combobox.entry.js +34 -4
  77. package/dist/esm/pds-input.entry.js +3 -3
  78. package/dist/esm/pds-modal-content.entry.js +7 -2
  79. package/dist/esm/pds-modal-footer.entry.js +8 -2
  80. package/dist/esm/pds-modal-header.entry.js +8 -2
  81. package/dist/esm/pds-modal.entry.js +40 -5
  82. package/dist/esm/pds-multiselect.entry.js +5 -5
  83. package/dist/esm/pds-radio-group.entry.js +20 -4
  84. package/dist/esm/pds-radio.entry.js +17 -5
  85. package/dist/esm/pds-select.entry.js +8 -3
  86. package/dist/esm/pds-sortable-item.entry.js +14 -1
  87. package/dist/esm/pds-switch.entry.js +4 -4
  88. package/dist/esm/pds-tab.entry.js +5 -0
  89. package/dist/esm/pds-tabpanel.entry.js +6 -1
  90. package/dist/esm/pds-textarea.entry.js +4 -4
  91. package/dist/esm/pds-tooltip.entry.js +32 -2
  92. package/dist/esm/pine-core.js +1 -1
  93. package/dist/esm/reconnected-content-RFpTWV6r.js +27 -0
  94. package/dist/esm-es5/form-BuRbS7Hp.js +1 -0
  95. package/dist/esm-es5/loader.js +1 -1
  96. package/dist/esm-es5/pds-avatar.entry.js +1 -1
  97. package/dist/esm-es5/pds-checkbox.entry.js +1 -1
  98. package/dist/esm-es5/pds-combobox.entry.js +2 -2
  99. package/dist/esm-es5/pds-input.entry.js +1 -1
  100. package/dist/esm-es5/pds-modal-content.entry.js +1 -1
  101. package/dist/esm-es5/pds-modal-footer.entry.js +1 -1
  102. package/dist/esm-es5/pds-modal-header.entry.js +1 -1
  103. package/dist/esm-es5/pds-modal.entry.js +1 -1
  104. package/dist/esm-es5/pds-multiselect.entry.js +1 -1
  105. package/dist/esm-es5/pds-radio-group.entry.js +1 -1
  106. package/dist/esm-es5/pds-radio.entry.js +1 -1
  107. package/dist/esm-es5/pds-select.entry.js +1 -1
  108. package/dist/esm-es5/pds-sortable-item.entry.js +1 -1
  109. package/dist/esm-es5/pds-switch.entry.js +1 -1
  110. package/dist/esm-es5/pds-tab.entry.js +1 -1
  111. package/dist/esm-es5/pds-tabpanel.entry.js +1 -1
  112. package/dist/esm-es5/pds-textarea.entry.js +1 -1
  113. package/dist/esm-es5/pds-tooltip.entry.js +1 -1
  114. package/dist/esm-es5/pine-core.js +1 -1
  115. package/dist/esm-es5/reconnected-content-RFpTWV6r.js +1 -0
  116. package/dist/pine-core/p-08b0d298.entry.js +1 -0
  117. package/dist/pine-core/p-0aa85901.entry.js +2 -0
  118. package/dist/pine-core/p-16f13b17.entry.js +1 -0
  119. package/dist/pine-core/p-17d4a99a.system.entry.js +1 -0
  120. package/dist/pine-core/p-18ae43e3.entry.js +1 -0
  121. package/dist/pine-core/p-1b1ec833.system.entry.js +3 -0
  122. package/dist/pine-core/p-1b8ac76c.system.entry.js +1 -0
  123. package/dist/pine-core/p-1e87e72a.entry.js +1 -0
  124. package/dist/pine-core/p-2c5fe3d9.system.entry.js +1 -0
  125. package/dist/pine-core/{p-978b848b.system.entry.js → p-31679dbc.system.entry.js} +1 -1
  126. package/dist/pine-core/p-36fc1ade.system.entry.js +1 -0
  127. package/dist/pine-core/{p-5f4d2c5c.system.entry.js → p-3cece186.system.entry.js} +1 -1
  128. package/dist/pine-core/p-419e711c.entry.js +1 -0
  129. package/dist/pine-core/p-43268325.system.entry.js +1 -0
  130. package/dist/pine-core/p-5d1228cb.entry.js +1 -0
  131. package/dist/pine-core/p-6630f428.system.entry.js +1 -0
  132. package/dist/pine-core/{p-82af7d58.system.entry.js → p-69372e72.system.entry.js} +1 -1
  133. package/dist/pine-core/p-73619cfc.system.entry.js +1 -0
  134. package/dist/pine-core/p-73b40545.system.entry.js +1 -0
  135. package/dist/pine-core/p-7ad6f313.entry.js +1 -0
  136. package/dist/pine-core/p-7e146a45.entry.js +1 -0
  137. package/dist/pine-core/{p-ba54470a.system.entry.js → p-86d12f3c.system.entry.js} +1 -1
  138. package/dist/pine-core/p-950dd70e.system.entry.js +1 -0
  139. package/dist/pine-core/p-B1rytYxP.system.js +1 -1
  140. package/dist/pine-core/p-BbXp4qBM.system.js +1 -0
  141. package/dist/pine-core/p-BuRbS7Hp.js +1 -0
  142. package/dist/pine-core/p-BxIzb-Wc.system.js +1 -0
  143. package/dist/pine-core/p-RFpTWV6r.js +1 -0
  144. package/dist/pine-core/p-a0edb4ad.entry.js +1 -0
  145. package/dist/pine-core/p-af1e2778.entry.js +1 -0
  146. package/dist/pine-core/p-b1e5e8b1.system.entry.js +1 -0
  147. package/dist/pine-core/p-b3b44b80.entry.js +1 -0
  148. package/dist/pine-core/p-b759dc21.entry.js +1 -0
  149. package/dist/pine-core/{p-dc48f603.entry.js → p-caf73216.entry.js} +1 -1
  150. package/dist/pine-core/p-cd2370d0.system.entry.js +1 -0
  151. package/dist/pine-core/{p-3c6300a8.system.entry.js → p-cd407bed.system.entry.js} +1 -1
  152. package/dist/pine-core/p-d12a93d6.entry.js +1 -0
  153. package/dist/pine-core/p-dfa70d20.entry.js +1 -0
  154. package/dist/pine-core/p-f145e018.entry.js +1 -0
  155. package/dist/pine-core/p-f7cbdb81.system.entry.js +1 -0
  156. package/dist/pine-core/p-fef6694d.entry.js +1 -0
  157. package/dist/pine-core/pine-core.esm.js +1 -1
  158. package/dist/types/components/pds-avatar/pds-avatar.d.ts +1 -0
  159. package/dist/types/components/pds-combobox/pds-combobox.d.ts +18 -0
  160. package/dist/types/components/pds-modal/pds-modal-content/pds-modal-content.d.ts +1 -0
  161. package/dist/types/components/pds-modal/pds-modal-footer/pds-modal-footer.d.ts +2 -0
  162. package/dist/types/components/pds-modal/pds-modal-header/pds-modal-header.d.ts +2 -0
  163. package/dist/types/components/pds-modal/pds-modal.d.ts +11 -0
  164. package/dist/types/components/pds-radio/pds-radio.d.ts +1 -0
  165. package/dist/types/components/pds-radio-group/pds-radio-group.d.ts +1 -0
  166. package/dist/types/components/pds-select/pds-select.d.ts +1 -0
  167. package/dist/types/components/pds-sortable/pds-sortable-item/pds-sortable-item.d.ts +1 -0
  168. package/dist/types/components/pds-tabs/pds-tab/pds-tab.d.ts +1 -0
  169. package/dist/types/components/pds-tabs/pds-tabpanel/pds-tabpanel.d.ts +1 -0
  170. package/dist/types/components/pds-tooltip/pds-tooltip.d.ts +3 -0
  171. package/dist/types/components.d.ts +42 -0
  172. package/dist/types/{home/runner/work/pine/pine → private/tmp/claude-501/-Users-qjason-Documents-GitHub/dc3bfd4f-fc9e-49b8-b152-4257ab4ca83c/scratchpad/pine-publish-backfill}/libs/core/.stencil/scripts/vscode-custom-data-generator.d.ts +1 -1
  173. package/dist/types/utils/form.d.ts +4 -1
  174. package/dist/types/utils/reconnected-content.d.ts +14 -0
  175. package/dist/types/utils/test/reconnect-safety.d.ts +11 -0
  176. package/dist/vscode.html-data.json +10909 -0
  177. package/hydrate/index.js +248 -50
  178. package/hydrate/index.mjs +248 -50
  179. package/package.json +2 -2
  180. package/dist/esm-es5/form-C3xDZBme.js +0 -1
  181. package/dist/pine-core/p-02805a93.system.entry.js +0 -1
  182. package/dist/pine-core/p-02977c6f.entry.js +0 -1
  183. package/dist/pine-core/p-054f7011.entry.js +0 -1
  184. package/dist/pine-core/p-092a72d2.system.entry.js +0 -1
  185. package/dist/pine-core/p-0d6daa35.entry.js +0 -1
  186. package/dist/pine-core/p-12154189.system.entry.js +0 -1
  187. package/dist/pine-core/p-1deded6e.system.entry.js +0 -1
  188. package/dist/pine-core/p-1fb985bb.entry.js +0 -1
  189. package/dist/pine-core/p-2a74b396.entry.js +0 -1
  190. package/dist/pine-core/p-39ad92fc.entry.js +0 -1
  191. package/dist/pine-core/p-507e831f.system.entry.js +0 -1
  192. package/dist/pine-core/p-5c229a7f.entry.js +0 -1
  193. package/dist/pine-core/p-69e47ffc.system.entry.js +0 -1
  194. package/dist/pine-core/p-6fb68ad1.entry.js +0 -1
  195. package/dist/pine-core/p-72a1b563.system.entry.js +0 -1
  196. package/dist/pine-core/p-7a7954b2.system.entry.js +0 -1
  197. package/dist/pine-core/p-7d15b65e.entry.js +0 -1
  198. package/dist/pine-core/p-902b5790.entry.js +0 -2
  199. package/dist/pine-core/p-9aaee1e9.system.entry.js +0 -1
  200. package/dist/pine-core/p-9ba86e34.entry.js +0 -1
  201. package/dist/pine-core/p-9f041a63.system.entry.js +0 -3
  202. package/dist/pine-core/p-B1u-QvFn.system.js +0 -1
  203. package/dist/pine-core/p-C3xDZBme.js +0 -1
  204. package/dist/pine-core/p-b0674b8d.entry.js +0 -1
  205. package/dist/pine-core/p-c1932447.entry.js +0 -1
  206. package/dist/pine-core/p-ce715993.entry.js +0 -1
  207. package/dist/pine-core/p-d037308b.entry.js +0 -1
  208. package/dist/pine-core/p-e0fb06ea.system.entry.js +0 -1
  209. package/dist/pine-core/p-e4b69d10.entry.js +0 -1
  210. package/dist/pine-core/p-e81b4d04.system.entry.js +0 -1
  211. package/dist/pine-core/p-fb10caff.system.entry.js +0 -1
  212. package/dist/pine-core/p-ff3399ed.entry.js +0 -1
@@ -1031,16 +1031,16 @@ export class PdsMultiselect {
1031
1031
  'pds-multiselect__trigger--invalid': this.invalid || !!this.errorMessage,
1032
1032
  'pds-multiselect__trigger--has-value': hasSelections,
1033
1033
  'pds-multiselect__trigger--pill-inline': true,
1034
- }, onClick: this.handleTriggerClick }, this.renderInlinePills(), h("button", { ref: el => (this.triggerEl = el), type: "button", id: this.componentId, part: "pill-toggle", class: "pds-multiselect__pill-toggle", disabled: this.disabled, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "listbox", "aria-labelledby": this.label ? `${this.componentId}-label` : undefined, "aria-required": this.required ? 'true' : undefined, "aria-describedby": assignDescription(this.componentId, this.invalid || !!this.errorMessage, this.errorMessage || this.helperMessage), "aria-invalid": this.invalid || !!this.errorMessage ? 'true' : undefined, onKeyDown: this.handleTriggerKeyDown }, h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge })))) : (h("button", { ref: el => (this.triggerEl = el), type: "button", part: "trigger", class: {
1034
+ }, onClick: this.handleTriggerClick }, this.renderInlinePills(), h("button", { ref: el => (this.triggerEl = el), type: "button", id: this.componentId, part: "pill-toggle", class: "pds-multiselect__pill-toggle", disabled: this.disabled, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "listbox", "aria-labelledby": this.label ? `${this.componentId}-label` : undefined, "aria-required": this.required ? 'true' : undefined, "aria-describedby": assignDescription(this.componentId, this.invalid || !!this.errorMessage, this.helperMessage, this.errorMessage), "aria-invalid": this.invalid || !!this.errorMessage ? 'true' : undefined, onKeyDown: this.handleTriggerKeyDown }, h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge })))) : (h("button", { ref: el => (this.triggerEl = el), type: "button", part: "trigger", class: {
1035
1035
  'pds-multiselect__trigger': true,
1036
1036
  'pds-multiselect__trigger--open': this.isOpen,
1037
1037
  'pds-multiselect__trigger--disabled': this.disabled,
1038
1038
  'pds-multiselect__trigger--invalid': this.invalid || !!this.errorMessage,
1039
1039
  'pds-multiselect__trigger--has-value': hasSelections,
1040
- }, id: this.componentId, disabled: this.disabled, "aria-required": this.required ? 'true' : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "listbox", "aria-describedby": assignDescription(this.componentId, this.invalid || !!this.errorMessage, this.errorMessage || this.helperMessage), "aria-invalid": this.invalid || !!this.errorMessage ? 'true' : undefined, onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeyDown }, h("span", { class: {
1040
+ }, id: this.componentId, disabled: this.disabled, "aria-required": this.required ? 'true' : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "listbox", "aria-describedby": assignDescription(this.componentId, this.invalid || !!this.errorMessage, this.helperMessage, this.errorMessage), "aria-invalid": this.invalid || !!this.errorMessage ? 'true' : undefined, onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeyDown }, h("span", { class: {
1041
1041
  'pds-multiselect__trigger-text': true,
1042
1042
  'pds-multiselect__trigger-text--placeholder': !hasSelections || (this.selectedDisplay === 'pill' && this.pillPosition === 'below'),
1043
- } }, this.getTriggerText()), h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: '973443f9eb29dcf7fb1bde3f9101ac02967a8fd9', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: '568aab2b278abb7f4426d84ee926b4883375fb11', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: 'daddf192efd47df8c15267b9896913b926e02544', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'd0c72ab75a8e02e61c09e980ae817790804a776a', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: '0453db2fca10b3573b1dd244875f90c856c8887b', style: { display: 'none' } }, h("slot", { key: 'a612741afc9545e5e50c47d27c3c27c1d7cade3c' })))));
1043
+ } }, this.getTriggerText()), h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: '199804f5352818d32542864e3a61f7a9364cc2e3', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: 'e6855ff0aaf18f59dced2df5d636cadb4d47427b', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: '29eae23d8db31b9b9c292d5cd1dc5f641613ed32', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'aad6fd945998957cd28ab6eb97c4d80f0a732ea5', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: '7d0d56a1e097cfc0c7396c1957d16014cb071b1e', style: { display: 'none' } }, h("slot", { key: '6e7fc9dbdab3977248439aa5ea14f13e0f45bbc6' })))));
1044
1044
  }
1045
1045
  static get is() { return "pds-multiselect"; }
1046
1046
  static get encapsulation() { return "shadow"; }
@@ -59,6 +59,9 @@
59
59
  color: var(--pine-color-text-label-disabled);
60
60
  cursor: not-allowed;
61
61
  }
62
+ :host(.has-border):has(input:disabled) label::after {
63
+ cursor: not-allowed;
64
+ }
62
65
  :host(.has-border).is-invalid .pds-radio__message--error {
63
66
  color: var(--pine-color-text-message-danger);
64
67
  }
@@ -255,6 +258,9 @@ label:has(input:disabled) {
255
258
  color: var(--pine-color-text-label-disabled);
256
259
  cursor: not-allowed;
257
260
  }
261
+ :host(.has-image).is-disabled label::after {
262
+ cursor: not-allowed;
263
+ }
258
264
  :host(.has-image).is-disabled .pds-radio__message {
259
265
  color: var(--pine-color-text-label-disabled);
260
266
  }
@@ -78,13 +78,25 @@ export class PdsRadio {
78
78
  // Expose type property on the element instance to match native form element behavior
79
79
  exposeTypeProperty(this.el, () => this._type);
80
80
  }
81
+ // Discards stale hidden label/message/wrapper copies left by a page-cache (Turbo, bfcache) reconnect, rescuing real [slot="image"] content stranded inside a stale image-container first.
82
+ componentDidRender() {
83
+ const freshImageContainer = this.el.querySelector('.pds-radio__image-container:not([hidden])');
84
+ const staleSelector = '.pds-radio__image-container[hidden], .pds-radio__content-wrapper[hidden], label[hidden], .pds-radio__message[hidden]';
85
+ Array.from(this.el.querySelectorAll(staleSelector)).forEach((stale) => {
86
+ const imageSlotContent = stale.querySelector('[slot="image"]');
87
+ if (imageSlotContent !== null && freshImageContainer !== null) {
88
+ freshImageContainer.appendChild(imageSlotContent);
89
+ }
90
+ stale.remove();
91
+ });
92
+ }
81
93
  render() {
82
94
  const renderLabelAndMessages = () => [
83
- h("label", { htmlFor: this.componentId, key: `${this.componentId}-label` }, h("input", { key: '75aca490be2db050f66ddd9cb45ce122bea4db53', "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, type: "radio", id: this.componentId, name: this.name, value: this.value, checked: this.checked, required: this.required, disabled: this.disabled, onChange: this.handleRadioChange, class: this.hasImage() ? 'visually-hidden' : '' }), h("span", { key: '1bbc7398d3be35e301526b0f842274a3f1db4457', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)),
95
+ h("label", { htmlFor: this.componentId, key: `${this.componentId}-label` }, h("input", { key: 'd7534f457e24558e0e206e2de82eac5f59b47d8a', "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage, this.errorMessage), "aria-invalid": this.invalid ? "true" : undefined, type: "radio", id: this.componentId, name: this.name, value: this.value, checked: this.checked, required: this.required, disabled: this.disabled, onChange: this.handleRadioChange, class: this.hasImage() ? 'visually-hidden' : '' }), h("span", { key: 'bfb6a44684fcbb271c38da03b620e97067af6634', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)),
84
96
  this.helperMessage && (h("div", { key: `${this.componentId}-helper`, class: 'pds-radio__message', id: messageId(this.componentId, 'helper') }, this.helperMessage)),
85
- this.errorMessage && (h("div", { key: `${this.componentId}-error`, class: `pds-radio__message pds-radio__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: 'e1a1228fa52e68623098f09493d93aa03d2e65c4', icon: danger, size: "small" }), this.errorMessage))
97
+ this.errorMessage && (h("div", { key: `${this.componentId}-error`, class: `pds-radio__message pds-radio__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: 'd0c120ce21687b550b22546330d647f9876ee4d6', icon: danger, size: "small" }), this.errorMessage))
86
98
  ];
87
- return (h(Host, { key: '60fabeef5778fd30e46cfd23d05684e1743bc57f', class: this.classNames() }, this.hasImage() && (h("div", { key: '9ba3e60182a68cc8e996623cf46e17001ff451f6', class: "pds-radio__image-container", part: "image-container" }, h("slot", { key: 'bf8927129eb68ee7ed07a1f8f8727f013254e133', name: "image", onSlotchange: () => (this._hasImage = this.hasImageSlot()) }))), this.hasImage() ? (h("div", { class: "pds-radio__content-wrapper" }, renderLabelAndMessages())) : (renderLabelAndMessages())));
99
+ return (h(Host, { key: '55e4f32776bc8a5835801cd7d48b29045d4ce17f', class: this.classNames() }, this.hasImage() && (h("div", { key: '3d9bf1d624c00ea90971638b2de7b548aec73330', class: "pds-radio__image-container", part: "image-container" }, h("slot", { key: 'a256ede1340cf052570330342b1ed9e5f299c821', name: "image", onSlotchange: () => (this._hasImage = this.hasImageSlot()) }))), this.hasImage() ? (h("div", { class: "pds-radio__content-wrapper" }, renderLabelAndMessages())) : (renderLabelAndMessages())));
88
100
  }
89
101
  static get is() { return "pds-radio"; }
90
102
  static get encapsulation() { return "scoped"; }
@@ -102,6 +102,22 @@ export class PdsRadioGroup {
102
102
  }
103
103
  this.updateChildRadios();
104
104
  }
105
+ // Unwraps a stale nested .pds-radio-group__radios and discards stale label/message siblings left by a page-cache (Turbo, bfcache) reconnect.
106
+ componentDidRender() {
107
+ const radiosContainer = this.el.querySelector('.pds-radio-group__radios');
108
+ if (radiosContainer === null)
109
+ return;
110
+ const staleSelector = '.pds-radio-group__radios, .pds-radio-group__label, .pds-radio-group__message';
111
+ const findStale = () => Array.from(radiosContainer.children).find((child) => child.matches(staleSelector));
112
+ let stale = findStale();
113
+ while (stale !== undefined) {
114
+ if (stale.matches('.pds-radio-group__radios')) {
115
+ Array.from(stale.childNodes).forEach((node) => radiosContainer.insertBefore(node, stale));
116
+ }
117
+ stale.remove();
118
+ stale = findStale();
119
+ }
120
+ }
105
121
  classNames() {
106
122
  const classNames = [];
107
123
  if (this.invalid) {
@@ -144,13 +160,13 @@ export class PdsRadioGroup {
144
160
  render() {
145
161
  const gapValue = this.getGapValue();
146
162
  const ariaDescribedBy = this.getAriaDescribedBy();
147
- return (h(Host, { key: '53949e8e878887189482a13e0402402b8ee79c46', class: this.classNames(), id: this._groupId, role: "group", "aria-describedby": ariaDescribedBy, style: {
163
+ return (h(Host, { key: '0f6b6ddc2af79fc470c050ed6b5588640fe0d7b6', class: this.classNames(), id: this._groupId, role: "group", "aria-describedby": ariaDescribedBy, style: {
148
164
  '--pds-radio-group-gap': gapValue,
149
- } }, this.groupLabel && (h("div", { key: '9aa547ff0b60d1eb78ab6806c552391c119c6511', class: "pds-radio-group__label" }, this.groupLabel)), h("div", { key: '5bad4f6d4c685eca8a97b574511f21b93bdf4821', class: {
165
+ } }, this.groupLabel && (h("div", { key: '77dbdc4801c3ff50fa3ea6a84d3d6aa51702ad02', class: "pds-radio-group__label" }, this.groupLabel)), h("div", { key: 'c8d7f6aebc39f72a57f353ac2f8677139ac77e71', class: {
150
166
  'pds-radio-group__radios': true,
151
167
  'pds-radio-group__radios--row': this.direction === 'row',
152
168
  'pds-radio-group__radios--column': this.direction === 'column',
153
- } }, h("slot", { key: 'ffd76f30b308f124e1df925b2fe354ffb80f59bc', onSlotchange: () => this.updateChildRadios() })), this.helperMessage && (h("div", { key: 'ea8995384b1e1c1e98d01d704bd969a97bfd2b2a', class: "pds-radio-group__message", id: messageId(this._groupId, 'helper') }, this.helperMessage)), this.errorMessage && (h("div", { key: '30726bc368c7ad2820ae4cb43faf0a45e94a51e8', class: "pds-radio-group__message pds-radio-group__message--error", id: messageId(this._groupId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: 'acc00b6e36ead10cc5cc01033ad0f619bd75f5da', icon: danger, size: "small" }), this.errorMessage))));
169
+ } }, h("slot", { key: '605e640fada693696e0b71205d18904b0af887b0', onSlotchange: () => this.updateChildRadios() })), this.helperMessage && (h("div", { key: '13cc1c7a6b70ce6826f91a68380bc46188b218e1', class: "pds-radio-group__message", id: messageId(this._groupId, 'helper') }, this.helperMessage)), this.errorMessage && (h("div", { key: '693dd2f784eb5de04f1b885948e7064936cffa7d', class: "pds-radio-group__message pds-radio-group__message--error", id: messageId(this._groupId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: '1569aeeeffde77d4920627020d04983e860ea52e', icon: danger, size: "small" }), this.errorMessage))));
154
170
  }
155
171
  static get is() { return "pds-radio-group"; }
156
172
  static get encapsulation() { return "scoped"; }
@@ -151,7 +151,7 @@ select:has(~ .pds-select__message .pds-select__error-message):focus-visible {
151
151
  height: var(--pds-select-min-height);
152
152
  pointer-events: none;
153
153
  position: relative;
154
- z-index: var(--pine-z-index-raised);
154
+ z-index: calc(var(--pine-z-index-raised) - 1);
155
155
  }
156
156
 
157
157
  .visually-hidden {
@@ -1,5 +1,5 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { isSpecTest, messageId, exposeTypeProperty } from "../../utils/form";
2
+ import { assignDescription, isSpecTest, messageId, exposeTypeProperty } from "../../utils/form";
3
3
  import { danger, enlarge } from "@pine-ds/icons/icons";
4
4
  /**
5
5
  * @slot action - Content to be displayed in the label area, typically for help icons or links
@@ -140,6 +140,11 @@ export class PdsSelect {
140
140
  return null;
141
141
  return (h("div", { class: "pds-select__message" }, this.getHelperMessage(), this.getErrorMessage()));
142
142
  }
143
+ // The field also renders as invalid whenever an error message is present, via
144
+ // `select:has(~ .pds-select__message .pds-select__error-message)` in the styles.
145
+ isInvalid() {
146
+ return Boolean(this.invalid) || Boolean(this.errorMessage);
147
+ }
143
148
  classNames() {
144
149
  const classNames = [];
145
150
  if (this.invalid) {
@@ -223,7 +228,7 @@ export class PdsSelect {
223
228
  }
224
229
  render() {
225
230
  const hasAction = this.el.querySelector('[slot="action"]') !== null;
226
- return (h(Host, { key: '71f6bfba3361eaac3459c1b30b23183503b57ae5', "aria-disabled": this.disabled ? 'true' : null, class: this.classNames(), "has-action": hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: 'cbd0059fc405179a59c29f81510d2948e358531c', class: "pds-select" }, !this.hideLabel && (h("div", { key: '87d42d145ec0a46a474bb599e46226efc72d1acb', class: "pds-select__label-wrapper" }, h("label", { key: '23e4b10a8b99023d1779de0eb6c56ff31189dce1', htmlFor: this.componentId }, h("span", { key: 'b655a0850ce9ce173fbd814461df8529c9c150d9', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), hasAction && this.renderAction())), h("select", { key: 'a9f2cd048cdea6f0a44305a2760c418617d7c0eb', "aria-label": this.hideLabel ? this.label : undefined, autocomplete: this.autocomplete || undefined, class: "pds-select__field", disabled: this.disabled, id: this.componentId, multiple: this.multiple, name: this.name, onBlur: this.onBlur, onChange: this.onSelectUpdate, onFocus: this.onFocus, onKeyDown: this.onKeyDown, part: "select", required: this.required, ref: (el) => (this.selectEl = el) }), h("div", { key: 'cca5b1b634d1d77bc4164cb196fdd1c4ffcb888e', "aria-hidden": "true", class: "hidden", ref: (el) => (this.slotContainer = el) }, h("slot", { key: '018780883212786a89c5e6f776dc8c69853bf732', onSlotchange: this.handleSlotChange })), this.renderMessages(), !this.multiple && h("pds-icon", { key: '10e82ad220b4e9d8d9c0710a14335d5603bd6164', "aria-hidden": "true", class: "pds-select__select-icon", icon: enlarge }))));
231
+ return (h(Host, { key: 'c74f5e86a09bd3fe6e8048ca103ec9aa66a98fc6', "aria-disabled": this.disabled ? 'true' : null, class: this.classNames(), "has-action": hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: '76de23d6b0d9e32fab48e09a8f6ee3211e196115', class: "pds-select" }, !this.hideLabel && (h("div", { key: '1db87074447cbc819e6b06dd89135d018656a471', class: "pds-select__label-wrapper" }, h("label", { key: 'bc28c3b3361a19ee14a1b79edda736340009d87d', htmlFor: this.componentId }, h("span", { key: 'f0828e0e83c7c0d7cf50e08df4b861dad4df9eb9', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), hasAction && this.renderAction())), h("select", { key: 'd7d254887c976a95ad1f1da2ea540d6d3f986630', "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-label": this.hideLabel ? this.label : undefined, autocomplete: this.autocomplete || undefined, class: "pds-select__field", disabled: this.disabled, id: this.componentId, multiple: this.multiple, name: this.name, onBlur: this.onBlur, onChange: this.onSelectUpdate, onFocus: this.onFocus, onKeyDown: this.onKeyDown, part: "select", required: this.required, ref: (el) => (this.selectEl = el) }), h("div", { key: '793a84d41bd5e18d64757238704a053b1135a83c', "aria-hidden": "true", class: "hidden", ref: (el) => (this.slotContainer = el) }, h("slot", { key: '27ed9ff31bbf83fcbd2ed8dd2b23b97422b18d25', onSlotchange: this.handleSlotChange })), this.renderMessages(), !this.multiple && h("pds-icon", { key: '43d415eab0fc8a3c02e19848a5622ea43f04256e', "aria-hidden": "true", class: "pds-select__select-icon", icon: enlarge }))));
227
232
  }
228
233
  static get is() { return "pds-select"; }
229
234
  static get encapsulation() { return "shadow"; }
@@ -16,6 +16,19 @@ export class PdsSortableItem {
16
16
  */
17
17
  this.showHandle = false;
18
18
  }
19
+ // Discards stale handle/actions siblings left by a page-cache (Turbo, bfcache) reconnect; the fresh handle is always first, the fresh actions wrapper always last.
20
+ componentDidRender() {
21
+ const handles = Array.from(this.el.children).filter((child) => child.matches('.pds-sortable-item__handle'));
22
+ handles.slice(1).forEach((stale) => stale.remove());
23
+ const actionsWrappers = Array.from(this.el.children).filter((child) => child.matches('.pds-sortable-item__actions'));
24
+ const freshActions = actionsWrappers[actionsWrappers.length - 1];
25
+ actionsWrappers.slice(0, -1).forEach((stale) => {
26
+ if (freshActions !== undefined) {
27
+ Array.from(stale.children).forEach((node) => freshActions.appendChild(node));
28
+ }
29
+ stale.remove();
30
+ });
31
+ }
19
32
  componentWillRender() {
20
33
  // When the parent sortable has a type of 'handle', the sortable items
21
34
  // will automatically set showHandle to 'true'.
@@ -25,7 +38,7 @@ export class PdsSortableItem {
25
38
  }
26
39
  }
27
40
  render() {
28
- return (h(Host, { key: '631a0c1150226256cdb47d1a7bc6635144bb56d0', class: "pds-sortable-item", id: this.componentId }, this.showHandle && (h("div", { key: 'bdb6ff779a5d750b75d404521bc91cad02176ea8', class: "pds-sortable-item__handle" }, h("pds-icon", { key: '8a2d151607015d853b240517c0a1930e8c5efabb', "aria-hidden": "true", icon: handleIcon }))), h("slot", { key: '2749b15b7ec10bcd2e99677a59772107295a20e2' }), this.enableActions && (h("div", { key: '9019a0736eec7f62c5a1d25d92071fddd79a5c37', class: "pds-sortable-item__actions" }, h("slot", { key: '6645aca60484b591231f91e4a846dbe29ccca7a7', name: "sortable-item-actions" })))));
41
+ return (h(Host, { key: '5533907ee217d31754ac19bf712bdb903e3b1614', class: "pds-sortable-item", id: this.componentId }, this.showHandle && (h("div", { key: '37642112619986b21c16c243e8d140ae82c869da', class: "pds-sortable-item__handle" }, h("pds-icon", { key: '71ec5188d7443c39ab00ba8b24ffbfbdfb3bd5b4', "aria-hidden": "true", icon: handleIcon }))), h("slot", { key: '4c5f80514336f40086a3b92d8c3d5ebb04115f4a' }), this.enableActions && (h("div", { key: 'ca821be132fb88e0faa207817bb27db488475d96', class: "pds-sortable-item__actions" }, h("slot", { key: '50fc7b02c86246cd60710996399c53b9f1f669c4', name: "sortable-item-actions" })))));
29
42
  }
30
43
  static get is() { return "pds-sortable-item"; }
31
44
  static get encapsulation() { return "scoped"; }
@@ -82,9 +82,9 @@ export class PdsSwitch {
82
82
  this.inheritedAttributes = Object.assign({}, inheritAriaAttributes(this.el));
83
83
  }
84
84
  render() {
85
- return (h(Host, { key: '96ee8c40c04e95b461ba2942b740503897a56b27', class: this.switchClassNames(), "aria-disabled": this.disabled ? 'true' : null }, h("label", { key: '441d6854f2c0b02ecf3d874198b3e0636d68c83b', htmlFor: this.componentId }, h("input", Object.assign({ key: 'a26cd5fb407abc20da3e9dcfe0e52333690b783a', "aria-describedby": assignDescription(this.componentId, this.invalid, this.errorMessage || this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, checked: this.checked, class: "pds-switch__input", disabled: this.disabled, id: this.componentId, name: this.name ? this.name : this.componentId, onChange: this.onSwitchUpdate, required: this.required, type: "checkbox", value: this.value }, this.inheritedAttributes)), h("span", { key: '5762c48f481c5c5d7b62e8dab40579a4e7ff290b', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), this.helperMessage &&
86
- h("div", { key: '64c14b8833b45b4e9efb2f76faa47f0d24127c91', class: `pds-switch__message`, id: messageId(this.componentId, 'helper') }, this.helperMessage), this.errorMessage &&
87
- h("div", { key: 'cecd2e8da713e74b8e6b528b50733015f5d5069b', class: `pds-switch__message pds-switch__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: '3a1c8f87b3909cdad1bc680931f5521ecb77acd6', icon: danger, size: "small" }), this.errorMessage)));
85
+ return (h(Host, { key: '96ee8c40c04e95b461ba2942b740503897a56b27', class: this.switchClassNames(), "aria-disabled": this.disabled ? 'true' : null }, h("label", { key: '441d6854f2c0b02ecf3d874198b3e0636d68c83b', htmlFor: this.componentId }, h("input", Object.assign({ key: 'ed0c344ab46d83faf902571fcd282a605f5cfbec', "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage, this.errorMessage), "aria-invalid": this.invalid ? "true" : undefined, checked: this.checked, class: "pds-switch__input", disabled: this.disabled, id: this.componentId, name: this.name ? this.name : this.componentId, onChange: this.onSwitchUpdate, required: this.required, type: "checkbox", value: this.value }, this.inheritedAttributes)), h("span", { key: 'a2e89156f56d6c921be9b866823bb4b36710b40f', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), this.helperMessage &&
86
+ h("div", { key: '1465778f0a69d4c87108a80603d123bf0500911d', class: `pds-switch__message`, id: messageId(this.componentId, 'helper') }, this.helperMessage), this.errorMessage &&
87
+ h("div", { key: '2a652c3019f45a060283f98ea97ac83e17d7de33', class: `pds-switch__message pds-switch__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: '438895d9ad8799b540ab239ac90bedcb0231d2f0', icon: danger, size: "small" }), this.errorMessage)));
88
88
  }
89
89
  static get is() { return "pds-switch"; }
90
90
  static get encapsulation() { return "shadow"; }
@@ -1,4 +1,5 @@
1
1
  import { Fragment, Host, h } from "@stencil/core";
2
+ import { unwrapReconnectedContent } from "../../../utils/reconnected-content";
2
3
  export class PdsTab {
3
4
  constructor() {
4
5
  /**
@@ -19,6 +20,10 @@ export class PdsTab {
19
20
  /** @internal */
20
21
  this.selected = false;
21
22
  }
23
+ // Unwraps a nested <a>/<button> left by a page-cache (Turbo, bfcache) reconnect.
24
+ componentDidRender() {
25
+ unwrapReconnectedContent(this.el.querySelector('.pds-tab__content'), 'a.pds-tab, button.pds-tab', '.pds-tab__content');
26
+ }
22
27
  onTabClick(index, parentComponentId) {
23
28
  if (this.disabled)
24
29
  return;
@@ -1,4 +1,5 @@
1
1
  import { Host, h } from "@stencil/core";
2
+ import { unwrapReconnectedContent } from "../../../utils/reconnected-content";
2
3
  export class PdsTabpanel {
3
4
  constructor() {
4
5
  /**
@@ -12,8 +13,12 @@ export class PdsTabpanel {
12
13
  /** @internal */
13
14
  this.stretch = false;
14
15
  }
16
+ // Unwraps a nested .pds-tabpanel left by a page-cache (Turbo, bfcache) reconnect.
17
+ componentDidRender() {
18
+ unwrapReconnectedContent(this.el.querySelector('.pds-tabpanel'), '.pds-tabpanel');
19
+ }
15
20
  render() {
16
- return (h(Host, { key: '88dfc12ce8b2413824e6d3425aa38674fa14c764', slot: "tabpanels", class: this.stretch && this.selected ? "pds-tabpanel--stretch-active" : undefined }, h("div", { key: 'bcfe8be6480dc253b10d63d6e37caacec4a8fe7f', role: "tabpanel", id: this.parentComponentId + "__" + this.name + '-panel', tabindex: "0", "aria-labelledby": this.parentComponentId + "__" + this.name, class: this.selected ? "pds-tabpanel is-active" : "pds-tabpanel" }, h("slot", { key: '96ee87a0917e5f538a5c053045a5d6821684cf3a' }))));
21
+ return (h(Host, { key: '342748daeeba7a5e0d2daef6eb0d1c787cdb47ea', slot: "tabpanels", class: this.stretch && this.selected ? "pds-tabpanel--stretch-active" : undefined }, h("div", { key: '72826548113720f89b9adcf017c1ca02a9f7a02a', role: "tabpanel", id: this.parentComponentId + "__" + this.name + '-panel', tabindex: "0", "aria-labelledby": this.parentComponentId + "__" + this.name, class: this.selected ? "pds-tabpanel is-active" : "pds-tabpanel" }, h("slot", { key: 'f12d5bacd3ce3509c84720cdbd4441c82b1f8ced' }))));
17
22
  }
18
23
  static get is() { return "pds-tabpanel"; }
19
24
  static get originalStyleUrls() {
@@ -302,9 +302,9 @@ export class PdsTextarea {
302
302
  render() {
303
303
  const value = this.getValue();
304
304
  return (h(Host, { key: 'd13869d989752c76c80a46ebb0291df2c0546cc2', "aria-disabled": this.disabled ? 'true' : null, "aria-readonly": this.readonly ? 'true' : null, "has-action": this.hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: '19454f642896485dc22bc5dac8b6ed3b4ae5627a', class: "pds-textarea" }, this.label &&
305
- h("div", { key: 'def9e117ba3667a542e8cec32c2eabfa701c3305', class: "pds-textarea__label-wrapper" }, h("label", { key: '893a1db325ece460c627e72b765289098823e49e', htmlFor: this.componentId }, h("span", { key: 'd047f17441aa81800057d7403af15f6e38c53f6c', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), !this.hideLabel && this.renderAction()), h("div", { key: '7d0f2fab56fee9b9d9e0facabc7e607cb6bee23b', class: "pds-textarea__field-wrapper" }, h("textarea", Object.assign({ key: 'a3ecb78c5b8f42f8350abe623bacb55be6c4a0c0', ref: (el) => this.nativeTextarea = el, "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, autocomplete: this.autocomplete, class: this.textareaClassNames(), disabled: this.disabled, id: this.componentId, maxlength: this.maxLength, name: this.name, placeholder: this.placeholder, readOnly: this.readonly, required: this.required, rows: this.rows, onBlur: this.onBlur, onChange: this.onTextareaChange, onFocus: this.onFocus, onInput: this.onInput, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value), this.renderCharacterCounter()), this.helperMessage &&
306
- h("p", { key: 'b5229a6ef0b2c4ee5dcb820ce2b9bbf6334adef8', class: "pds-textarea__helper-message", id: messageId(this.componentId, 'helper') }, this.helperMessage), this.invalid &&
307
- h("p", { key: '8e6dfa97496d553b8e1e2a50c1221fad3ddb539a', "aria-live": "assertive", class: "pds-textarea__error-message", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'f3ed2677239e6d135480cf55d1d908936d746322', icon: danger, size: "small" }), this.errorMessage))));
305
+ h("div", { key: 'def9e117ba3667a542e8cec32c2eabfa701c3305', class: "pds-textarea__label-wrapper" }, h("label", { key: '893a1db325ece460c627e72b765289098823e49e', htmlFor: this.componentId }, h("span", { key: 'd047f17441aa81800057d7403af15f6e38c53f6c', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), !this.hideLabel && this.renderAction()), h("div", { key: '7d0f2fab56fee9b9d9e0facabc7e607cb6bee23b', class: "pds-textarea__field-wrapper" }, h("textarea", Object.assign({ key: '261e6031c61832acde2d595248ccdc8bd5c84768', ref: (el) => this.nativeTextarea = el, "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage, this.errorMessage), "aria-invalid": this.invalid ? "true" : undefined, autocomplete: this.autocomplete, class: this.textareaClassNames(), disabled: this.disabled, id: this.componentId, maxlength: this.maxLength, name: this.name, placeholder: this.placeholder, readOnly: this.readonly, required: this.required, rows: this.rows, onBlur: this.onBlur, onChange: this.onTextareaChange, onFocus: this.onFocus, onInput: this.onInput, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value), this.renderCharacterCounter()), this.helperMessage &&
306
+ h("p", { key: 'de40f9d13bda3d9a224349b7f4ca38194e7adbb5', class: "pds-textarea__helper-message", id: messageId(this.componentId, 'helper') }, this.helperMessage), this.invalid &&
307
+ h("p", { key: '1306917ce521c3ad0d303d255f9e7aefd0e65de7', "aria-live": "assertive", class: "pds-textarea__error-message", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: '1c9e22b9b4bf84f671797bbfb9080bdbdb7619a7', icon: danger, size: "small" }), this.errorMessage))));
308
308
  }
309
309
  static get is() { return "pds-textarea"; }
310
310
  static get encapsulation() { return "shadow"; }
@@ -44,6 +44,10 @@ export class PdsTooltip {
44
44
  * @defaultValue false
45
45
  */
46
46
  this.opened = false;
47
+ // connectedCallback fires on every reconnect (unlike componentWillLoad/componentDidLoad,
48
+ // which are one-time), so resetting this here re-arms exactly one reconnect-cleanup pass
49
+ // per connect instead of re-scanning on every render for the component's whole lifetime.
50
+ this.hasCheckedReconnect = false;
47
51
  this.handleHide = () => {
48
52
  if (this.opened && !this._isInteractiveOpen) {
49
53
  return;
@@ -104,6 +108,9 @@ export class PdsTooltip {
104
108
  }
105
109
  // no return; Stencil ignores teardown functions here
106
110
  }
111
+ connectedCallback() {
112
+ this.hasCheckedReconnect = false;
113
+ }
107
114
  disconnectedCallback() {
108
115
  window.removeEventListener('pageshow', this.handlePageShow);
109
116
  if (this.slotMutationObserver !== null) {
@@ -124,7 +131,30 @@ export class PdsTooltip {
124
131
  this.stopAutoUpdate = null;
125
132
  }
126
133
  }
134
+ // Unwraps stale nested trigger/content-slot-wrapper siblings left by a page-cache (Turbo, bfcache) reconnect, rerouting content-slot content back to the real content wrapper. Drains both wrappers (not just trigger) so content rerouted into contentWrapper is itself re-checked for further nesting.
135
+ unwrapReconnectedSlots() {
136
+ // Direct children only — querySelector would find a stale nested wrapper first.
137
+ const trigger = Array.from(this.el.children).find((child) => child.matches('.pds-tooltip__trigger'));
138
+ const contentWrapper = Array.from(this.el.children).find((child) => child.matches('.pds-tooltip__content-slot-wrapper'));
139
+ if (trigger === undefined || contentWrapper === undefined)
140
+ return;
141
+ const staleSelector = '.pds-tooltip__trigger, .pds-tooltip__content-slot-wrapper';
142
+ const findStaleIn = (root) => Array.from(root.children).find((child) => child.matches(staleSelector));
143
+ [trigger, contentWrapper].forEach((root) => {
144
+ let stale = findStaleIn(root);
145
+ while (stale !== undefined) {
146
+ const destination = stale.matches('.pds-tooltip__content-slot-wrapper') ? contentWrapper : trigger;
147
+ Array.from(stale.childNodes).forEach((node) => destination === root ? root.insertBefore(node, stale) : destination.appendChild(node));
148
+ stale.remove();
149
+ stale = findStaleIn(root);
150
+ }
151
+ });
152
+ }
127
153
  componentDidRender() {
154
+ if (!this.hasCheckedReconnect) {
155
+ this.unwrapReconnectedSlots();
156
+ this.hasCheckedReconnect = true;
157
+ }
128
158
  if (this.opened && this.portalEl === null) {
129
159
  this.createPortal();
130
160
  }
@@ -312,9 +342,9 @@ export class PdsTooltip {
312
342
  }
313
343
  render() {
314
344
  const hostId = this.componentId || undefined;
315
- return (h(Host, { key: '6af9c969e0dae4f3969cba2153797a1bccfc6d21', id: hostId, class: { 'pds-tooltip--is-open': this.opened } }, h("span", { key: '97c48a8b8d626ee913412bd55aefb17f36fad401', class: "pds-tooltip__trigger", onMouseEnter: this.handleShow, onMouseLeave: this.handleHide,
345
+ return (h(Host, { key: '10913091177f60b7de464e302067998e1a847304', id: hostId, class: { 'pds-tooltip--is-open': this.opened } }, h("span", { key: 'f61689273c965a8374e44907003f1ec83b8f28d4', class: "pds-tooltip__trigger", onMouseEnter: this.handleShow, onMouseLeave: this.handleHide,
316
346
  /* focusin/out bubble; ensure keyboard users see tooltips */
317
- onFocusin: this.handleShow, onFocusout: this.handleHide, ref: el => this.triggerEl = el }, h("slot", { key: '37715fc0bf525695a62af1944ff853228080302a' })), h("div", { key: 'a9a925b1de9ea45d2f6b9f39ec5e386537313217', class: "pds-tooltip__content-slot-wrapper", hidden: true }, h("slot", { key: '1486b30af21dc69758d7dc9890cbaf227bafffc7', name: "content" }))));
347
+ onFocusin: this.handleShow, onFocusout: this.handleHide, ref: el => this.triggerEl = el }, h("slot", { key: '7dbbcff01c291b1ec431c80fce898c1ac3b30a86' })), h("div", { key: 'f87df4b6ead21e9f96271c5717ed93b2d9992f65', class: "pds-tooltip__content-slot-wrapper", hidden: true }, h("slot", { key: 'def9f799ef340e59fbf34a0fb3c0271f0fcfd2ca', name: "content" }))));
318
348
  }
319
349
  static get is() { return "pds-tooltip"; }
320
350
  static get originalStyleUrls() {
@@ -6,14 +6,18 @@ export const messageId = (id, messageType) => {
6
6
  };
7
7
  /**
8
8
  * Assign aria-description id to relate messages with form element
9
+ *
10
+ * Returns the error message id when invalid, otherwise the helper message id.
11
+ * Pass only messages the component renders — a described id must exist in the DOM.
9
12
  */
10
- export const assignDescription = (id, invalid, helperMessage) => {
11
- if (!helperMessage)
12
- return;
13
- let relatedId = messageId(id, 'helper');
14
- if (invalid)
15
- relatedId = messageId(id, 'error');
16
- return relatedId;
13
+ export const assignDescription = (id, invalid, helperMessage, errorMessage) => {
14
+ const hasErrorMessage = Boolean(errorMessage);
15
+ const hasHelperMessage = Boolean(helperMessage);
16
+ if (invalid && hasErrorMessage)
17
+ return messageId(id, 'error');
18
+ if (hasHelperMessage)
19
+ return messageId(id, 'helper');
20
+ return undefined;
17
21
  };
18
22
  /**
19
23
  * Updates the `invalid` prop of a form element based on it's values validity
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Unwraps a stale copy of a light-DOM (`shadow: false`) component's own wrapper,
3
+ * left behind when a page-cache (Turbo, browser bfcache) reconnect nests a
4
+ * component's previous render inside its freshly rendered one. Call from
5
+ * `componentDidRender` with the element that directly contains the rendered
6
+ * `<slot>` and the selector that identifies "another one of me." Unwraps in
7
+ * place (move-then-remove) so nested content is never lost.
8
+ *
9
+ * `contentSelector` is only needed when the wrapper itself further nests a
10
+ * separate content element (e.g. pds-tab's `<a class="pds-tab">` wrapping a
11
+ * `.pds-tab__content` div) — omit it when the wrapper's own children are the
12
+ * slotted content (e.g. pds-tabpanel's `.pds-tabpanel` div).
13
+ */
14
+ export function unwrapReconnectedContent(container, selector, contentSelector) {
15
+ var _a;
16
+ if (container === null)
17
+ return;
18
+ let stale = container.firstElementChild;
19
+ while (stale === null || stale === void 0 ? void 0 : stale.matches(selector)) {
20
+ const source = contentSelector !== undefined ? ((_a = stale.querySelector(contentSelector)) !== null && _a !== void 0 ? _a : stale) : stale;
21
+ Array.from(source.childNodes).forEach((node) => container.insertBefore(node, stale));
22
+ stale.remove();
23
+ stale = container.firstElementChild;
24
+ }
25
+ }
@@ -0,0 +1,31 @@
1
+ import { newSpecPage } from "@stencil/core/testing";
2
+ /**
3
+ * Generic guard against the page-cache (Turbo, browser bfcache) reconnect bug class:
4
+ * a light-DOM (`shadow: false` or `scoped: true`) component that wraps its slotted
5
+ * content in a rendered element is reconnected over its own prior render, nesting
6
+ * (or duplicating, or losing) content.
7
+ *
8
+ * Hydrates `html`, re-parses the resulting markup the way a cache restore reconnects
9
+ * a component over its own output, and asserts no duplicate `id`s and no content
10
+ * loss or duplication survive the second pass.
11
+ */
12
+ export async function expectReconnectSafe(components, html) {
13
+ var _a, _b, _c, _d, _e, _f, _g, _h;
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ const first = await newSpecPage({ components: components, html });
16
+ const hydrated = (_b = (_a = first.root) === null || _a === void 0 ? void 0 : _a.outerHTML) !== null && _b !== void 0 ? _b : '';
17
+ const originalText = normalizeText((_d = (_c = first.root) === null || _c === void 0 ? void 0 : _c.textContent) !== null && _d !== void 0 ? _d : '');
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ const second = await newSpecPage({ components: components, html: hydrated });
20
+ const reconnectedText = normalizeText((_f = (_e = second.root) === null || _e === void 0 ? void 0 : _e.textContent) !== null && _f !== void 0 ? _f : '');
21
+ expect(reconnectedText).toBe(originalText);
22
+ const ids = Array.from((_h = (_g = second.root) === null || _g === void 0 ? void 0 : _g.querySelectorAll('[id]')) !== null && _h !== void 0 ? _h : []).map((el) => el.id);
23
+ const duplicateIds = ids.filter((id, index) => ids.indexOf(id) !== index);
24
+ expect(duplicateIds).toEqual([]);
25
+ }
26
+ // Strips whitespace entirely rather than collapsing it: an outerHTML round-trip through
27
+ // re-parsing can introduce or lose insignificant whitespace between elements, which isn't
28
+ // the content-loss/duplication bug this guard is checking for.
29
+ function normalizeText(text) {
30
+ return text.replace(/\s+/g, '');
31
+ }
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-08-13T20:44:44",
2
+ "timestamp": "2026-09-21T21:04:29",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -705,6 +705,10 @@
705
705
  {
706
706
  "name": "part",
707
707
  "text": "image - The main image element that represents the avatar component."
708
+ },
709
+ {
710
+ "name": "part",
711
+ "text": "initials - The text element that renders the avatar's initials, for restyling their color."
708
712
  }
709
713
  ],
710
714
  "usage": {},
@@ -1083,6 +1087,10 @@
1083
1087
  "name": "image",
1084
1088
  "docs": "The main image element that represents the avatar component."
1085
1089
  },
1090
+ {
1091
+ "name": "initials",
1092
+ "docs": "The text element that renders the avatar's initials, for restyling their color."
1093
+ },
1086
1094
  {
1087
1095
  "name": "status",
1088
1096
  "docs": ""
@@ -13703,6 +13711,29 @@
13703
13711
  "getter": false,
13704
13712
  "setter": false
13705
13713
  },
13714
+ {
13715
+ "name": "errorMessage",
13716
+ "type": "string",
13717
+ "complexType": {
13718
+ "original": "string",
13719
+ "resolved": "string",
13720
+ "references": {}
13721
+ },
13722
+ "mutable": false,
13723
+ "attr": "error-message",
13724
+ "reflectToAttr": false,
13725
+ "docs": "Error message to display.",
13726
+ "docsTags": [],
13727
+ "values": [
13728
+ {
13729
+ "type": "string"
13730
+ }
13731
+ ],
13732
+ "optional": true,
13733
+ "required": false,
13734
+ "getter": false,
13735
+ "setter": false
13736
+ },
13706
13737
  {
13707
13738
  "name": "fetchTimeout",
13708
13739
  "type": "number",
@@ -13761,6 +13792,29 @@
13761
13792
  "getter": false,
13762
13793
  "setter": false
13763
13794
  },
13795
+ {
13796
+ "name": "helperMessage",
13797
+ "type": "string",
13798
+ "complexType": {
13799
+ "original": "string",
13800
+ "resolved": "string",
13801
+ "references": {}
13802
+ },
13803
+ "mutable": false,
13804
+ "attr": "helper-message",
13805
+ "reflectToAttr": false,
13806
+ "docs": "Helper message to display below the combobox.",
13807
+ "docsTags": [],
13808
+ "values": [
13809
+ {
13810
+ "type": "string"
13811
+ }
13812
+ ],
13813
+ "optional": true,
13814
+ "required": false,
13815
+ "getter": false,
13816
+ "setter": false
13817
+ },
13764
13818
  {
13765
13819
  "name": "hideLabel",
13766
13820
  "type": "boolean",
@@ -13790,6 +13844,29 @@
13790
13844
  "getter": false,
13791
13845
  "setter": false
13792
13846
  },
13847
+ {
13848
+ "name": "invalid",
13849
+ "type": "boolean",
13850
+ "complexType": {
13851
+ "original": "boolean",
13852
+ "resolved": "boolean",
13853
+ "references": {}
13854
+ },
13855
+ "mutable": false,
13856
+ "attr": "invalid",
13857
+ "reflectToAttr": false,
13858
+ "docs": "If true, the combobox is in an invalid state.",
13859
+ "docsTags": [],
13860
+ "values": [
13861
+ {
13862
+ "type": "boolean"
13863
+ }
13864
+ ],
13865
+ "optional": true,
13866
+ "required": false,
13867
+ "getter": false,
13868
+ "setter": false
13869
+ },
13793
13870
  {
13794
13871
  "name": "label",
13795
13872
  "type": "string",
@@ -14148,6 +14225,28 @@
14148
14225
  }
14149
14226
  ],
14150
14227
  "methods": [
14228
+ {
14229
+ "name": "clear",
14230
+ "returns": {
14231
+ "type": "Promise<void>",
14232
+ "docs": ""
14233
+ },
14234
+ "complexType": {
14235
+ "signature": "() => Promise<void>",
14236
+ "parameters": [],
14237
+ "references": {
14238
+ "Promise": {
14239
+ "location": "global",
14240
+ "id": "global::Promise"
14241
+ }
14242
+ },
14243
+ "return": "Promise<void>"
14244
+ },
14245
+ "signature": "clear() => Promise<void>",
14246
+ "parameters": [],
14247
+ "docs": "Clears the selected value and resets the component.",
14248
+ "docsTags": []
14249
+ },
14151
14250
  {
14152
14251
  "name": "getSelectedValue",
14153
14252
  "returns": {
@@ -17383,6 +17482,35 @@
17383
17482
  "getter": false,
17384
17483
  "setter": false
17385
17484
  },
17485
+ {
17486
+ "name": "disableTopLayer",
17487
+ "type": "boolean",
17488
+ "complexType": {
17489
+ "original": "boolean",
17490
+ "resolved": "boolean",
17491
+ "references": {}
17492
+ },
17493
+ "mutable": false,
17494
+ "attr": "disable-top-layer",
17495
+ "reflectToAttr": false,
17496
+ "docs": "Whether the modal opens outside the browser top layer as a non-modal dialog.\nWhen `true` it opens with `dialog.show()` instead of `dialog.showModal()`, so\noverlays rendered elsewhere in the DOM (file pickers, editor menus) can display\nabove it via `z-index`. The page is not made inert and focus is not trapped in\nthis mode. Read when the modal opens; changing it while the modal is open is\nnot supported.",
17497
+ "docsTags": [
17498
+ {
17499
+ "name": "default",
17500
+ "text": "false"
17501
+ }
17502
+ ],
17503
+ "default": "false",
17504
+ "values": [
17505
+ {
17506
+ "type": "boolean"
17507
+ }
17508
+ ],
17509
+ "optional": false,
17510
+ "required": false,
17511
+ "getter": false,
17512
+ "setter": false
17513
+ },
17386
17514
  {
17387
17515
  "name": "open",
17388
17516
  "type": "boolean",