@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
@@ -3,10 +3,11 @@ import { c as containsComposed, a as closest } from './closest-DHPzKMVS.js';
3
3
  import { u as unwrapReconnectedContent } from './reconnected-content-RFpTWV6r.js';
4
4
  import './keep-hydrated-BLG6RDBt.js';
5
5
 
6
- const pdsDrawerCss = () => `.pds-drawer__modal>.pds-modal__backdrop{-ms-flex-align:stretch;align-items:stretch;background-color:transparent;pointer-events:none}@supports ((-webkit-backdrop-filter: blur(3px)) or (backdrop-filter: blur(3px))){.pds-drawer__modal>.pds-modal__backdrop{-webkit-backdrop-filter:none;backdrop-filter:none}}.pds-drawer__modal>.pds-modal__backdrop[aria-modal]::before{content:none}.pds-drawer__modal>.pds-modal__backdrop>.pds-modal{border-radius:0;height:100%;margin:0;max-height:100%;max-width:100%;pointer-events:auto;width:var(--pds-drawer-width, 500px)}.pds-drawer{display:contents}.pds-drawer.pds-drawer--end .pds-drawer__modal>.pds-modal__backdrop{-ms-flex-pack:end;justify-content:flex-end}.pds-drawer.pds-drawer--start .pds-drawer__modal>.pds-modal__backdrop{-ms-flex-pack:start;justify-content:flex-start}.pds-drawer.pds-drawer--sm{--pds-drawer-width:360px}.pds-drawer.pds-drawer--md{--pds-drawer-width:500px}`;
6
+ const pdsDrawerCss = () => `.pds-drawer__modal>.pds-modal__backdrop{-ms-flex-align:stretch;align-items:stretch}.pds-drawer__modal:not(.pds-drawer__modal--modal)>.pds-modal__backdrop{background-color:transparent;pointer-events:none}@supports ((-webkit-backdrop-filter: blur(3px)) or (backdrop-filter: blur(3px))){.pds-drawer__modal:not(.pds-drawer__modal--modal)>.pds-modal__backdrop{-webkit-backdrop-filter:none;backdrop-filter:none}}.pds-drawer__modal>.pds-modal__backdrop[aria-modal]::before{content:none}.pds-drawer__modal>.pds-modal__backdrop>.pds-modal{border-radius:0;height:100%;margin:0;max-height:100%;max-width:100%;pointer-events:auto;width:var(--pds-drawer-width, 500px)}.pds-drawer{display:contents}.pds-drawer.pds-drawer--end .pds-drawer__modal>.pds-modal__backdrop{-ms-flex-pack:end;justify-content:flex-end}.pds-drawer.pds-drawer--start .pds-drawer__modal>.pds-modal__backdrop{-ms-flex-pack:start;justify-content:flex-start}.pds-drawer.pds-drawer--sm{--pds-drawer-width:360px}.pds-drawer.pds-drawer--md{--pds-drawer-width:500px}`;
7
7
 
8
- // Known selectors for content Pine components portal to document.body rather
9
- // than rendering in place — pds-popover, pds-tooltip, pds-combobox's dropdown.
8
+ // Known selectors for content Pine components portal out of place rather than
9
+ // rendering where they are — pds-tooltip and pds-combobox's dropdown in
10
+ // document.body, pds-popover in the body or the open dialog it's in.
10
11
  // A pointerdown landing on one of these is not "outside" the drawer in the
11
12
  // sense light dismiss cares about: it belongs to an overlay something inside
12
13
  // the drawer opened, even though it is not a DOM descendant of the drawer.
@@ -38,8 +39,18 @@ const PdsDrawer = class {
38
39
  */
39
40
  this.scrollable = true;
40
41
  /**
41
- * Whether the drawer can be dismissed with a pointerdown outside it.
42
- * Replaces `pds-modal`'s `backdropDismiss` — there is no backdrop to click.
42
+ * Whether the drawer is modal. A modal drawer dims the page behind it with a
43
+ * backdrop, makes the page inert, and keeps focus inside the drawer, like
44
+ * `pds-modal`. Use it for a task the page should wait on. Leave it off for a
45
+ * panel people work alongside the page. Read when the drawer opens; changing
46
+ * it while the drawer is open is not supported.
47
+ * @default false
48
+ */
49
+ this.modal = false;
50
+ /**
51
+ * Whether the drawer can be dismissed with a pointerdown outside it (in a
52
+ * `modal` drawer, a click on its backdrop).
53
+ * Replaces `pds-modal`'s `backdropDismiss`.
43
54
  * This also gates Escape, matching how `backdropDismiss` gates Escape on
44
55
  * `pds-modal` today: setting this to `false` means the close button is the
45
56
  * only way out.
@@ -58,7 +69,8 @@ const PdsDrawer = class {
58
69
  * background event while the user is mid-task elsewhere on the page —
59
70
  * moving focus there would interrupt them, and the page stays live under
60
71
  * a non-modal drawer, so it is a genuine data-entry risk, not just an
61
- * annoyance.
72
+ * annoyance. A `modal` drawer ignores `none`: the page behind it is inert,
73
+ * so focus starts in the drawer.
62
74
  * @default 'auto'
63
75
  */
64
76
  this.initialFocus = 'auto';
@@ -104,7 +116,8 @@ const PdsDrawer = class {
104
116
  // page underneath stays genuinely clickable, which means a click there
105
117
  // never reaches pds-modal's backdrop element at all.
106
118
  handleOutsidePointerDown(e) {
107
- if (!this.lightDismiss || !this.open)
119
+ // A modal drawer's backdrop takes the click instead, through pds-modal.
120
+ if (this.modal || !this.lightDismiss || !this.open)
108
121
  return;
109
122
  const target = e.target;
110
123
  if (!target)
@@ -114,7 +127,7 @@ const PdsDrawer = class {
114
127
  if (target.closest(PORTALED_OVERLAY_SELECTOR))
115
128
  return;
116
129
  // A datepicker's portaled calendar counts as inside only when its datepicker is in the drawer,
117
- // or in an overlay portaled from it (a pds-popover in the drawer puts its content on the body).
130
+ // or in an overlay portaled from it (a pds-popover in the drawer puts its content beside it).
118
131
  const calendar = target.closest('.pds-datepicker-calendar-portal');
119
132
  const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
120
133
  if (owner && (containsComposed(this.el, owner) || closest(PORTALED_OVERLAY_SELECTOR, owner)))
@@ -130,11 +143,11 @@ const PdsDrawer = class {
130
143
  this.open = false;
131
144
  }
132
145
  render() {
133
- return (h(Host, { key: 'ae7e67ed196ef95a39c2b729e859712ce5c41144', class: {
146
+ return (h(Host, { key: '287bf043c991209488eb1b617031acffb59ff9af', class: {
134
147
  'pds-drawer': true,
135
148
  [`pds-drawer--${this.side}`]: true,
136
149
  [`pds-drawer--${this.size}`]: true,
137
- } }, h("pds-modal", { key: '9b35ce377c84612a844a561d5540e98b08c0e499', class: "pds-drawer__modal", ref: (el) => (this.modalEl = el), componentId: this.componentId, open: this.open, scrollable: this.scrollable, disableTopLayer: true, backdropDismiss: this.lightDismiss, disableInitialFocus: this.initialFocus === 'none' }, h("slot", { key: 'dda01aa40dc41b3d17073238a8cad8d816571e18' }))));
150
+ } }, h("pds-modal", { key: 'cd86fb552353f5cc12fb36fc956033432a91847c', class: { 'pds-drawer__modal': true, 'pds-drawer__modal--modal': this.modal }, ref: (el) => (this.modalEl = el), componentId: this.componentId, open: this.open, scrollable: this.scrollable, disableTopLayer: !this.modal, backdropDismiss: this.lightDismiss, disableInitialFocus: !this.modal && this.initialFocus === 'none' }, h("slot", { key: '56bbe9b5c26b10b07c0f503ba147899a57a5de85' }))));
138
151
  }
139
152
  get el() { return getElement(this); }
140
153
  };
@@ -63,7 +63,7 @@ const PdsDropdownMenuItem = class {
63
63
  });
64
64
  }
65
65
  renderElement() {
66
- if (this.href !== undefined) {
66
+ if (this.href != null) {
67
67
  return (h("pds-link", { download: this.download, href: this.disabled ? null : this.href, external: this.external, target: this.target, class: {
68
68
  'pds-dropdown-menu-item__content': true,
69
69
  'has-focus': this.hasFocus
@@ -75,7 +75,7 @@ const PdsDropdownMenuItem = class {
75
75
  }, tabIndex: this.disabled ? -1 : 0, type: "button", part: "button", onKeyDown: this.handleKeyDown, onFocus: this.handleFocus, onBlur: this.handleBlur, disabled: this.disabled, "aria-disabled": this.disabled ? 'true' : null }, h("slot", null)));
76
76
  }
77
77
  render() {
78
- return (h(Host, { key: '33bd645d7c9547e3fd07429cf795302e6a482296', id: this.componentId, class: { 'is-disabled': this.disabled, 'destructive': !this.disabled && this.destructive }, onClick: () => !this.disabled && this.handleClick(), role: "none", tabIndex: -1, "aria-disabled": this.disabled ? 'true' : null }, this.renderElement()));
78
+ return (h(Host, { key: '2d499a06768bdc4b9a34774d16c1f1e10804b3d5', id: this.componentId, class: { 'is-disabled': this.disabled, 'destructive': !this.disabled && this.destructive }, onClick: () => !this.disabled && this.handleClick(), role: "none", tabIndex: -1, "aria-disabled": this.disabled ? 'true' : null }, this.renderElement()));
79
79
  }
80
80
  get host() { return getElement(this); }
81
81
  };
@@ -253,15 +253,19 @@ const PdsDropdownMenu = class {
253
253
  this.focusItemByIndex(prevIndex);
254
254
  }
255
255
  }
256
+ // Escape is taken in document's capture phase, before a modal around the menu hears it on
257
+ // document and closes too.
258
+ handleEscapeKeyDown(event) {
259
+ if (!this.isOpen || event.key !== 'Escape' || event.defaultPrevented)
260
+ return;
261
+ event.preventDefault();
262
+ this.closeDropdown();
263
+ }
256
264
  // Handle keyboard events for the dropdown
257
265
  handleKeyDown(event) {
258
266
  if (!this.isOpen)
259
267
  return;
260
268
  switch (event.key) {
261
- case 'Escape':
262
- event.preventDefault();
263
- this.closeDropdown();
264
- break;
265
269
  case 'ArrowDown':
266
270
  event.preventDefault();
267
271
  this.focusNextItem();
@@ -353,7 +357,7 @@ const PdsDropdownMenu = class {
353
357
  }
354
358
  }
355
359
  render() {
356
- return (h(Host, { key: '0dd585168e8fa86378c4812ce54fd09108861d5b', id: this.componentId }, h("slot", { key: 'c7144f8d6aaebe37b585c6c6230102c013230a9e', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), h("pds-box", { key: '82292e051337141bc9fd83b90292b188b0bb3489', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", part: "menu-panel" }, h("div", { key: 'c0f49dca14df0ba3885865c51562c380155bf8a8', class: { 'pds-dropdown-menu__header': true, 'is-hidden': !this.hasHeader } }, h("slot", { key: 'dc80c97a8dbb79ab4563524b3dea68d144e8570c', name: "header", onSlotchange: this.handleHeaderSlotChange })), h("div", { key: '29cb56bdf28a0438296f33e0fa86c9da7b51902c', class: "pds-dropdown-menu__items", role: "menu", "aria-orientation": "vertical" }, h("slot", { key: '8f91ceeb1eedc4acc79f09032dedc69a2ba1f99a', onSlotchange: this.handleSlotChange })))));
360
+ return (h(Host, { key: '18dac4d59ea236fe171f4c16f6571cb1547059c6', id: this.componentId }, h("slot", { key: '95201a75a33ccb70dbd51a5cf9d78c76ebf26f65', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), h("pds-box", { key: '7fc588f40f607ad81ad70bf74a525d078d32a80b', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", part: "menu-panel" }, h("div", { key: '73d13d94edccb68db7b703f930b50f729334efa8', class: { 'pds-dropdown-menu__header': true, 'is-hidden': !this.hasHeader } }, h("slot", { key: '7066f3a6f71c8961326f38f0509f1c0cc17098ae', name: "header", onSlotchange: this.handleHeaderSlotChange })), h("div", { key: '9f07ec488b688c58c6422b575015ccd364075fe8', class: "pds-dropdown-menu__items", role: "menu", "aria-orientation": "vertical" }, h("slot", { key: 'd0aad3f9ac3b58779669411523adbb8878dec61c', onSlotchange: this.handleSlotChange })))));
357
361
  }
358
362
  get host() { return getElement(this); }
359
363
  };
@@ -76,6 +76,20 @@ function oneRadioPerGroup(elements) {
76
76
  const stops = new Set(groups.map((radios) => { var _a; return (_a = radios.find((radio) => radio.checked)) !== null && _a !== void 0 ? _a : radios[0]; }));
77
77
  return elements.filter((el) => groupedRadio(el) === null || stops.has(el));
78
78
  }
79
+ /** The controls Tab reaches in `root`, in order: visible ones, and one radio per group. */
80
+ function tabbableIn(root) {
81
+ const found = [];
82
+ collectTabbable(root, found);
83
+ // checkVisibility() also drops an element inside a hidden ancestor, whose own computed
84
+ // display isn't none; such an element can't take focus.
85
+ const visible = found.filter(el => {
86
+ if (typeof el.checkVisibility === 'function')
87
+ return el.checkVisibility({ checkVisibilityCSS: true });
88
+ const style = window.getComputedStyle(el);
89
+ return style.display !== 'none' && style.visibility !== 'hidden';
90
+ });
91
+ return oneRadioPerGroup(visible);
92
+ }
79
93
  /** Whether `node` is `ancestor` or inside it, crossing shadow roots, which `Node.contains` doesn't. */
80
94
  function containsComposed(ancestor, node) {
81
95
  for (let current = node; current; current = current instanceof ShadowRoot ? current.host : current.parentNode) {
@@ -84,6 +98,34 @@ function containsComposed(ancestor, node) {
84
98
  }
85
99
  return false;
86
100
  }
101
+ /**
102
+ * Every open modal, with the order it opened in, which ranks top-layer modals and the modals
103
+ * inside them. Kept here rather than queried from the document, which can't see a modal inside
104
+ * another component's shadow root.
105
+ */
106
+ const openModals = new Map();
107
+ let openSequence = 0;
108
+ /** Whether an open auto popover's panel sits in `root`, including inside shadow roots under it. */
109
+ function hasOpenPopover(root) {
110
+ if (root.querySelector('[data-pds-popover-open]'))
111
+ return true;
112
+ return Array.from(root.querySelectorAll('*')).some(el => !!el.shadowRoot && hasOpenPopover(el.shadowRoot));
113
+ }
114
+ /**
115
+ * Whether `a` comes before `b` in the page. `compareDocumentPosition` is arbitrary across a shadow
116
+ * boundary, so each side climbs to its host until both are in the same tree.
117
+ */
118
+ function precedesComposed(a, b) {
119
+ // A document has no host, which ends each climb.
120
+ for (let x = a; x; x = x.getRootNode().host) {
121
+ for (let y = b; y; y = y.getRootNode().host) {
122
+ if (x.getRootNode() === y.getRootNode()) {
123
+ return !!(x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING);
124
+ }
125
+ }
126
+ }
127
+ return false;
128
+ }
87
129
  /** The focused element, followed down through shadow roots to the control that has focus. */
88
130
  function deepActiveElement() {
89
131
  var _a;
@@ -99,7 +141,8 @@ const PdsModal = class {
99
141
  this.pdsModalClose = createEvent(this, "pdsModalClose");
100
142
  this.focusableElements = [];
101
143
  /**
102
- * Whether the modal can be dismissed by clicking the backdrop
144
+ * Whether the modal can be dismissed by clicking the backdrop, pressing Escape, or the browser's
145
+ * own close request (such as a back gesture)
103
146
  * @default true
104
147
  */
105
148
  this.backdropDismiss = true;
@@ -147,19 +190,33 @@ const PdsModal = class {
147
190
  * Stores the list of focusable elements in the modal
148
191
  */
149
192
  this.focusableElementsArray = [];
193
+ // The browser's own close request (an Escape nothing prevented, a back gesture) would close the
194
+ // dialog without updating `open`, so close it through hideModal() instead, or not at all.
195
+ this.handleCancel = (e) => {
196
+ e.preventDefault();
197
+ if (!this.open)
198
+ return;
199
+ // The request reaches the top-layer dialog even when a disableTopLayer modal inside it is on
200
+ // top; that one closes first, as it would on Escape.
201
+ const top = this.innermostOpenModal();
202
+ const target = (top && containsComposed(this.el, top) ? top : this.el);
203
+ if (target.backdropDismiss)
204
+ target.hideModal();
205
+ };
150
206
  this.handleBackdropClick = (e) => {
151
207
  if (!this.backdropDismiss || !this.open)
152
208
  return;
153
- if (e.target.classList.contains('pds-modal__backdrop')) {
209
+ // This modal's own backdrop; a nested modal's backdrop handles its own clicks.
210
+ if (e.target === this.modalRef) {
154
211
  e.stopPropagation();
155
212
  // Only close if this is the innermost modal
156
- if (this.isInnermostModal()) {
213
+ if (this.innermostOpenModal() === this.el) {
157
214
  this.hideModal();
158
215
  }
159
216
  }
160
217
  };
161
218
  this.handleKeyDown = (e) => {
162
- var _a, _b, _c;
219
+ var _a, _b, _c, _d;
163
220
  // If the modal is not open, don't handle any keyboard events
164
221
  if (!this.open)
165
222
  return;
@@ -182,24 +239,39 @@ const PdsModal = class {
182
239
  if (!('__pdsActiveElementAtEscape' in eventSnapshot)) {
183
240
  const activeAtDispatch = document.activeElement;
184
241
  eventSnapshot.__pdsActiveElementAtEscape = activeAtDispatch;
242
+ // Followed into shadow roots: for a modal inside one, document.activeElement is only the host.
243
+ eventSnapshot.__pdsDeepActiveElementAtEscape = deepActiveElement();
185
244
  const topLayerDialog = (_a = activeAtDispatch === null || activeAtDispatch === void 0 ? void 0 : activeAtDispatch.closest('dialog')) !== null && _a !== void 0 ? _a : null;
186
245
  eventSnapshot.__pdsTopLayerDialogAtEscape = topLayerDialog;
187
246
  eventSnapshot.__pdsTopLayerDialogWasModalAtEscape = !!(topLayerDialog && topLayerDialog.matches(':modal'));
247
+ // A control that closed on this Escape (a combobox on its own element, a dropdown menu or
248
+ // multiselect in document's capture phase) has prevented it before this bubble listener.
249
+ // Read before any modal prevents it below.
250
+ eventSnapshot.__pdsEscapeHandledInside = e.defaultPrevented;
251
+ // Which modal is innermost is read once too: the inner one closing first would make its
252
+ // outer modal the innermost by the time that modal's listener runs.
253
+ eventSnapshot.__pdsInnermostModalAtEscape = this.innermostOpenModal();
188
254
  }
255
+ if (eventSnapshot.__pdsEscapeHandledInside)
256
+ return;
189
257
  // Leave Escape to a genuinely stacked-above overlay (disableTopLayer's
190
258
  // reason for existing) — not just to anything outside this modal.
191
259
  const active = eventSnapshot.__pdsActiveElementAtEscape;
192
260
  if (this.disableTopLayer &&
193
261
  active &&
194
262
  active !== document.body &&
195
- !this.el.contains(active) &&
196
- this.isStackedAboveOverlay(active, (_b = eventSnapshot.__pdsTopLayerDialogAtEscape) !== null && _b !== void 0 ? _b : null, (_c = eventSnapshot.__pdsTopLayerDialogWasModalAtEscape) !== null && _c !== void 0 ? _c : false)) {
263
+ !containsComposed(this.el, (_b = eventSnapshot.__pdsDeepActiveElementAtEscape) !== null && _b !== void 0 ? _b : active) &&
264
+ this.isStackedAboveOverlay(active, (_c = eventSnapshot.__pdsTopLayerDialogAtEscape) !== null && _c !== void 0 ? _c : null, (_d = eventSnapshot.__pdsTopLayerDialogWasModalAtEscape) !== null && _d !== void 0 ? _d : false)) {
197
265
  return;
198
266
  }
267
+ // An open popover inside takes Escape from its own document listener, which runs after this
268
+ // one, so leave the key for it. Its preventDefault() keeps the native dialog open.
269
+ if (this.modalRef && hasOpenPopover(this.modalRef))
270
+ return;
199
271
  // Always prevent native dialog close behavior
200
272
  e.preventDefault();
201
273
  // Only close if backdropDismiss is enabled and this is the innermost modal
202
- if (this.backdropDismiss && this.isInnermostModal()) {
274
+ if (this.backdropDismiss && eventSnapshot.__pdsInnermostModalAtEscape === this.el) {
203
275
  this.hideModal();
204
276
  }
205
277
  return;
@@ -259,8 +331,6 @@ const PdsModal = class {
259
331
  }
260
332
  componentDidLoad() {
261
333
  this.modalRef = this.el.querySelector('.pds-modal__backdrop');
262
- // Add keyboard event listener
263
- document.addEventListener('keydown', this.handleKeyDown);
264
334
  // @Watch('open') only fires on a later change, not the prop's initial
265
335
  // value — a modal mounted with `open` already true (static markup, or a
266
336
  // framework passing it on first render) would otherwise never call
@@ -276,9 +346,18 @@ const PdsModal = class {
276
346
  componentDidRender() {
277
347
  unwrapReconnectedContent(this.el.querySelector('.pds-modal'), 'dialog.pds-modal__backdrop', '.pds-modal');
278
348
  }
349
+ // Here rather than in componentDidLoad, which runs once: a modal taken out of the page and put
350
+ // back (a morph or a framework moving it) gets its keyboard handling, and its place among the
351
+ // open modals, back too. Adding the same listener twice is a no-op.
352
+ connectedCallback() {
353
+ document.addEventListener('keydown', this.handleKeyDown);
354
+ if (this.open && !openModals.has(this.el))
355
+ openModals.set(this.el, ++openSequence);
356
+ }
279
357
  disconnectedCallback() {
280
358
  // Clean up event listener
281
359
  document.removeEventListener('keydown', this.handleKeyDown);
360
+ openModals.delete(this.el);
282
361
  }
283
362
  handleOpenChange(newValue) {
284
363
  if (newValue) {
@@ -294,17 +373,7 @@ const PdsModal = class {
294
373
  updateFocusableElements() {
295
374
  if (!this.modalRef)
296
375
  return;
297
- this.focusableElements = [];
298
- collectTabbable(this.modalRef, this.focusableElements);
299
- // checkVisibility() also drops an element inside a hidden ancestor, whose own computed
300
- // display isn't none; such an element can't take focus, so it can't anchor the trap.
301
- this.focusableElements = this.focusableElements.filter(el => {
302
- if (typeof el.checkVisibility === 'function')
303
- return el.checkVisibility({ checkVisibilityCSS: true });
304
- const style = window.getComputedStyle(el);
305
- return style.display !== 'none' && style.visibility !== 'hidden';
306
- });
307
- this.focusableElements = oneRadioPerGroup(this.focusableElements);
376
+ this.focusableElements = tabbableIn(this.modalRef);
308
377
  }
309
378
  /**
310
379
  * Sets focus to the first focusable element in the modal
@@ -328,10 +397,13 @@ const PdsModal = class {
328
397
  * Opens the modal
329
398
  */
330
399
  async showModal() {
400
+ var _a;
331
401
  if (this.modalRef) {
332
402
  try {
333
- // Store the currently focused element to restore focus when modal closes
334
- this.previousActiveElement = document.activeElement;
403
+ // Store the currently focused element to restore focus when modal closes. Showing an open
404
+ // modal again (the open watcher does) would record a control inside it instead.
405
+ if (!this.modalRef.open)
406
+ this.previousActiveElement = document.activeElement;
335
407
  // showModal() promotes the dialog to the browser top layer (and makes the
336
408
  // rest of the page inert), which prevents any overlay outside the dialog
337
409
  // from ever painting above it. show() opens a non-modal dialog that stays
@@ -343,11 +415,25 @@ const PdsModal = class {
343
415
  this.modalRef.showModal();
344
416
  }
345
417
  this.open = true;
418
+ // Showing an open modal again doesn't move it above one opened after it.
419
+ if (!openModals.has(this.el))
420
+ openModals.set(this.el, ++openSequence);
346
421
  // Update focusable elements and set initial focus
347
422
  // Using a longer timeout to ensure all components are fully rendered
423
+ const openedAs = (_a = openModals.get(this.el)) !== null && _a !== void 0 ? _a : 0;
348
424
  setTimeout(() => {
349
425
  var _a, _b;
350
426
  this.updateFocusableElements();
427
+ // A modal opened above this one in the meantime has focus; don't take it back. Not this
428
+ // modal itself (moving it gives it a new place), and not a disableTopLayer modal outside
429
+ // it while this one is in the top layer, which sits below it.
430
+ const openedAbove = Array.from(openModals).some(([modal, sequence]) => sequence > openedAs &&
431
+ modal !== this.el &&
432
+ (containsComposed(this.el, modal) || !modal.disableTopLayer || this.disableTopLayer));
433
+ if (openedAbove) {
434
+ this.pdsModalOpen.emit();
435
+ return;
436
+ }
351
437
  if (this.disableInitialFocus) {
352
438
  // show()/showModal() also move focus into the dialog natively (the
353
439
  // HTML spec's "dialog focusing steps") — that native step isn't
@@ -391,6 +477,7 @@ const PdsModal = class {
391
477
  * Closes the modal
392
478
  */
393
479
  async hideModal() {
480
+ var _a;
394
481
  if (this.modalRef) {
395
482
  try {
396
483
  // Capture before close(): with the async task queue, a prop change
@@ -405,11 +492,19 @@ const PdsModal = class {
405
492
  const focusAlreadyMovedElsewhere = activeElement !== null && activeElement !== document.body && !this.modalRef.contains(activeElement);
406
493
  this.modalRef.close();
407
494
  this.open = false;
408
- // Restore focus to the element that was focused before the modal was opened
409
- if (!focusAlreadyMovedElsewhere &&
410
- this.previousActiveElement &&
411
- typeof this.previousActiveElement.focus === 'function') {
412
- this.previousActiveElement.focus();
495
+ openModals.delete(this.el);
496
+ // Restore focus to the element that was focused before the modal was opened. If that's
497
+ // gone or can't take focus (disabled, hidden, or nothing), fall back to the open modal now
498
+ // on top, so focus doesn't land on an inert page behind it.
499
+ if (!focusAlreadyMovedElsewhere) {
500
+ const previous = this.previousActiveElement;
501
+ if (previous && previous !== document.body && previous.isConnected)
502
+ (_a = previous.focus) === null || _a === void 0 ? void 0 : _a.call(previous);
503
+ const active = deepActiveElement();
504
+ // document.body isn't a real restore target — it's just where focus lands when nothing
505
+ // was focused before opening, so landing back there never counts as a successful restore.
506
+ if (!previous || previous === document.body || !containsComposed(previous, active) || containsComposed(this.el, active))
507
+ this.focusTopModal();
413
508
  }
414
509
  this.pdsModalClose.emit();
415
510
  }
@@ -418,12 +513,29 @@ const PdsModal = class {
418
513
  }
419
514
  }
420
515
  }
516
+ /**
517
+ * Focuses the first control of the open modal now on top, when the page behind it is inert: that
518
+ * modal is in the top layer (or paints there inside a top-layer one), or it wraps this one. A
519
+ * non-modal one over an interactive page, like a drawer, is left alone.
520
+ */
521
+ focusTopModal() {
522
+ var _a;
523
+ const top = this.innermostOpenModal();
524
+ const dialog = top === null || top === void 0 ? void 0 : top.querySelector('.pds-modal__backdrop');
525
+ if (!dialog)
526
+ return;
527
+ if (!closest('dialog:modal', dialog) && !containsComposed(top, this.el))
528
+ return;
529
+ (_a = tabbableIn(dialog).find(el => !containsComposed(this.el, el))) === null || _a === void 0 ? void 0 : _a.focus();
530
+ }
421
531
  /**
422
532
  * Gets the z-index of a modal's backdrop element
423
533
  */
424
534
  getBackdropZIndex(modal) {
425
535
  const backdrop = modal.querySelector('.pds-modal__backdrop');
426
- return backdrop ? parseInt(getComputedStyle(backdrop).zIndex, 10) : -1;
536
+ // `auto` (no z-index token loaded) parses to NaN, which no comparison can rank.
537
+ const zIndex = backdrop ? parseInt(getComputedStyle(backdrop).zIndex, 10) : -1;
538
+ return Number.isNaN(zIndex) ? 0 : zIndex;
427
539
  }
428
540
  /**
429
541
  * Whether `active` sits inside a surface actually stacked above this modal.
@@ -450,7 +562,8 @@ const PdsModal = class {
450
562
  * lose that evidence depending on listener order.
451
563
  */
452
564
  isStackedAboveOverlay(active, topLayerDialog, topLayerDialogWasModal) {
453
- if (topLayerDialog && topLayerDialog !== this.modalRef && topLayerDialogWasModal) {
565
+ // A top-layer dialog this modal sits inside is underneath it, not an overlay above.
566
+ if (topLayerDialog && topLayerDialog !== this.modalRef && topLayerDialogWasModal && !containsComposed(topLayerDialog, this.el)) {
454
567
  return true;
455
568
  }
456
569
  const ownZIndex = this.getBackdropZIndex(this.el);
@@ -466,24 +579,37 @@ const PdsModal = class {
466
579
  return false;
467
580
  }
468
581
  /**
469
- * Checks if this modal is the innermost (highest z-index) modal
582
+ * The open modal that takes Escape or a backdrop click, among those with no other open modal
583
+ * inside them (a nested modal's backdrop can share its outer modal's z-index). A top-layer dialog
584
+ * (or a modal inside one) paints above anything outside it, and within the top layer the last
585
+ * opened is on top. Modals in the same layer (the page, or one top-layer dialog) then rank by
586
+ * the highest backdrop, then the one later in the page.
470
587
  */
471
- isInnermostModal() {
472
- // Find all open modals
473
- const openModals = Array.from(document.querySelectorAll('pds-modal')).filter(modal => modal.open);
474
- if (openModals.length === 0)
475
- return false;
476
- // Get this modal's backdrop element
477
- const thisBackdrop = this.el.querySelector('.pds-modal__backdrop');
478
- if (!thisBackdrop)
479
- return false;
480
- // Get computed z-index of all open modal backdrops
481
- const modalZIndexes = openModals.map(modal => this.getBackdropZIndex(modal));
482
- // Get the highest z-index
483
- const maxZIndex = Math.max(...modalZIndexes);
484
- // Check if this modal's backdrop has the highest z-index
485
- const thisZIndex = this.getBackdropZIndex(this.el);
486
- return thisZIndex === maxZIndex;
588
+ innermostOpenModal() {
589
+ const open = Array.from(openModals.keys()).filter(modal => modal.isConnected);
590
+ const innermost = open.filter(modal => !open.some(other => other !== modal && containsComposed(modal, other)));
591
+ const byDocumentOrder = [...innermost].sort((a, b) => (precedesComposed(a, b) ? -1 : 1));
592
+ // A modal inside a top-layer dialog paints in that dialog's place in the top layer, even when it
593
+ // isn't in the top layer itself (disableTopLayer), so that dialog's open order ranks it first.
594
+ const rank = (modal) => {
595
+ var _a;
596
+ const backdrop = modal.querySelector('.pds-modal__backdrop');
597
+ const topLayerDialog = backdrop ? closest('dialog:modal', backdrop) : null;
598
+ const topLayerModal = topLayerDialog === null || topLayerDialog === void 0 ? void 0 : topLayerDialog.closest('pds-modal');
599
+ const layer = topLayerDialog ? ((_a = (topLayerModal && openModals.get(topLayerModal))) !== null && _a !== void 0 ? _a : 0) : 0;
600
+ return [topLayerDialog ? 1 : 0, layer, this.getBackdropZIndex(modal), byDocumentOrder.indexOf(modal)];
601
+ };
602
+ let top = null;
603
+ let topRank = [-1, -1, -1, -1];
604
+ for (const modal of innermost) {
605
+ const modalRank = rank(modal);
606
+ const above = modalRank.findIndex((value, i) => value !== topRank[i]);
607
+ if (above >= 0 && modalRank[above] > topRank[above]) {
608
+ top = modal;
609
+ topRank = modalRank;
610
+ }
611
+ }
612
+ return top;
487
613
  }
488
614
  /** Whether a modal dialog other than this one sits between the focused element and this modal. */
489
615
  modalDialogAbove(active) {
@@ -523,14 +649,14 @@ const PdsModal = class {
523
649
  }
524
650
  render() {
525
651
  const [sizeClass = 'md', customSize] = this.resolveSize();
526
- return (h("dialog", { key: '12ea38928ea287f16ffa33e246caa2bfde6fc130', class: {
652
+ return (h("dialog", { key: '0b187f36910a859afe57b891f1ebffd1d2d49ab7', class: {
527
653
  'pds-modal__backdrop': true,
528
654
  'open': this.open
529
- }, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick }, h("div", { key: 'b9d83cabda56c315d9115f7030e3bdbcf923ec08', class: {
655
+ }, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick, onCancel: this.handleCancel }, h("div", { key: 'f5e652d4dae0e7c272b37b63eb9c65f04c69536a', class: {
530
656
  'pds-modal': true,
531
657
  [`pds-modal--${sizeClass}`]: true,
532
658
  'pds-modal--scrollable': this.scrollable
533
- }, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, h("slot", { key: '3c5edad1482cb124e503197adf411890573b076d' }))));
659
+ }, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, h("slot", { key: 'a954e1694741f78230599c476b270079797a263e' }))));
534
660
  }
535
661
  get el() { return getElement(this); }
536
662
  static get watchers() { return {