@pine-ds/core 4.6.0 → 4.7.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 (174) hide show
  1. package/components/pds-box2.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 +1 -1
  5. package/components/pds-copytext.js +1 -1
  6. package/components/pds-drawer.js +1 -1
  7. package/components/pds-dropdown-menu-item.js +1 -1
  8. package/components/pds-dropdown-menu.js +1 -1
  9. package/components/pds-modal2.js +1 -1
  10. package/components/pds-multiselect.js +1 -1
  11. package/components/pds-popover.js +1 -1
  12. package/components/pds-radio.js +1 -1
  13. package/components/pds-row.js +1 -1
  14. package/components/pds-switch.js +1 -1
  15. package/components/pds-table-cell2.js +1 -1
  16. package/components/pds-text2.js +1 -1
  17. package/components/truncation-tooltip.js +1 -1
  18. package/dist/cjs/loader.cjs.js +1 -1
  19. package/dist/cjs/pds-box.cjs.entry.js +96 -96
  20. package/dist/cjs/pds-checkbox.cjs.entry.js +16 -4
  21. package/dist/cjs/pds-chip.cjs.entry.js +34 -9
  22. package/dist/cjs/pds-combobox.cjs.entry.js +47 -4
  23. package/dist/cjs/pds-copytext.cjs.entry.js +7 -2
  24. package/dist/cjs/pds-drawer.cjs.entry.js +23 -10
  25. package/dist/cjs/pds-dropdown-menu-item.cjs.entry.js +2 -2
  26. package/dist/cjs/pds-dropdown-menu.cjs.entry.js +9 -5
  27. package/dist/cjs/pds-modal.cjs.entry.js +175 -49
  28. package/dist/cjs/pds-multiselect.cjs.entry.js +40 -9
  29. package/dist/cjs/pds-popover.cjs.entry.js +170 -26
  30. package/dist/cjs/pds-radio.cjs.entry.js +1 -1
  31. package/dist/cjs/pds-row.cjs.entry.js +7 -7
  32. package/dist/cjs/pds-switch.cjs.entry.js +15 -3
  33. package/dist/cjs/pds-table-cell.cjs.entry.js +24 -4
  34. package/dist/cjs/pds-text.cjs.entry.js +17 -9
  35. package/dist/cjs/pine-core.cjs.js +1 -1
  36. package/dist/cjs/{truncation-tooltip-CYgQfBLt.js → truncation-tooltip-DO9xli2e.js} +7 -7
  37. package/dist/collection/components/pds-box/pds-box.js +96 -96
  38. package/dist/collection/components/pds-checkbox/pds-checkbox.css +4 -0
  39. package/dist/collection/components/pds-checkbox/pds-checkbox.js +15 -3
  40. package/dist/collection/components/pds-chip/pds-chip.js +33 -8
  41. package/dist/collection/components/pds-chip/stories/pds-chip.stories.js +17 -0
  42. package/dist/collection/components/pds-combobox/pds-combobox.js +48 -5
  43. package/dist/collection/components/pds-combobox/stories/pds-combobox.stories.js +1 -1
  44. package/dist/collection/components/pds-copytext/pds-copytext.js +6 -1
  45. package/dist/collection/components/pds-drawer/pds-drawer.css +4 -1
  46. package/dist/collection/components/pds-drawer/pds-drawer.js +54 -17
  47. package/dist/collection/components/pds-drawer/stories/pds-drawer.stories.js +6 -1
  48. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu-item/pds-dropdown-menu-item.js +2 -2
  49. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js +15 -5
  50. package/dist/collection/components/pds-modal/pds-modal.js +180 -50
  51. package/dist/collection/components/pds-multiselect/pds-multiselect.css +4 -0
  52. package/dist/collection/components/pds-multiselect/pds-multiselect.js +42 -11
  53. package/dist/collection/components/pds-popover/pds-popover.js +171 -27
  54. package/dist/collection/components/pds-radio/pds-radio.css +6 -0
  55. package/dist/collection/components/pds-row/pds-row.js +7 -7
  56. package/dist/collection/components/pds-switch/pds-switch.js +15 -3
  57. package/dist/collection/components/pds-table/pds-table-cell/pds-table-cell.js +23 -3
  58. package/dist/collection/components/pds-text/pds-text.js +16 -8
  59. package/dist/collection/utils/truncation-tooltip.js +7 -7
  60. package/dist/docs.json +48 -9
  61. package/dist/esm/loader.js +1 -1
  62. package/dist/esm/pds-box.entry.js +96 -96
  63. package/dist/esm/pds-checkbox.entry.js +16 -4
  64. package/dist/esm/pds-chip.entry.js +34 -9
  65. package/dist/esm/pds-combobox.entry.js +47 -4
  66. package/dist/esm/pds-copytext.entry.js +7 -2
  67. package/dist/esm/pds-drawer.entry.js +23 -10
  68. package/dist/esm/pds-dropdown-menu-item.entry.js +2 -2
  69. package/dist/esm/pds-dropdown-menu.entry.js +9 -5
  70. package/dist/esm/pds-modal.entry.js +175 -49
  71. package/dist/esm/pds-multiselect.entry.js +40 -9
  72. package/dist/esm/pds-popover.entry.js +171 -27
  73. package/dist/esm/pds-radio.entry.js +1 -1
  74. package/dist/esm/pds-row.entry.js +7 -7
  75. package/dist/esm/pds-switch.entry.js +15 -3
  76. package/dist/esm/pds-table-cell.entry.js +24 -4
  77. package/dist/esm/pds-text.entry.js +17 -9
  78. package/dist/esm/pine-core.js +1 -1
  79. package/dist/esm/{truncation-tooltip-_902ENWC.js → truncation-tooltip-DRXsdKk1.js} +7 -7
  80. package/dist/esm-es5/loader.js +1 -1
  81. package/dist/esm-es5/pds-box.entry.js +1 -1
  82. package/dist/esm-es5/pds-checkbox.entry.js +1 -1
  83. package/dist/esm-es5/pds-chip.entry.js +1 -1
  84. package/dist/esm-es5/pds-combobox.entry.js +1 -1
  85. package/dist/esm-es5/pds-copytext.entry.js +1 -1
  86. package/dist/esm-es5/pds-drawer.entry.js +1 -1
  87. package/dist/esm-es5/pds-dropdown-menu-item.entry.js +1 -1
  88. package/dist/esm-es5/pds-dropdown-menu.entry.js +1 -1
  89. package/dist/esm-es5/pds-modal.entry.js +1 -1
  90. package/dist/esm-es5/pds-multiselect.entry.js +1 -1
  91. package/dist/esm-es5/pds-popover.entry.js +1 -1
  92. package/dist/esm-es5/pds-radio.entry.js +1 -1
  93. package/dist/esm-es5/pds-row.entry.js +1 -1
  94. package/dist/esm-es5/pds-switch.entry.js +1 -1
  95. package/dist/esm-es5/pds-table-cell.entry.js +1 -1
  96. package/dist/esm-es5/pds-text.entry.js +1 -1
  97. package/dist/esm-es5/pine-core.js +1 -1
  98. package/dist/esm-es5/truncation-tooltip-DRXsdKk1.js +1 -0
  99. package/dist/pine-core/{p-9af131d6.system.entry.js → p-11d98408.system.entry.js} +1 -1
  100. package/dist/pine-core/p-153ba77b.entry.js +1 -0
  101. package/dist/pine-core/p-355e4cf9.entry.js +1 -0
  102. package/dist/pine-core/p-4435fff6.system.entry.js +1 -0
  103. package/dist/pine-core/p-576cf904.system.entry.js +1 -0
  104. package/dist/pine-core/{p-4f94b4f1.system.entry.js → p-645a482b.system.entry.js} +1 -1
  105. package/dist/pine-core/{p-4fa63723.system.entry.js → p-6d603d16.system.entry.js} +1 -1
  106. package/dist/pine-core/p-74a05bcc.entry.js +1 -0
  107. package/dist/pine-core/p-7fa66cad.entry.js +1 -0
  108. package/dist/pine-core/p-80a698ae.entry.js +1 -0
  109. package/dist/pine-core/{p-bf7ee3b7.system.entry.js → p-80e6f3a0.system.entry.js} +1 -1
  110. package/dist/pine-core/p-88ff1604.entry.js +1 -0
  111. package/dist/pine-core/p-92ae6082.entry.js +1 -0
  112. package/dist/pine-core/{p-6eec23a7.system.entry.js → p-97d0b89e.system.entry.js} +1 -1
  113. package/dist/pine-core/p-993d1043.entry.js +1 -0
  114. package/dist/pine-core/p-CuSNnuFu.system.js +1 -1
  115. package/dist/pine-core/p-JtdHT_W5.js +1 -0
  116. package/dist/pine-core/p-a787b34a.system.entry.js +1 -0
  117. package/dist/pine-core/p-a939b471.entry.js +1 -0
  118. package/dist/pine-core/p-aa032a5e.system.entry.js +1 -0
  119. package/dist/pine-core/{p-646afbca.system.entry.js → p-b60ac7eb.system.entry.js} +1 -1
  120. package/dist/pine-core/p-bb73ad66.entry.js +2 -0
  121. package/dist/pine-core/p-bd26a5e8.entry.js +1 -0
  122. package/dist/pine-core/p-bf5887e8.system.entry.js +1 -0
  123. package/dist/pine-core/p-c36b490e.entry.js +1 -0
  124. package/dist/pine-core/p-c81d8ac8.entry.js +1 -0
  125. package/dist/pine-core/p-ca0a8f5c.entry.js +1 -0
  126. package/dist/pine-core/p-ca0d48e8.entry.js +1 -0
  127. package/dist/pine-core/p-cfc52b95.system.entry.js +1 -0
  128. package/dist/pine-core/{p-ba1f65c2.system.entry.js → p-d8570b4b.system.entry.js} +1 -1
  129. package/dist/pine-core/{p-9e0f920a.system.entry.js → p-e7a95a49.system.entry.js} +1 -1
  130. package/dist/pine-core/p-e803f629.system.entry.js +1 -0
  131. package/dist/pine-core/{p-df539c42.system.entry.js → p-e836f3ec.system.entry.js} +2 -2
  132. package/dist/pine-core/{p-b8e8a4ce.entry.js → p-f474d7de.entry.js} +1 -1
  133. package/dist/pine-core/{p-CBu9UrXr.system.js → p-qhdoK1Jp.system.js} +1 -1
  134. package/dist/pine-core/pine-core.esm.js +1 -1
  135. package/dist/types/components/pds-checkbox/pds-checkbox.d.ts +4 -0
  136. package/dist/types/components/pds-combobox/pds-combobox.d.ts +7 -1
  137. package/dist/types/components/pds-drawer/pds-drawer.d.ts +21 -9
  138. package/dist/types/components/pds-dropdown-menu/pds-dropdown-menu.d.ts +1 -0
  139. package/dist/types/components/pds-modal/pds-modal.d.ts +16 -3
  140. package/dist/types/components/pds-multiselect/pds-multiselect.d.ts +10 -3
  141. package/dist/types/components/pds-popover/pds-popover.d.ts +31 -1
  142. package/dist/types/components/pds-switch/pds-switch.d.ts +4 -0
  143. package/dist/types/components/pds-table/pds-table-cell/pds-table-cell.d.ts +3 -0
  144. package/dist/types/components/pds-text/pds-text.d.ts +1 -0
  145. package/dist/types/components.d.ts +47 -32
  146. package/dist/types/utils/truncation-tooltip.d.ts +15 -2
  147. package/dist/vscode.html-data.json +11 -4
  148. package/hydrate/index.js +698 -253
  149. package/hydrate/index.mjs +698 -253
  150. package/package.json +2 -2
  151. package/dist/esm-es5/truncation-tooltip-_902ENWC.js +0 -1
  152. package/dist/pine-core/p-01c9b8f3.entry.js +0 -1
  153. package/dist/pine-core/p-258d5e83.entry.js +0 -1
  154. package/dist/pine-core/p-3c27088f.system.entry.js +0 -1
  155. package/dist/pine-core/p-4849fda7.entry.js +0 -1
  156. package/dist/pine-core/p-4de8f333.entry.js +0 -1
  157. package/dist/pine-core/p-550c2fd3.entry.js +0 -1
  158. package/dist/pine-core/p-6bf853c9.entry.js +0 -1
  159. package/dist/pine-core/p-6d3610f9.entry.js +0 -1
  160. package/dist/pine-core/p-73eb47fa.entry.js +0 -1
  161. package/dist/pine-core/p-7f367db4.system.entry.js +0 -1
  162. package/dist/pine-core/p-84e9b7da.entry.js +0 -1
  163. package/dist/pine-core/p-9a0083dd.system.entry.js +0 -1
  164. package/dist/pine-core/p-CnM3cCof.js +0 -1
  165. package/dist/pine-core/p-a3735199.entry.js +0 -1
  166. package/dist/pine-core/p-a85a6ab9.system.entry.js +0 -1
  167. package/dist/pine-core/p-cf08a6dd.system.entry.js +0 -1
  168. package/dist/pine-core/p-da103a54.system.entry.js +0 -1
  169. package/dist/pine-core/p-e800a2b1.entry.js +0 -1
  170. package/dist/pine-core/p-eb5465ce.entry.js +0 -1
  171. package/dist/pine-core/p-ec5428fb.entry.js +0 -1
  172. package/dist/pine-core/p-ed4b979e.entry.js +0 -1
  173. package/dist/pine-core/p-f1f17940.entry.js +0 -2
  174. package/dist/pine-core/p-f25e4731.system.entry.js +0 -1
@@ -249,9 +249,13 @@
249
249
  transition: background 0.15s;
250
250
  }
251
251
  .pds-multiselect__option pds-checkbox {
252
+ min-width: var(--pine-dimension-none);
252
253
  pointer-events: none;
253
254
  width: 100%;
254
255
  }
256
+ .pds-multiselect__option pds-chip {
257
+ pointer-events: auto;
258
+ }
255
259
  .pds-multiselect__option:hover:not(.pds-multiselect__option--disabled), .pds-multiselect__option.pds-multiselect__option--highlighted:not(.pds-multiselect__option--disabled) {
256
260
  background: var(--pine-color-background-muted);
257
261
  }
@@ -345,6 +345,11 @@ export class PdsMultiselect {
345
345
  e.preventDefault(); // Prevent focus change
346
346
  this.toggleOption(option);
347
347
  };
348
+ // mousedown already toggled the option. Without this, a click on the chip reaches the
349
+ // checkbox through its label and toggles it a second time.
350
+ this.handleOptionClick = (e) => {
351
+ e.preventDefault();
352
+ };
348
353
  this.handleOptionMouseEnter = (index, option) => () => {
349
354
  if (option.disabled)
350
355
  return;
@@ -403,6 +408,18 @@ export class PdsMultiselect {
403
408
  this.internals = this.el.attachInternals();
404
409
  }
405
410
  }
411
+ /**
412
+ * Form Associated Custom Elements API: Called when the form is disabled
413
+ */
414
+ formDisabledCallback(disabled) {
415
+ // Also fires when this element's own `disabled` attribute is merely present, even as the
416
+ // literal string "false" (a consumer's or React's attribute serialization can write that) —
417
+ // the platform treats any value as disabled, independent of fieldset state. A real disabled
418
+ // fieldset ancestor confirms this is genuinely that, not this element's own attribute.
419
+ if (disabled && !this.el.closest('fieldset[disabled]'))
420
+ return;
421
+ this.disabled = disabled;
422
+ }
406
423
  componentWillLoad() {
407
424
  this.originalSearchEmitter = this.pdsMultiselectSearch;
408
425
  this.syncSelectedItems();
@@ -501,8 +518,20 @@ export class PdsMultiselect {
501
518
  var _a;
502
519
  (_a = this.slottedTriggerEl) === null || _a === void 0 ? void 0 : _a.setAttribute('aria-expanded', String(this.isOpen));
503
520
  }
504
- disabledChanged() {
521
+ disabledChanged(disabled) {
522
+ var _a, _b;
505
523
  this.syncSlottedTrigger();
524
+ // A disabled control can't stay open, or its options could still be toggled.
525
+ if (!disabled || !this.isOpen)
526
+ return;
527
+ const activeElement = document.activeElement;
528
+ const focusInside = !!(((_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(activeElement)) || this.el.contains(activeElement));
529
+ this.closeDropdown();
530
+ // A disabled built-in trigger can't take focus back (falls to <body>, as natively); a slotted
531
+ // trigger without its own disabled property only gets aria-disabled and stays focusable, so
532
+ // focus would otherwise stay stranded on the closed panel's former content.
533
+ if (focusInside)
534
+ (_b = this.activeTriggerEl) === null || _b === void 0 ? void 0 : _b.focus();
506
535
  }
507
536
  /**
508
537
  * Sets focus on the trigger button.
@@ -512,7 +541,8 @@ export class PdsMultiselect {
512
541
  (_a = this.activeTriggerEl) === null || _a === void 0 ? void 0 : _a.focus();
513
542
  }
514
543
  /**
515
- * Clears all selected values and resets the component.
544
+ * Clears all selected values and resets the component. Works while disabled too, as setting a
545
+ * native control's value from script does.
516
546
  */
517
547
  async clear() {
518
548
  const hadValues = this.value.length > 0 || this.searchQuery !== '';
@@ -535,11 +565,12 @@ export class PdsMultiselect {
535
565
  }
536
566
  /**
537
567
  * Handle global keyboard events for accessibility.
538
- * Closes dropdown on Escape key press regardless of focus location.
568
+ * Closes dropdown on Escape key press regardless of focus location. Taken in document's capture
569
+ * phase, before a modal around the multiselect hears it on document and closes too.
539
570
  */
540
571
  handleWindowKeyDown(event) {
541
572
  var _a;
542
- if (!this.isOpen)
573
+ if (!this.isOpen || event.defaultPrevented)
543
574
  return;
544
575
  if (event.key === 'Escape') {
545
576
  event.preventDefault();
@@ -1147,7 +1178,7 @@ export class PdsMultiselect {
1147
1178
  'pds-multiselect__option--selected': isSelected,
1148
1179
  'pds-multiselect__option--create': isCreateOption,
1149
1180
  'pds-multiselect__option--disabled': isDisabled || isCreateDisabled,
1150
- }, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": isDisabled || isCreateDisabled ? 'true' : undefined, "aria-label": isCreateOption ? formatMessage(this.createOptionAriaLabel, { text: option.text }) : undefined, "aria-describedby": hasAction ? `${optionId}-action-description` : undefined, "data-index": index, onMouseDown: this.handleOptionMouseDown(option), onMouseEnter: this.handleOptionMouseEnter(index, option) }, isCreateOption ? (h("pds-box", { class: "pds-multiselect__create-option", "align-items": "center", gap: "xs" }, h("pds-icon", { name: "add", size: "small" }), h("pds-text", null, formatMessage(this.createOptionLabel, { text: option.text })))) : (h("pds-checkbox", { componentId: `${this.componentId}-checkbox-${index}`, checked: isSelected, label: option.text, disabled: isDisabled, style: { pointerEvents: 'none' } }, this.optionDisplay === 'chip' && (h("pds-chip", { slot: "label", sentiment: "subtle", dot: !!option.dotColor, "dot-color": option.dotColor }, option.text)))), hasAction && this.renderOptionAction(option, optionId, isHighlighted)));
1181
+ }, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": isDisabled || isCreateDisabled ? 'true' : undefined, "aria-label": isCreateOption ? formatMessage(this.createOptionAriaLabel, { text: option.text }) : undefined, "aria-describedby": hasAction ? `${optionId}-action-description` : undefined, "data-index": index, onMouseDown: this.handleOptionMouseDown(option), onClick: this.handleOptionClick, onMouseEnter: this.handleOptionMouseEnter(index, option) }, isCreateOption ? (h("pds-box", { class: "pds-multiselect__create-option", "align-items": "center", gap: "xs" }, h("pds-icon", { name: "add", size: "small" }), h("pds-text", null, formatMessage(this.createOptionLabel, { text: option.text })))) : (h("pds-checkbox", { componentId: `${this.componentId}-checkbox-${index}`, checked: isSelected, label: option.text, disabled: isDisabled, style: { pointerEvents: 'none' } }, this.optionDisplay === 'chip' && (h("pds-chip", { slot: "label", sentiment: "subtle", dot: !!option.dotColor, "dot-color": option.dotColor, "max-width": "100%" }, option.text)))), hasAction && this.renderOptionAction(option, optionId, isHighlighted)));
1151
1182
  }
1152
1183
  renderOptionAction(option, optionId, isHighlighted) {
1153
1184
  var _a;
@@ -1229,10 +1260,10 @@ export class PdsMultiselect {
1229
1260
  }
1230
1261
  render() {
1231
1262
  const hasSelections = this.selectedItems.length > 0;
1232
- return (h(Host, { key: '0ef6791666063e0d951d28f980b3bca89cf24287', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: 'f0ccbabfbd2dcf38f6df52f73f2152eb4bd2828e', class: "pds-multiselect", onFocusout: this.handleContainerFocusOut }, this.label && (h("label", { key: '88e01c744644ce1f75c8d5b71dfaeeb79d1ef7df', id: `${this.componentId}-label`, htmlFor: this.componentId, class: {
1263
+ return (h(Host, { key: 'a7806379c53598d41af91be63ee5bd300cc87755', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: '0213d40953f1735b84c038e0e0afd1bc289d45ad', class: "pds-multiselect", onFocusout: this.handleContainerFocusOut }, this.label && (h("label", { key: 'fa91c2337cdc9f5dea62173aeaa6b56e118a1316', id: `${this.componentId}-label`, htmlFor: this.componentId, class: {
1233
1264
  'pds-multiselect__label': true,
1234
1265
  'visually-hidden': this.hideLabel,
1235
- } }, this.label)), h("div", { key: '0bf4a3b1378ff18e6d6b449507ebbae1bfb279e4', class: "pds-multiselect__wrapper", ref: el => (this.containerEl = el), style: { width: this.triggerWidth } }, this.slottedTriggerEl ? (h("slot", { name: "trigger" })) : this.selectedDisplay === 'pill' && this.pillPosition === 'inline' ? (h("div", { ref: el => (this.pillInlineTriggerEl = el || undefined), part: "trigger", class: {
1266
+ } }, this.label)), h("div", { key: '54209b3edfb3583ab1bcecd2b1df973955abfcc3', class: "pds-multiselect__wrapper", ref: el => (this.containerEl = el), style: { width: this.triggerWidth } }, this.slottedTriggerEl ? (h("slot", { name: "trigger" })) : this.selectedDisplay === 'pill' && this.pillPosition === 'inline' ? (h("div", { ref: el => (this.pillInlineTriggerEl = el || undefined), part: "trigger", class: {
1236
1267
  'pds-multiselect__trigger': true,
1237
1268
  'pds-multiselect__trigger--open': this.isOpen,
1238
1269
  'pds-multiselect__trigger--disabled': this.disabled,
@@ -1248,7 +1279,7 @@ export class PdsMultiselect {
1248
1279
  }, 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: {
1249
1280
  'pds-multiselect__trigger-text': true,
1250
1281
  'pds-multiselect__trigger-text--placeholder': !hasSelections || (this.selectedDisplay === 'pill' && this.pillPosition === 'below'),
1251
- } }, this.getTriggerText()), h("pds-icon", { "aria-hidden": "true", class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: '5202a263b219d06891bda739f98db0162bf33c48', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: '47f7b55863c5b72d41c4ef1893b9364988fc0b56', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: '3930dc30b2df7179d178873c470aa1da0f6f258c', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'e31d55db3fd0173c56faa23e34e0be92371983d4', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: 'b3326cc1a5e5886be05327a066e0a7ddd36ccefc', style: { display: 'none' } }, h("slot", { key: '91559cb9510abce6084348a17516460fd8545ef7' })))));
1282
+ } }, this.getTriggerText()), h("pds-icon", { "aria-hidden": "true", class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: 'e3c1bb5c484d851b332e994cd2a528ae95cbfc4d', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: '2009f6487118252ef1ec14170ddd0c6853ad279f', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: 'c740f4845ff0c1ccff4633810c1d9d92fb2e8a78', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'b2406ab3b0957a440593b4b986c98476258349be', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: '6d2db6563864c71ab92ed9a8d4133efca23b1c55', style: { display: 'none' } }, h("slot", { key: '2af0e0a7e2410b9850fd15ef524fb388c32dc320' })))));
1252
1283
  }
1253
1284
  static get is() { return "pds-multiselect"; }
1254
1285
  static get encapsulation() { return "shadow"; }
@@ -2439,7 +2470,7 @@ export class PdsMultiselect {
2439
2470
  "return": "Promise<void>"
2440
2471
  },
2441
2472
  "docs": {
2442
- "text": "Clears all selected values and resets the component.",
2473
+ "text": "Clears all selected values and resets the component. Works while disabled too, as setting a\nnative control's value from script does.",
2443
2474
  "tags": []
2444
2475
  }
2445
2476
  },
@@ -2488,8 +2519,8 @@ export class PdsMultiselect {
2488
2519
  return [{
2489
2520
  "name": "keydown",
2490
2521
  "method": "handleWindowKeyDown",
2491
- "target": "window",
2492
- "capture": false,
2522
+ "target": "document",
2523
+ "capture": true,
2493
2524
  "passive": false
2494
2525
  }];
2495
2526
  }
@@ -1,9 +1,19 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { containsComposed } from "../../utils/closest";
2
+ import { closest, containsComposed } from "../../utils/closest";
3
3
  import { restoreReflectedDefault } from "../../utils/reflected-attribute-default";
4
4
  import { setAttributesIfChanged } from "../../utils/attributes";
5
5
  import { cssEscape } from "../../utils/css";
6
6
  import { limitRestores } from "../../utils/keep-hydrated";
7
+ /** Open auto popovers, in the order they opened: Escape goes to the last one it applies to. */
8
+ const openAutoPopovers = [];
9
+ /** The focused element, followed down through shadow roots to the control that has focus. */
10
+ function deepActiveElement() {
11
+ var _a;
12
+ let active = document.activeElement;
13
+ while ((_a = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement)
14
+ active = active.shadowRoot.activeElement;
15
+ return active;
16
+ }
7
17
  /**
8
18
  * @slot trigger - The trigger element for the popover
9
19
  * @slot (default) - The content to display inside the popover
@@ -36,7 +46,7 @@ export class PdsPopover {
36
46
  */
37
47
  this.triggerObserver = null;
38
48
  /**
39
- * Portal element rendered in document.body
49
+ * Portal element: in document.body, or in the open dialog the popover is in
40
50
  */
41
51
  this.portalEl = null;
42
52
  /**
@@ -132,6 +142,26 @@ export class PdsPopover {
132
142
  break;
133
143
  }
134
144
  };
145
+ /** The focus style copied into a shadow root the panel opened in, which `document.head` can't reach. */
146
+ this.shadowFocusStyle = null;
147
+ /** The dialog the panel was opened in, closed along with it. */
148
+ this.watchedDialog = null;
149
+ this.onDialogClose = () => {
150
+ this.hide();
151
+ };
152
+ /**
153
+ * Inside a dialog, the panel can sit in a form that wraps the dialog, which a body portal never
154
+ * did. A submit from the panel (a button in it, or Enter in a field in it) is stopped, so the
155
+ * panel behaves as it does in the body.
156
+ */
157
+ this.handleSubmitFromPanel = (event) => {
158
+ if (!this.portalEl || !containsComposed(event.target, this.portalEl))
159
+ return;
160
+ if (containsComposed(this.portalEl, event.submitter) || containsComposed(this.portalEl, deepActiveElement())) {
161
+ event.preventDefault();
162
+ event.stopPropagation();
163
+ }
164
+ };
135
165
  }
136
166
  restorePlacementDefault(newValue) {
137
167
  this.placement = restoreReflectedDefault(this.el, 'placement', newValue, 'right');
@@ -194,19 +224,23 @@ export class PdsPopover {
194
224
  (_a = this.triggerEl) === null || _a === void 0 ? void 0 : _a.addEventListener('click', this.handleTriggerClick);
195
225
  this.observeTrigger();
196
226
  this.linkTriggerToPortal();
197
- // Still open after a move: the trigger moved, so the portal follows it.
227
+ // Still open after a move: the trigger moved, so the portal follows it, into the dialog it
228
+ // is in now, if any.
198
229
  if (this.active) {
230
+ this.placePortal();
199
231
  requestAnimationFrame(() => this.handlePopoverPositioning());
200
232
  }
201
233
  }
202
234
  disconnectedCallback() {
203
235
  var _a;
204
236
  // Moved in one operation (a DOM morph, or a framework reparenting it), the popover is
205
- // already back in the page. Its portal is in <body>, untouched, so it stays open, with focus
206
- // where it was.
237
+ // already back in the page. Its portal is outside the popover, so it stays open, with focus
238
+ // where it was; connectedCallback moves it to follow the popover.
207
239
  if (this.el.isConnected)
208
240
  return;
209
241
  this.isComponentMounted = false;
242
+ this.unwatchDialogClose();
243
+ this.forgetOpen();
210
244
  // Open, the content sits in the portal; put it back before the portal goes. Only listeners on
211
245
  // the popover itself hear the close event now, but those are the ones mirroring its state.
212
246
  if (this.active) {
@@ -227,6 +261,7 @@ export class PdsPopover {
227
261
  // Clean up all event listeners
228
262
  this.removeLightDismissListeners();
229
263
  this.removeScrollAndResizeListeners();
264
+ document.removeEventListener('submit', this.handleSubmitFromPanel, true);
230
265
  // Clear any pending debounce timers
231
266
  this.clearDebounceTimers();
232
267
  // Remove portal from DOM
@@ -271,9 +306,6 @@ export class PdsPopover {
271
306
  else {
272
307
  this.portalEl.id = `${this.componentId}-portal`;
273
308
  }
274
- // Add accessibility attributes for screen readers
275
- // Note: Native Popover API doesn't add a specific role, keeping semantic HTML
276
- this.portalEl.setAttribute('aria-modal', 'false'); // Not a modal, can interact with rest of page
277
309
  // Append to body
278
310
  document.body.appendChild(this.portalEl);
279
311
  // Add global focus styles to match Pine design system
@@ -357,7 +389,27 @@ export class PdsPopover {
357
389
  // Clear tracking array
358
390
  this.movedNodes = [];
359
391
  }
392
+ copyFocusStylesInto(root) {
393
+ var _a, _b, _c;
394
+ // Outside a shadow root the document's own style applies, so drop a copy left in one.
395
+ if (!(root instanceof ShadowRoot)) {
396
+ (_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
397
+ this.shadowFocusStyle = null;
398
+ return;
399
+ }
400
+ if (((_b = this.shadowFocusStyle) === null || _b === void 0 ? void 0 : _b.parentNode) === root || !this.portalEl)
401
+ return;
402
+ const source = document.querySelector(`style[data-pds-popover-focus="${cssEscape(this.portalEl.id)}"]`);
403
+ if (!source)
404
+ return;
405
+ (_c = this.shadowFocusStyle) === null || _c === void 0 ? void 0 : _c.remove();
406
+ this.shadowFocusStyle = source.cloneNode(true);
407
+ root.appendChild(this.shadowFocusStyle);
408
+ }
360
409
  removePortal() {
410
+ var _a;
411
+ (_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
412
+ this.shadowFocusStyle = null;
361
413
  if (this.portalEl) {
362
414
  // Remove the portal element from DOM
363
415
  if (this.portalEl.parentNode) {
@@ -382,9 +434,13 @@ export class PdsPopover {
382
434
  // Record open timestamp to prevent immediate close from opening click
383
435
  this.openTimestamp = Date.now();
384
436
  this.linkTriggerToPortal();
437
+ this.placePortal();
385
438
  // Update portal content with latest slot content
386
439
  this.updatePortalContent();
387
- // Show portal
440
+ // Show portal. The attribute tells a modal around it that this popover takes Escape first; only
441
+ // an auto popover listens for Escape.
442
+ if (this.popoverType === 'auto')
443
+ this.portalEl.setAttribute('data-pds-popover-open', '');
388
444
  this.portalEl.style.display = 'block';
389
445
  this.portalEl.style.opacity = '1';
390
446
  this.portalEl.style.visibility = 'visible';
@@ -396,8 +452,10 @@ export class PdsPopover {
396
452
  });
397
453
  // Add scroll and resize listeners for repositioning (always)
398
454
  this.addScrollAndResizeListeners();
455
+ document.addEventListener('submit', this.handleSubmitFromPanel, true);
399
456
  // Add document listeners for light dismiss and escape key (auto type only)
400
457
  if (this.popoverType === 'auto') {
458
+ openAutoPopovers.push(this);
401
459
  this.addLightDismissListeners();
402
460
  }
403
461
  // Emit open event
@@ -413,12 +471,16 @@ export class PdsPopover {
413
471
  if (!this.active || !this.portalEl)
414
472
  return;
415
473
  this.active = false;
416
- // Restoring the content drops its focus to the body, so check where focus is first.
417
- const focusWasInside = this.portalEl.contains(document.activeElement);
474
+ this.unwatchDialogClose();
475
+ // Restoring the content drops its focus to the body, so check where focus is first. In a
476
+ // shadow root, document.activeElement is only its host.
477
+ const focusWasInside = containsComposed(this.portalEl, deepActiveElement());
418
478
  this.linkTriggerToPortal();
419
479
  // Restore content back to original slot positions
420
480
  this.restorePortalContent();
421
- // Hide portal
481
+ // Hide portal. The dark-mode border set in a shadow root is worked out again on the next open.
482
+ this.portalEl.style.border = '';
483
+ this.portalEl.removeAttribute('data-pds-popover-open');
422
484
  this.portalEl.style.display = 'none';
423
485
  this.portalEl.style.opacity = '0';
424
486
  this.portalEl.style.visibility = 'hidden';
@@ -428,8 +490,10 @@ export class PdsPopover {
428
490
  this.returnFocusToTrigger();
429
491
  }
430
492
  // Remove all listeners
493
+ this.forgetOpen();
431
494
  this.removeLightDismissListeners();
432
495
  this.removeScrollAndResizeListeners();
496
+ document.removeEventListener('submit', this.handleSubmitFromPanel, true);
433
497
  // Clear any pending timers
434
498
  this.clearDebounceTimers();
435
499
  // Emit close event
@@ -449,6 +513,59 @@ export class PdsPopover {
449
513
  this.show();
450
514
  }
451
515
  }
516
+ /**
517
+ * Puts the panel where it shows above everything around the popover. In an open dialog, it goes
518
+ * inside it: a modal dialog sits in the top layer above the body and makes the rest of the page
519
+ * inert, and a non-modal one sits above it by z-index. Right after the popover, it's next in the
520
+ * Tab order. In another component's slot, though, it would have no slot to render in, and in a
521
+ * form its buttons would submit it, so there it goes at the end of the dialog.
522
+ */
523
+ placePortal() {
524
+ var _a, _b;
525
+ if (!this.portalEl)
526
+ return;
527
+ const dialog = closest('dialog[open]', this.el);
528
+ if (!dialog) {
529
+ this.unwatchDialogClose();
530
+ this.portalEl.style.border = '';
531
+ if (this.portalEl.parentElement !== document.body)
532
+ document.body.appendChild(this.portalEl);
533
+ this.copyFocusStylesInto(document);
534
+ return;
535
+ }
536
+ const form = closest('form', this.el);
537
+ const besidePopover = !((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.shadowRoot) && !(form && containsComposed(dialog, form));
538
+ if (besidePopover) {
539
+ if (this.el.nextElementSibling !== this.portalEl)
540
+ (_b = this.el.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(this.portalEl, this.el.nextSibling);
541
+ }
542
+ else if (this.portalEl.parentNode !== dialog) {
543
+ dialog.appendChild(this.portalEl);
544
+ }
545
+ this.watchDialogClose(dialog);
546
+ const root = this.portalEl.getRootNode();
547
+ this.copyFocusStylesInto(root);
548
+ // In a shadow root, the copied dark-mode rule can't see a [data-theme="dark"] on the page.
549
+ this.portalEl.style.border = root instanceof ShadowRoot && closest('[data-theme="dark"]', this.el) ? 'var(--pine-border)' : '';
550
+ }
551
+ forgetOpen() {
552
+ const index = openAutoPopovers.indexOf(this);
553
+ if (index >= 0)
554
+ openAutoPopovers.splice(index, 1);
555
+ }
556
+ /**
557
+ * Whether an Escape is this popover's. One from a dialog the popover isn't in belongs to that
558
+ * dialog when it's above it: a top-layer dialog or a pds-modal. A plain non-modal dialog inside
559
+ * the popover's modal doesn't close on Escape, so the popover takes it.
560
+ */
561
+ takesEscapeFrom(event) {
562
+ var _a, _b;
563
+ const origin = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
564
+ const dialog = closest('dialog[open]', origin);
565
+ if (!dialog || containsComposed(dialog, this.portalEl))
566
+ return true;
567
+ return !(dialog.classList.contains('pds-modal__backdrop') || dialog.matches(':modal'));
568
+ }
452
569
  /**
453
570
  * Adds light dismiss listeners (click outside and escape key)
454
571
  */
@@ -457,6 +574,19 @@ export class PdsPopover {
457
574
  document.addEventListener('click', this.boundClickOutsideHandler, true);
458
575
  document.addEventListener('keydown', this.boundEscapeKeyHandler);
459
576
  }
577
+ /** Closes the popover when the dialog it opened in closes, so it isn't left open inside. */
578
+ watchDialogClose(dialog) {
579
+ if (this.watchedDialog === dialog)
580
+ return;
581
+ this.unwatchDialogClose();
582
+ this.watchedDialog = dialog;
583
+ dialog.addEventListener('close', this.onDialogClose);
584
+ }
585
+ unwatchDialogClose() {
586
+ var _a;
587
+ (_a = this.watchedDialog) === null || _a === void 0 ? void 0 : _a.removeEventListener('close', this.onDialogClose);
588
+ this.watchedDialog = null;
589
+ }
460
590
  /**
461
591
  * Removes light dismiss listeners
462
592
  */
@@ -482,7 +612,7 @@ export class PdsPopover {
482
612
  * Handles clicks outside the popover for light dismiss (auto type only)
483
613
  */
484
614
  handleClickOutside(event) {
485
- var _a, _b, _c, _d;
615
+ var _a, _b;
486
616
  // Ignore events that occurred at or before the popover opened
487
617
  // This prevents the opening click from immediately closing the popover
488
618
  // Convert event.timeStamp (DOMHighResTimeStamp from performance.now()) to epoch time
@@ -493,16 +623,18 @@ export class PdsPopover {
493
623
  if (eventTime <= this.openTimestamp) {
494
624
  return;
495
625
  }
496
- const target = event.target;
626
+ // In a shadow root, event.target is only its host.
627
+ const target = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
497
628
  // A datepicker's calendar is portaled to the body: a click in the calendar of a datepicker
498
- // inside this popover, in its content or its trigger, isn't outside it.
499
- const calendar = (_b = (_a = target).closest) === null || _b === void 0 ? void 0 : _b.call(_a, '.pds-datepicker-calendar-portal');
629
+ // inside this popover, in its content or its trigger, isn't outside it. The target can be
630
+ // inside the calendar's shadow root, so look up across it.
631
+ const calendar = closest('.pds-datepicker-calendar-portal', target);
500
632
  const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
501
633
  if (owner && (containsComposed(this.portalEl, owner) || containsComposed(this.triggerEl, owner)))
502
634
  return;
503
635
  // Check if click is outside both the popover portal and the trigger
504
- const clickedInsidePopover = (_c = this.portalEl) === null || _c === void 0 ? void 0 : _c.contains(target);
505
- const clickedInsideTrigger = (_d = this.triggerEl) === null || _d === void 0 ? void 0 : _d.contains(target);
636
+ const clickedInsidePopover = containsComposed(this.portalEl, target);
637
+ const clickedInsideTrigger = containsComposed(this.triggerEl, target);
506
638
  if (!clickedInsidePopover && !clickedInsideTrigger) {
507
639
  this.hide();
508
640
  }
@@ -523,14 +655,19 @@ export class PdsPopover {
523
655
  * Mirrors native Popover API: Escape closes and returns focus to trigger
524
656
  */
525
657
  handleEscapeKey(event) {
526
- if (event.key === 'Escape') {
527
- // Prevent default Escape behavior and stop propagation
528
- // This mirrors native Popover API which handles Escape exclusively
529
- event.preventDefault();
530
- event.stopPropagation();
531
- // Close popover and return focus to trigger
532
- this.hide();
533
- }
658
+ // A control inside that closes on Escape (a datepicker, a combobox) has handled it already.
659
+ if (event.key !== 'Escape' || event.defaultPrevented)
660
+ return;
661
+ // Like the native Popover API, Escape closes only the top popover: the last one opened that
662
+ // it applies to. Every open popover hears it, so each checks whether it's that one.
663
+ const top = [...openAutoPopovers].reverse().find(popover => popover.takesEscapeFrom(event));
664
+ if (top !== this)
665
+ return;
666
+ // Take the key, so the dialog or modal around it doesn't close too.
667
+ event.preventDefault();
668
+ event.stopPropagation();
669
+ // Close popover and return focus to trigger
670
+ this.hide();
534
671
  }
535
672
  /**
536
673
  * Handles scroll events to reposition the popover (debounced for performance)
@@ -635,13 +772,20 @@ export class PdsPopover {
635
772
  }
636
773
  this.portalEl.style.top = `${top}px`;
637
774
  this.portalEl.style.left = `${left}px`;
775
+ // `position: fixed` measures from the viewport unless an ancestor becomes its containing block,
776
+ // as a modal dialog does with its backdrop filter. Shift by however far it landed from the spot.
777
+ const placed = this.portalEl.getBoundingClientRect();
778
+ if (Math.abs(placed.top - top) > 0.5 || Math.abs(placed.left - left) > 0.5) {
779
+ this.portalEl.style.top = `${2 * top - placed.top}px`;
780
+ this.portalEl.style.left = `${2 * left - placed.left}px`;
781
+ }
638
782
  // Reset the repositioning guard after a short delay
639
783
  setTimeout(() => {
640
784
  this.isRepositioning = false;
641
785
  }, 16); // ~1 frame at 60fps
642
786
  }
643
787
  render() {
644
- return (h(Host, { key: 'd804db8c73e0dc2acf0d1bbca20edb77993ff7fd', id: this.componentId }, h("span", { key: '5408d1856c9b13b327ea13b43cffc23af925a82f', class: "pds-popover__trigger-wrapper" }, h("slot", { key: '9d0ff01292c67bdaa88d49114162c3c65ff8a20d', name: "trigger", onSlotchange: this.handleTriggerSlotChange })), h("div", { key: 'cdd38016453ea1838d5718fb8e190cd4304ac8cc', class: "pds-popover__content-slot-wrapper" }, h("slot", { key: '9faf60d7be7a2ff3c5fe6c3e4de374bafadf848a', onSlotchange: this.handleContentSlotChange }))));
788
+ return (h(Host, { key: 'da8a0c715df1199231b1265085f3f9ae0234032d', id: this.componentId }, h("span", { key: 'f35023492399420829cec2e88556462f5ac1663e', class: "pds-popover__trigger-wrapper" }, h("slot", { key: '38ebe92eebb87665467b3f92ff94dc8095450063', name: "trigger", onSlotchange: this.handleTriggerSlotChange })), h("div", { key: '8917930f4520544d14bbd68b4c7936dd60af19e3', class: "pds-popover__content-slot-wrapper" }, h("slot", { key: '28d3f9112256edd95721a79a7072a9e35a3712bf', onSlotchange: this.handleContentSlotChange }))));
645
789
  }
646
790
  static get is() { return "pds-popover"; }
647
791
  static get encapsulation() { return "shadow"; }
@@ -181,6 +181,7 @@ label:has(input:disabled) {
181
181
  column-gap: var(--pine-dimension-xs);
182
182
  display: flex;
183
183
  flex: 1;
184
+ flex-direction: row;
184
185
  padding: var(--pine-dimension-md);
185
186
  }
186
187
  @media (max-width: 767px) {
@@ -235,6 +236,11 @@ label:has(input:disabled) {
235
236
  object-fit: cover;
236
237
  width: 100%;
237
238
  }
239
+ :host(.has-image) .pds-radio__content-wrapper {
240
+ flex: 1;
241
+ min-width: 0;
242
+ overflow-wrap: anywhere;
243
+ }
238
244
  :host(.has-image) .pds-radio__message {
239
245
  grid-area: message;
240
246
  margin-block-start: 0;
@@ -51,23 +51,23 @@ export class PdsRow {
51
51
  }
52
52
  render() {
53
53
  const rowClasses = `
54
- ${this.alignItems !== undefined && this.alignItems.trim() !== '' ? `pds-align-items-${this.alignItems}` : ''}
54
+ ${this.alignItems != null && this.alignItems.trim() !== '' ? `pds-align-items-${this.alignItems}` : ''}
55
55
  ${this.border ? 'pds-row--border' : ''}
56
- ${this.justifyContent !== undefined && this.justifyContent.trim() !== '' ? `pds-justify-content-${this.justifyContent}` : ''}
56
+ ${this.justifyContent != null && this.justifyContent.trim() !== '' ? `pds-justify-content-${this.justifyContent}` : ''}
57
57
  ${this.noWrap ? 'pds-row--no-wrap' : ''}
58
58
  `;
59
59
  const rowInlineStyles = Object.assign(Object.assign(Object.assign(Object.assign({}, (this.colGap && {
60
- '--row-gap-x': this.colGap !== undefined && this.colGap.trim() !== '' ? this.colGapMap[this.colGap] : '',
61
- '--row-gap-y': this.colGap !== undefined && this.colGap.trim() !== '' ? this.colGapMap[this.colGap] : '',
60
+ '--row-gap-x': this.colGap != null && this.colGap.trim() !== '' ? this.colGapMap[this.colGap] : '',
61
+ '--row-gap-y': this.colGap != null && this.colGap.trim() !== '' ? this.colGapMap[this.colGap] : '',
62
62
  })), (this.colGapBlock && {
63
- '--row-gap-y': this.colGapBlock !== undefined && this.colGapBlock.trim() !== '' ? this.colGapMap[this.colGapBlock] : '',
63
+ '--row-gap-y': this.colGapBlock != null && this.colGapBlock.trim() !== '' ? this.colGapMap[this.colGapBlock] : '',
64
64
  })), (this.colGapInline && {
65
- '--row-gap-x': this.colGapInline !== undefined && this.colGapInline.trim() !== '' ? this.colGapMap[this.colGapInline] : '',
65
+ '--row-gap-x': this.colGapInline != null && this.colGapInline.trim() !== '' ? this.colGapMap[this.colGapInline] : '',
66
66
  })), (this.minHeight && {
67
67
  'min-height': this.minHeight,
68
68
  }));
69
69
  this.hostKeeper.record(`pds-row ${rowClasses}`, rowInlineStyles);
70
- return h(Host, { key: '78a505fef7132f9545916155d2485a6d2df8f4a5', class: `pds-row ${rowClasses}`, style: rowInlineStyles });
70
+ return h(Host, { key: '452882c1105868f5d392e7cb165311b1abc4a243', class: `pds-row ${rowClasses}`, style: rowInlineStyles });
71
71
  }
72
72
  static get is() { return "pds-row"; }
73
73
  static get originalStyleUrls() {
@@ -93,6 +93,18 @@ export class PdsSwitch {
93
93
  this.checked = state === (this.value || 'on');
94
94
  }
95
95
  }
96
+ /**
97
+ * Form Associated Custom Elements API: Called when the form is disabled
98
+ */
99
+ formDisabledCallback(disabled) {
100
+ // Also fires when this element's own `disabled` attribute is merely present, even as the
101
+ // literal string "false" (a consumer's or React's attribute serialization can write that) —
102
+ // the platform treats any value as disabled, independent of fieldset state. A real disabled
103
+ // fieldset ancestor confirms this is genuinely that, not this element's own attribute.
104
+ if (disabled && !this.el.closest('fieldset[disabled]'))
105
+ return;
106
+ this.disabled = disabled;
107
+ }
96
108
  componentWillLoad() {
97
109
  this.inheritedAttributes = Object.assign({}, inheritAriaAttributes(this.el));
98
110
  this.updateHasLabelSlot();
@@ -101,9 +113,9 @@ export class PdsSwitch {
101
113
  const hostClass = this.switchClassNames();
102
114
  const ariaDisabled = this.disabled ? 'true' : null;
103
115
  this.hostKeeper.record(hostClass, {}, { 'aria-disabled': ariaDisabled });
104
- return (h(Host, { key: 'ee8576e523348ff9eed1b6087626849bb0966608', class: hostClass, "aria-disabled": ariaDisabled }, h("label", { key: '09433b5356d718be65f4f2eb61f35fff1d000e10', htmlFor: this.componentId }, h("input", Object.assign({ key: 'f996a0fad56119674cfb7d95e1444bf411b64396', "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: '4b23305d3cc0f5b37b23c6b79a14cfba57c16816', class: this.hideLabel ? 'visually-hidden' : '' }, h("slot", { key: '258b5ccf0d4b01518df3a37772d694cb37569ffa', name: "label", onSlotchange: this.updateHasLabelSlot }), !this.hasLabelSlot && this.label)), this.helperMessage &&
105
- h("div", { key: 'c8196fa2ce832de3a8c6d987a78fd65d791c4c59', class: `pds-switch__message`, id: messageId(this.componentId, 'helper') }, this.helperMessage), this.errorMessage &&
106
- h("div", { key: '948894dd2e642689af6cad545a0b31f7c4711d87', class: `pds-switch__message pds-switch__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: 'd4b72b49bfd38a396b8f7c0686e1b2ef92d65491', icon: danger, size: "small" }), this.errorMessage)));
116
+ return (h(Host, { key: 'b8bd2870be101081aa8a65cdee45397bc4c21435', class: hostClass, "aria-disabled": ariaDisabled }, h("label", { key: '1e223f22f7fc6c576098353ad67dc11500def8b4', htmlFor: this.componentId }, h("input", Object.assign({ key: 'edf59869e165a65b97465ea9de06f7ea82fbc9a6', "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: '1c252b9455471069f8c6ea6c13f2e88c99308b41', class: this.hideLabel ? 'visually-hidden' : '' }, h("slot", { key: 'ce0d471918bd3018f5e55d0d1e6c5c2247790f81', name: "label", onSlotchange: this.updateHasLabelSlot }), !this.hasLabelSlot && this.label)), this.helperMessage &&
117
+ h("div", { key: '64874b15403f1f42344715ac34febdfb8d94042a', class: `pds-switch__message`, id: messageId(this.componentId, 'helper') }, this.helperMessage), this.errorMessage &&
118
+ h("div", { key: '560ea486859124bb0ac2f75ab4bd34b0bca7efbc', class: `pds-switch__message pds-switch__message--error`, id: messageId(this.componentId, 'error'), "aria-live": "assertive" }, h("pds-icon", { key: 'f49caaba976579eb5588e442499595c7dba7ceff', icon: danger, size: "small" }), this.errorMessage)));
107
119
  }
108
120
  static get is() { return "pds-switch"; }
109
121
  static get encapsulation() { return "shadow"; }
@@ -6,6 +6,7 @@ export class PdsTableCell {
6
6
  this.scrollContainer = null;
7
7
  this.setupRetries = 0;
8
8
  this.truncationCleanup = null;
9
+ this.hasLoaded = false;
9
10
  /**
10
11
  * Determines if the table is currently scrolling.
11
12
  * @defaultValue false
@@ -31,8 +32,23 @@ export class PdsTableCell {
31
32
  componentWillRender() {
32
33
  this.tableRef = this.hostElement.closest('pds-table');
33
34
  }
35
+ // Fires again each time the cell is moved (a sort re-appends every row), unlike componentDidLoad,
36
+ // so it re-binds what disconnectedCallback tore down. The tooltip binds to the host, which exists before load.
37
+ connectedCallback() {
38
+ if (!this.hasLoaded)
39
+ return;
40
+ this.tableRef = this.hostElement.closest('pds-table');
41
+ this.cleanupScrollListener();
42
+ if (this.needsScrollShadow) {
43
+ this.setupScrollListener();
44
+ }
45
+ if (this.truncate) {
46
+ this.initTruncationTooltip();
47
+ }
48
+ }
34
49
  componentDidLoad() {
35
- if (this.tableRef && this.tableRef.responsive && this.tableRef.fixedColumn) {
50
+ this.hasLoaded = true;
51
+ if (this.needsScrollShadow) {
36
52
  // For responsive tables with fixed columns, set up scroll detection
37
53
  // This enables the first column to show a shadow when the table is scrolled horizontally
38
54
  this.setupScrollListener();
@@ -45,6 +61,10 @@ export class PdsTableCell {
45
61
  this.cleanupScrollListener();
46
62
  this.destroyTruncationTooltip();
47
63
  }
64
+ get needsScrollShadow() {
65
+ var _a;
66
+ return Boolean(((_a = this.tableRef) === null || _a === void 0 ? void 0 : _a.responsive) && this.tableRef.fixedColumn);
67
+ }
48
68
  setupScrollListener() {
49
69
  var _a;
50
70
  if (!this.tableRef)
@@ -123,11 +143,11 @@ export class PdsTableCell {
123
143
  return classNames.join(' ');
124
144
  }
125
145
  render() {
126
- return (h(Host, { key: 'bedaeeb5723299656f872a760ed1dd80c7fe8793', class: this.classNames(), role: "gridcell", part: "cell", style: this.tableRef &&
146
+ return (h(Host, { key: 'de70a1002cc46e204f87349069b86ca43aa2129a', class: this.classNames(), role: "gridcell", part: "cell", style: this.tableRef &&
127
147
  this.tableRef.fixedColumn &&
128
148
  this.tableRef.selectable
129
149
  ? { '--fixed-cell-position': '40px' }
130
- : {} }, h("slot", { key: '45182ee3e004097660432f552780b3d27671bd46' })));
150
+ : {} }, h("slot", { key: '5e2b3308291e480323d7a1ac0575035758fb3695' })));
131
151
  }
132
152
  static get is() { return "pds-table-cell"; }
133
153
  static get encapsulation() { return "shadow"; }