@pine-ds/core 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/pds-combobox.js +1 -1
- package/components/pds-drawer.js +1 -1
- package/components/pds-dropdown-menu.js +1 -1
- package/components/pds-modal2.js +1 -1
- package/components/pds-multiselect.js +1 -1
- package/components/pds-popover.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/pds-combobox.cjs.entry.js +33 -3
- package/dist/cjs/pds-drawer.cjs.entry.js +23 -10
- package/dist/cjs/pds-dropdown-menu.cjs.entry.js +9 -5
- package/dist/cjs/pds-modal.cjs.entry.js +116 -31
- package/dist/cjs/pds-multiselect.cjs.entry.js +6 -5
- package/dist/cjs/pds-popover.cjs.entry.js +170 -26
- package/dist/cjs/pine-core.cjs.js +1 -1
- package/dist/collection/components/pds-combobox/pds-combobox.js +33 -3
- package/dist/collection/components/pds-drawer/pds-drawer.css +4 -1
- package/dist/collection/components/pds-drawer/pds-drawer.js +54 -17
- package/dist/collection/components/pds-drawer/stories/pds-drawer.stories.js +6 -1
- package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js +15 -5
- package/dist/collection/components/pds-modal/pds-modal.js +117 -32
- package/dist/collection/components/pds-multiselect/pds-multiselect.js +8 -7
- package/dist/collection/components/pds-popover/pds-popover.js +171 -27
- package/dist/docs.json +42 -7
- package/dist/esm/loader.js +1 -1
- package/dist/esm/pds-combobox.entry.js +33 -3
- package/dist/esm/pds-drawer.entry.js +23 -10
- package/dist/esm/pds-dropdown-menu.entry.js +9 -5
- package/dist/esm/pds-modal.entry.js +116 -31
- package/dist/esm/pds-multiselect.entry.js +6 -5
- package/dist/esm/pds-popover.entry.js +171 -27
- package/dist/esm/pine-core.js +1 -1
- package/dist/esm-es5/loader.js +1 -1
- package/dist/esm-es5/pds-combobox.entry.js +1 -1
- package/dist/esm-es5/pds-drawer.entry.js +1 -1
- package/dist/esm-es5/pds-dropdown-menu.entry.js +1 -1
- package/dist/esm-es5/pds-modal.entry.js +1 -1
- package/dist/esm-es5/pds-multiselect.entry.js +1 -1
- package/dist/esm-es5/pds-popover.entry.js +1 -1
- package/dist/esm-es5/pine-core.js +1 -1
- package/dist/pine-core/p-153ba77b.entry.js +1 -0
- package/dist/pine-core/p-21fe6ee1.system.entry.js +1 -0
- package/dist/pine-core/p-24fbbb74.system.entry.js +1 -0
- package/dist/pine-core/{p-df539c42.system.entry.js → p-5a10784e.system.entry.js} +1 -1
- package/dist/pine-core/p-74a05bcc.entry.js +1 -0
- package/dist/pine-core/p-92ae6082.entry.js +1 -0
- package/dist/pine-core/p-945fb0b1.entry.js +1 -0
- package/dist/pine-core/p-CuSNnuFu.system.js +1 -1
- package/dist/pine-core/p-a0344e30.entry.js +2 -0
- package/dist/pine-core/p-a787b34a.system.entry.js +1 -0
- package/dist/pine-core/{p-646afbca.system.entry.js → p-b60ac7eb.system.entry.js} +1 -1
- package/dist/pine-core/p-bf5887e8.system.entry.js +1 -0
- package/dist/pine-core/p-e21ff692.entry.js +1 -0
- package/dist/pine-core/pine-core.esm.js +1 -1
- package/dist/types/components/pds-combobox/pds-combobox.d.ts +1 -0
- package/dist/types/components/pds-drawer/pds-drawer.d.ts +21 -9
- package/dist/types/components/pds-dropdown-menu/pds-dropdown-menu.d.ts +1 -0
- package/dist/types/components/pds-modal/pds-modal.d.ts +10 -3
- package/dist/types/components/pds-multiselect/pds-multiselect.d.ts +2 -1
- package/dist/types/components/pds-popover/pds-popover.d.ts +31 -1
- package/dist/types/components.d.ts +45 -30
- package/dist/vscode.html-data.json +11 -4
- package/hydrate/index.js +369 -90
- package/hydrate/index.mjs +369 -90
- package/package.json +2 -2
- package/dist/pine-core/p-01c9b8f3.entry.js +0 -1
- package/dist/pine-core/p-3c27088f.system.entry.js +0 -1
- package/dist/pine-core/p-73eb47fa.entry.js +0 -1
- package/dist/pine-core/p-7f367db4.system.entry.js +0 -1
- package/dist/pine-core/p-9a0083dd.system.entry.js +0 -1
- package/dist/pine-core/p-a3735199.entry.js +0 -1
- package/dist/pine-core/p-da103a54.system.entry.js +0 -1
- package/dist/pine-core/p-ec5428fb.entry.js +0 -1
- package/dist/pine-core/p-ed4b979e.entry.js +0 -1
- package/dist/pine-core/p-f1f17940.entry.js +0 -2
package/hydrate/index.js
CHANGED
|
@@ -11625,6 +11625,9 @@ class PdsCombobox {
|
|
|
11625
11625
|
};
|
|
11626
11626
|
// Handler for button trigger click
|
|
11627
11627
|
this.onButtonTriggerClick = () => {
|
|
11628
|
+
// The button and chip triggers are divs, so a click reaches them even while disabled.
|
|
11629
|
+
if (this.disabled)
|
|
11630
|
+
return;
|
|
11628
11631
|
this.isOpen = !this.isOpen;
|
|
11629
11632
|
if (this.isOpen) {
|
|
11630
11633
|
this.prepareExpandFilterListOnOpen();
|
|
@@ -11644,6 +11647,13 @@ class PdsCombobox {
|
|
|
11644
11647
|
};
|
|
11645
11648
|
// Handler for button trigger keyboard events
|
|
11646
11649
|
this.onButtonTriggerKeyDown = (e) => {
|
|
11650
|
+
// Disabled takes it out of the tab order, but setFocus() or a click can still focus it.
|
|
11651
|
+
if (this.disabled) {
|
|
11652
|
+
// Keep Space from scrolling the page, as on a native disabled button.
|
|
11653
|
+
if (e.key === ' ')
|
|
11654
|
+
e.preventDefault();
|
|
11655
|
+
return;
|
|
11656
|
+
}
|
|
11647
11657
|
// Escape closes an open group before the dropdown. Other keys reach the tree through handleKeyDown.
|
|
11648
11658
|
if (this.isOpen && e.key === 'Escape' && this.handleGroupedPanelKey(e))
|
|
11649
11659
|
return;
|
|
@@ -11664,8 +11674,9 @@ class PdsCombobox {
|
|
|
11664
11674
|
}, 0);
|
|
11665
11675
|
}
|
|
11666
11676
|
else if (e.key === 'Escape') {
|
|
11667
|
-
|
|
11677
|
+
// Only an open dropdown claims Escape; a closed one leaves it to a modal or popover around it.
|
|
11668
11678
|
if (this.isOpen) {
|
|
11679
|
+
e.preventDefault();
|
|
11669
11680
|
this.isOpen = false;
|
|
11670
11681
|
this.highlightedIndex = -1;
|
|
11671
11682
|
this.clearExpandFilterList();
|
|
@@ -11910,6 +11921,22 @@ class PdsCombobox {
|
|
|
11910
11921
|
if (this.isOpen && this.hidesPanelSearch && this.panelTreeEl)
|
|
11911
11922
|
this.focusPanel(this.panelTreeEl);
|
|
11912
11923
|
}
|
|
11924
|
+
disabledChanged(disabled) {
|
|
11925
|
+
var _a, _b, _c, _d, _e;
|
|
11926
|
+
if (!disabled || !this.isOpen)
|
|
11927
|
+
return;
|
|
11928
|
+
const shadowActive = (_b = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement) !== null && _b !== void 0 ? _b : null;
|
|
11929
|
+
const focusInDropdown = !!((_d = (_c = this.portalEl) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.activeElement) || (!!shadowActive && !!((_e = this.listboxEl) === null || _e === void 0 ? void 0 : _e.contains(shadowActive)));
|
|
11930
|
+
this.isOpen = false;
|
|
11931
|
+
this.highlightedIndex = -1;
|
|
11932
|
+
this.isArrowKeyNavigationMode = false;
|
|
11933
|
+
this.clearExpandFilterList();
|
|
11934
|
+
this.updateAriaActiveDescendant();
|
|
11935
|
+
// Closing removes the search field or option that held focus. A button or chip trigger can still
|
|
11936
|
+
// take it (aria-disabled), so focus doesn't fall to the page; a disabled input can't, as natively.
|
|
11937
|
+
if (focusInDropdown && this.trigger !== 'input')
|
|
11938
|
+
this.restoreFocusToTrigger();
|
|
11939
|
+
}
|
|
11913
11940
|
isOpenChanged(isOpen) {
|
|
11914
11941
|
if (!isOpen) {
|
|
11915
11942
|
this.revealedGroupLabel = null;
|
|
@@ -13624,13 +13651,13 @@ class PdsCombobox {
|
|
|
13624
13651
|
]
|
|
13625
13652
|
.filter(Boolean)
|
|
13626
13653
|
.join(' ');
|
|
13627
|
-
return (hAsync(Host, { key: '
|
|
13654
|
+
return (hAsync(Host, { key: 'c3bda161c67bab75f306c7f38435d279e5a88756', "aria-disabled": this.disabled ? 'true' : null }, hAsync("div", { key: '92b3f83c14a7296b3b2671eaef538a15743f695f', class: "pds-combobox", tabIndex: -1, onFocusout: this.onComboboxFocusOut, part: "combobox" }, this.hasVisibleLabel && (hAsync("label", { key: '4a2dba09dd6db9893e21346b861b4c6cb891112b', htmlFor: this.trigger === 'input' ? this.componentId : undefined, id: this.labelId, class: "pds-combobox__label", onClick: this.onLabelClick }, this.label)), this.trigger === 'input' ? (hAsync("div", { class: "pds-combobox__input-wrapper", style: { width: this.triggerWidth } }, hAsync("input", { ref: el => {
|
|
13628
13655
|
this.inputEl = el;
|
|
13629
13656
|
this.triggerEl = el;
|
|
13630
13657
|
}, class: {
|
|
13631
13658
|
'pds-combobox__input': true,
|
|
13632
13659
|
'pds-combobox__input--invalid': this.isInvalid(),
|
|
13633
|
-
}, type: "text", role: "combobox", "aria-autocomplete": "list", "aria-haspopup": this.inputPopupRole === 'tree' ? 'tree' : undefined, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, value: this.displayText, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput, onClick: this.handleInputClick, onKeyDown: this.handleKeyDown, autocomplete: "off", part: "input" }), hAsync("pds-icon", { icon: "enlarge", "aria-hidden": "true", class: "pds-combobox__input-icon" }))) : this.trigger === 'chip' ? (hAsync("div", { class: this.getChipTriggerClass(), style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "chip-trigger" }, this.renderChipTriggerContent())) : (hAsync("div", { class: triggerClass, style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "button-trigger" }, this.renderButtonTriggerContent())), this.renderMessages(), hAsync("div", { key: '
|
|
13660
|
+
}, type: "text", role: "combobox", "aria-autocomplete": "list", "aria-haspopup": this.inputPopupRole === 'tree' ? 'tree' : undefined, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.hideLabel ? this.label : undefined, id: this.componentId, value: this.displayText, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput, onClick: this.handleInputClick, onKeyDown: this.handleKeyDown, autocomplete: "off", part: "input" }), hAsync("pds-icon", { icon: "enlarge", "aria-hidden": "true", class: "pds-combobox__input-icon" }))) : this.trigger === 'chip' ? (hAsync("div", { class: this.getChipTriggerClass(), style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "chip-trigger" }, this.renderChipTriggerContent())) : (hAsync("div", { class: triggerClass, style: { width: this.triggerWidth }, role: this.usesPanelSearch ? 'button' : 'combobox', "aria-haspopup": this.triggerPopupRole, "aria-controls": this.listboxId, "aria-describedby": assignDescription(this.componentId, this.isInvalid(), this.helperMessage, this.errorMessage), "aria-invalid": this.isInvalid() ? 'true' : undefined, "aria-activedescendant": this.usesPanelSearch ? undefined : this.activeDescendantId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : 'false', "aria-label": this.triggerAriaLabel, "aria-labelledby": this.triggerLabelledBy, id: this.componentId, tabIndex: this.disabled ? -1 : 0, onClick: this.onButtonTriggerClick, "data-layout": this.customTriggerContent, onKeyDown: this.onButtonTriggerKeyDown, onKeyUp: this.onButtonTriggerKeyUp, ref: el => (this.triggerEl = el), part: "button-trigger" }, this.renderButtonTriggerContent())), this.renderMessages(), hAsync("div", { key: 'b8d358339bb26037b6c3c464bd4e13fe978f7857', style: { display: 'none' } }, hAsync("slot", { key: '4aa4c2b8f2b57e13d1e958cc745c61e39e800529', onSlotchange: () => this.updateOptions() })), this.renderDropdown(), this.groupDisplay !== 'inline' && [
|
|
13634
13661
|
hAsync("span", { key: "drill-status", class: "visually-hidden", role: "status", "aria-live": "polite" }, this.isOpen && this.effectiveGroupDisplay === 'drill-in' && this.openGroup !== null ? this.openGroup.label : ''),
|
|
13635
13662
|
// Its own region: sharing one, revealing a row then opening it would leave the text the
|
|
13636
13663
|
// same, and opening the group would go unannounced.
|
|
@@ -13649,6 +13676,9 @@ class PdsCombobox {
|
|
|
13649
13676
|
"flyoutFallback": [{
|
|
13650
13677
|
"flyoutFallbackChanged": 0
|
|
13651
13678
|
}],
|
|
13679
|
+
"disabled": [{
|
|
13680
|
+
"disabledChanged": 0
|
|
13681
|
+
}],
|
|
13652
13682
|
"isOpen": [{
|
|
13653
13683
|
"isOpenChanged": 0
|
|
13654
13684
|
}],
|
|
@@ -16082,22 +16112,24 @@ function unwrapReconnectedContent(container, selector, contentSelector) {
|
|
|
16082
16112
|
}
|
|
16083
16113
|
}
|
|
16084
16114
|
|
|
16085
|
-
const pdsDrawerCss = () => `.pds-drawer__modal>.pds-modal__backdrop{-ms-flex-align:stretch;align-items:stretch
|
|
16115
|
+
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}`;
|
|
16086
16116
|
|
|
16087
|
-
// Known selectors for content Pine components portal
|
|
16088
|
-
//
|
|
16117
|
+
// Known selectors for content Pine components portal out of place rather than
|
|
16118
|
+
// rendering where they are — pds-tooltip and pds-combobox's dropdown in
|
|
16119
|
+
// document.body, pds-popover in the body or the open dialog it's in.
|
|
16089
16120
|
// A pointerdown landing on one of these is not "outside" the drawer in the
|
|
16090
16121
|
// sense light dismiss cares about: it belongs to an overlay something inside
|
|
16091
16122
|
// the drawer opened, even though it is not a DOM descendant of the drawer.
|
|
16092
16123
|
const PORTALED_OVERLAY_SELECTOR = '.pds-popover, .pds-tooltip, .pds-combobox-dropdown-portal';
|
|
16093
16124
|
/**
|
|
16094
|
-
* A
|
|
16125
|
+
* A side panel composed from `pds-modal`, non-modal by default.
|
|
16095
16126
|
*
|
|
16096
|
-
*
|
|
16097
|
-
* dimming, no blur, no scroll lock, no click blocking.
|
|
16098
|
-
* `pds-modal` internally with `disableTopLayer`
|
|
16099
|
-
* suppressed, and adds the edge, width and dismiss behavior a
|
|
16100
|
-
* needs on top.
|
|
16127
|
+
* By default, unlike `pds-modal`, the page stays interactive while a drawer
|
|
16128
|
+
* is open: no dimming, no blur, no scroll lock, no click blocking.
|
|
16129
|
+
* `pds-drawer` renders a `pds-modal` internally with `disableTopLayer` on and
|
|
16130
|
+
* its backdrop suppressed, and adds the edge, width and dismiss behavior a
|
|
16131
|
+
* side panel needs on top. With `modal`, it opens that `pds-modal` in the top
|
|
16132
|
+
* layer instead and keeps its backdrop. It does not reimplement focus, Escape or dialog semantics —
|
|
16101
16133
|
* those come from `pds-modal` unchanged.
|
|
16102
16134
|
* @lightDom renders-markup
|
|
16103
16135
|
*/
|
|
@@ -16128,8 +16160,18 @@ class PdsDrawer {
|
|
|
16128
16160
|
*/
|
|
16129
16161
|
this.scrollable = true;
|
|
16130
16162
|
/**
|
|
16131
|
-
* Whether the drawer
|
|
16132
|
-
*
|
|
16163
|
+
* Whether the drawer is modal. A modal drawer dims the page behind it with a
|
|
16164
|
+
* backdrop, makes the page inert, and keeps focus inside the drawer, like
|
|
16165
|
+
* `pds-modal`. Use it for a task the page should wait on. Leave it off for a
|
|
16166
|
+
* panel people work alongside the page. Read when the drawer opens; changing
|
|
16167
|
+
* it while the drawer is open is not supported.
|
|
16168
|
+
* @default false
|
|
16169
|
+
*/
|
|
16170
|
+
this.modal = false;
|
|
16171
|
+
/**
|
|
16172
|
+
* Whether the drawer can be dismissed with a pointerdown outside it (in a
|
|
16173
|
+
* `modal` drawer, a click on its backdrop).
|
|
16174
|
+
* Replaces `pds-modal`'s `backdropDismiss`.
|
|
16133
16175
|
* This also gates Escape, matching how `backdropDismiss` gates Escape on
|
|
16134
16176
|
* `pds-modal` today: setting this to `false` means the close button is the
|
|
16135
16177
|
* only way out.
|
|
@@ -16148,7 +16190,8 @@ class PdsDrawer {
|
|
|
16148
16190
|
* background event while the user is mid-task elsewhere on the page —
|
|
16149
16191
|
* moving focus there would interrupt them, and the page stays live under
|
|
16150
16192
|
* a non-modal drawer, so it is a genuine data-entry risk, not just an
|
|
16151
|
-
* annoyance.
|
|
16193
|
+
* annoyance. A `modal` drawer ignores `none`: the page behind it is inert,
|
|
16194
|
+
* so focus starts in the drawer.
|
|
16152
16195
|
* @default 'auto'
|
|
16153
16196
|
*/
|
|
16154
16197
|
this.initialFocus = 'auto';
|
|
@@ -16194,7 +16237,8 @@ class PdsDrawer {
|
|
|
16194
16237
|
// page underneath stays genuinely clickable, which means a click there
|
|
16195
16238
|
// never reaches pds-modal's backdrop element at all.
|
|
16196
16239
|
handleOutsidePointerDown(e) {
|
|
16197
|
-
|
|
16240
|
+
// A modal drawer's backdrop takes the click instead, through pds-modal.
|
|
16241
|
+
if (this.modal || !this.lightDismiss || !this.open)
|
|
16198
16242
|
return;
|
|
16199
16243
|
const target = e.target;
|
|
16200
16244
|
if (!target)
|
|
@@ -16204,7 +16248,7 @@ class PdsDrawer {
|
|
|
16204
16248
|
if (target.closest(PORTALED_OVERLAY_SELECTOR))
|
|
16205
16249
|
return;
|
|
16206
16250
|
// A datepicker's portaled calendar counts as inside only when its datepicker is in the drawer,
|
|
16207
|
-
// or in an overlay portaled from it (a pds-popover in the drawer puts its content
|
|
16251
|
+
// or in an overlay portaled from it (a pds-popover in the drawer puts its content beside it).
|
|
16208
16252
|
const calendar = target.closest('.pds-datepicker-calendar-portal');
|
|
16209
16253
|
const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
|
|
16210
16254
|
if (owner && (containsComposed$1(this.el, owner) || closest$1(PORTALED_OVERLAY_SELECTOR, owner)))
|
|
@@ -16220,11 +16264,11 @@ class PdsDrawer {
|
|
|
16220
16264
|
this.open = false;
|
|
16221
16265
|
}
|
|
16222
16266
|
render() {
|
|
16223
|
-
return (hAsync(Host, { key: '
|
|
16267
|
+
return (hAsync(Host, { key: '287bf043c991209488eb1b617031acffb59ff9af', class: {
|
|
16224
16268
|
'pds-drawer': true,
|
|
16225
16269
|
[`pds-drawer--${this.side}`]: true,
|
|
16226
16270
|
[`pds-drawer--${this.size}`]: true,
|
|
16227
|
-
} }, hAsync("pds-modal", { key: '
|
|
16271
|
+
} }, hAsync("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' }, hAsync("slot", { key: '56bbe9b5c26b10b07c0f503ba147899a57a5de85' }))));
|
|
16228
16272
|
}
|
|
16229
16273
|
get el() { return getElement(this); }
|
|
16230
16274
|
static get style() { return pdsDrawerCss(); }
|
|
@@ -16237,6 +16281,7 @@ class PdsDrawer {
|
|
|
16237
16281
|
"side": [1],
|
|
16238
16282
|
"size": [1],
|
|
16239
16283
|
"scrollable": [4],
|
|
16284
|
+
"modal": [4],
|
|
16240
16285
|
"lightDismiss": [4, "light-dismiss"],
|
|
16241
16286
|
"initialFocus": [1, "initial-focus"]
|
|
16242
16287
|
},
|
|
@@ -16588,15 +16633,19 @@ class PdsDropdownMenu {
|
|
|
16588
16633
|
this.focusItemByIndex(prevIndex);
|
|
16589
16634
|
}
|
|
16590
16635
|
}
|
|
16636
|
+
// Escape is taken in document's capture phase, before a modal around the menu hears it on
|
|
16637
|
+
// document and closes too.
|
|
16638
|
+
handleEscapeKeyDown(event) {
|
|
16639
|
+
if (!this.isOpen || event.key !== 'Escape' || event.defaultPrevented)
|
|
16640
|
+
return;
|
|
16641
|
+
event.preventDefault();
|
|
16642
|
+
this.closeDropdown();
|
|
16643
|
+
}
|
|
16591
16644
|
// Handle keyboard events for the dropdown
|
|
16592
16645
|
handleKeyDown(event) {
|
|
16593
16646
|
if (!this.isOpen)
|
|
16594
16647
|
return;
|
|
16595
16648
|
switch (event.key) {
|
|
16596
|
-
case 'Escape':
|
|
16597
|
-
event.preventDefault();
|
|
16598
|
-
this.closeDropdown();
|
|
16599
|
-
break;
|
|
16600
16649
|
case 'ArrowDown':
|
|
16601
16650
|
event.preventDefault();
|
|
16602
16651
|
this.focusNextItem();
|
|
@@ -16688,7 +16737,7 @@ class PdsDropdownMenu {
|
|
|
16688
16737
|
}
|
|
16689
16738
|
}
|
|
16690
16739
|
render() {
|
|
16691
|
-
return (hAsync(Host, { key: '
|
|
16740
|
+
return (hAsync(Host, { key: '18dac4d59ea236fe171f4c16f6571cb1547059c6', id: this.componentId }, hAsync("slot", { key: '95201a75a33ccb70dbd51a5cf9d78c76ebf26f65', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), hAsync("pds-box", { key: '7fc588f40f607ad81ad70bf74a525d078d32a80b', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", part: "menu-panel" }, hAsync("div", { key: '73d13d94edccb68db7b703f930b50f729334efa8', class: { 'pds-dropdown-menu__header': true, 'is-hidden': !this.hasHeader } }, hAsync("slot", { key: '7066f3a6f71c8961326f38f0509f1c0cc17098ae', name: "header", onSlotchange: this.handleHeaderSlotChange })), hAsync("div", { key: '9f07ec488b688c58c6422b575015ccd364075fe8', class: "pds-dropdown-menu__items", role: "menu", "aria-orientation": "vertical" }, hAsync("slot", { key: 'd0aad3f9ac3b58779669411523adbb8878dec61c', onSlotchange: this.handleSlotChange })))));
|
|
16692
16741
|
}
|
|
16693
16742
|
get host() { return getElement(this); }
|
|
16694
16743
|
static get style() { return pdsDropdownMenuCss(); }
|
|
@@ -16701,7 +16750,7 @@ class PdsDropdownMenu {
|
|
|
16701
16750
|
"currentFocusIndex": [32],
|
|
16702
16751
|
"hasHeader": [32]
|
|
16703
16752
|
},
|
|
16704
|
-
"$listeners$": [[8, "keydown", "handleKeyDown"], [8, "click", "handleWindowClick"]],
|
|
16753
|
+
"$listeners$": [[6, "keydown", "handleEscapeKeyDown"], [8, "keydown", "handleKeyDown"], [8, "click", "handleWindowClick"]],
|
|
16705
16754
|
"$lazyBundleId$": "-",
|
|
16706
16755
|
"$attrsToReflect$": []
|
|
16707
16756
|
}; }
|
|
@@ -18570,8 +18619,36 @@ function containsComposed(ancestor, node) {
|
|
|
18570
18619
|
}
|
|
18571
18620
|
return false;
|
|
18572
18621
|
}
|
|
18622
|
+
/**
|
|
18623
|
+
* Every open modal, with the order it opened in, which ranks top-layer modals and the modals
|
|
18624
|
+
* inside them. Kept here rather than queried from the document, which can't see a modal inside
|
|
18625
|
+
* another component's shadow root.
|
|
18626
|
+
*/
|
|
18627
|
+
const openModals = new Map();
|
|
18628
|
+
let openSequence = 0;
|
|
18629
|
+
/** Whether an open auto popover's panel sits in `root`, including inside shadow roots under it. */
|
|
18630
|
+
function hasOpenPopover(root) {
|
|
18631
|
+
if (root.querySelector('[data-pds-popover-open]'))
|
|
18632
|
+
return true;
|
|
18633
|
+
return Array.from(root.querySelectorAll('*')).some(el => !!el.shadowRoot && hasOpenPopover(el.shadowRoot));
|
|
18634
|
+
}
|
|
18635
|
+
/**
|
|
18636
|
+
* Whether `a` comes before `b` in the page. `compareDocumentPosition` is arbitrary across a shadow
|
|
18637
|
+
* boundary, so each side climbs to its host until both are in the same tree.
|
|
18638
|
+
*/
|
|
18639
|
+
function precedesComposed(a, b) {
|
|
18640
|
+
// A document has no host, which ends each climb.
|
|
18641
|
+
for (let x = a; x; x = x.getRootNode().host) {
|
|
18642
|
+
for (let y = b; y; y = y.getRootNode().host) {
|
|
18643
|
+
if (x.getRootNode() === y.getRootNode()) {
|
|
18644
|
+
return !!(x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING);
|
|
18645
|
+
}
|
|
18646
|
+
}
|
|
18647
|
+
}
|
|
18648
|
+
return false;
|
|
18649
|
+
}
|
|
18573
18650
|
/** The focused element, followed down through shadow roots to the control that has focus. */
|
|
18574
|
-
function deepActiveElement() {
|
|
18651
|
+
function deepActiveElement$1() {
|
|
18575
18652
|
var _a;
|
|
18576
18653
|
let active = document.activeElement;
|
|
18577
18654
|
while ((_a = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement)
|
|
@@ -18588,7 +18665,8 @@ class PdsModal {
|
|
|
18588
18665
|
this.pdsModalClose = createEvent(this, "pdsModalClose");
|
|
18589
18666
|
this.focusableElements = [];
|
|
18590
18667
|
/**
|
|
18591
|
-
* Whether the modal can be dismissed by clicking the backdrop
|
|
18668
|
+
* Whether the modal can be dismissed by clicking the backdrop, pressing Escape, or the browser's
|
|
18669
|
+
* own close request (such as a back gesture)
|
|
18592
18670
|
* @default true
|
|
18593
18671
|
*/
|
|
18594
18672
|
this.backdropDismiss = true;
|
|
@@ -18636,19 +18714,33 @@ class PdsModal {
|
|
|
18636
18714
|
* Stores the list of focusable elements in the modal
|
|
18637
18715
|
*/
|
|
18638
18716
|
this.focusableElementsArray = [];
|
|
18717
|
+
// The browser's own close request (an Escape nothing prevented, a back gesture) would close the
|
|
18718
|
+
// dialog without updating `open`, so close it through hideModal() instead, or not at all.
|
|
18719
|
+
this.handleCancel = (e) => {
|
|
18720
|
+
e.preventDefault();
|
|
18721
|
+
if (!this.open)
|
|
18722
|
+
return;
|
|
18723
|
+
// The request reaches the top-layer dialog even when a disableTopLayer modal inside it is on
|
|
18724
|
+
// top; that one closes first, as it would on Escape.
|
|
18725
|
+
const top = this.innermostOpenModal();
|
|
18726
|
+
const target = (top && containsComposed(this.el, top) ? top : this.el);
|
|
18727
|
+
if (target.backdropDismiss)
|
|
18728
|
+
target.hideModal();
|
|
18729
|
+
};
|
|
18639
18730
|
this.handleBackdropClick = (e) => {
|
|
18640
18731
|
if (!this.backdropDismiss || !this.open)
|
|
18641
18732
|
return;
|
|
18642
|
-
|
|
18733
|
+
// This modal's own backdrop; a nested modal's backdrop handles its own clicks.
|
|
18734
|
+
if (e.target === this.modalRef) {
|
|
18643
18735
|
e.stopPropagation();
|
|
18644
18736
|
// Only close if this is the innermost modal
|
|
18645
|
-
if (this.
|
|
18737
|
+
if (this.innermostOpenModal() === this.el) {
|
|
18646
18738
|
this.hideModal();
|
|
18647
18739
|
}
|
|
18648
18740
|
}
|
|
18649
18741
|
};
|
|
18650
18742
|
this.handleKeyDown = (e) => {
|
|
18651
|
-
var _a, _b, _c;
|
|
18743
|
+
var _a, _b, _c, _d;
|
|
18652
18744
|
// If the modal is not open, don't handle any keyboard events
|
|
18653
18745
|
if (!this.open)
|
|
18654
18746
|
return;
|
|
@@ -18671,24 +18763,39 @@ class PdsModal {
|
|
|
18671
18763
|
if (!('__pdsActiveElementAtEscape' in eventSnapshot)) {
|
|
18672
18764
|
const activeAtDispatch = document.activeElement;
|
|
18673
18765
|
eventSnapshot.__pdsActiveElementAtEscape = activeAtDispatch;
|
|
18766
|
+
// Followed into shadow roots: for a modal inside one, document.activeElement is only the host.
|
|
18767
|
+
eventSnapshot.__pdsDeepActiveElementAtEscape = deepActiveElement$1();
|
|
18674
18768
|
const topLayerDialog = (_a = activeAtDispatch === null || activeAtDispatch === void 0 ? void 0 : activeAtDispatch.closest('dialog')) !== null && _a !== void 0 ? _a : null;
|
|
18675
18769
|
eventSnapshot.__pdsTopLayerDialogAtEscape = topLayerDialog;
|
|
18676
18770
|
eventSnapshot.__pdsTopLayerDialogWasModalAtEscape = !!(topLayerDialog && topLayerDialog.matches(':modal'));
|
|
18771
|
+
// A control that closed on this Escape (a combobox on its own element, a dropdown menu or
|
|
18772
|
+
// multiselect in document's capture phase) has prevented it before this bubble listener.
|
|
18773
|
+
// Read before any modal prevents it below.
|
|
18774
|
+
eventSnapshot.__pdsEscapeHandledInside = e.defaultPrevented;
|
|
18775
|
+
// Which modal is innermost is read once too: the inner one closing first would make its
|
|
18776
|
+
// outer modal the innermost by the time that modal's listener runs.
|
|
18777
|
+
eventSnapshot.__pdsInnermostModalAtEscape = this.innermostOpenModal();
|
|
18677
18778
|
}
|
|
18779
|
+
if (eventSnapshot.__pdsEscapeHandledInside)
|
|
18780
|
+
return;
|
|
18678
18781
|
// Leave Escape to a genuinely stacked-above overlay (disableTopLayer's
|
|
18679
18782
|
// reason for existing) — not just to anything outside this modal.
|
|
18680
18783
|
const active = eventSnapshot.__pdsActiveElementAtEscape;
|
|
18681
18784
|
if (this.disableTopLayer &&
|
|
18682
18785
|
active &&
|
|
18683
18786
|
active !== document.body &&
|
|
18684
|
-
!this.el.
|
|
18685
|
-
this.isStackedAboveOverlay(active, (
|
|
18787
|
+
!containsComposed(this.el, (_b = eventSnapshot.__pdsDeepActiveElementAtEscape) !== null && _b !== void 0 ? _b : active) &&
|
|
18788
|
+
this.isStackedAboveOverlay(active, (_c = eventSnapshot.__pdsTopLayerDialogAtEscape) !== null && _c !== void 0 ? _c : null, (_d = eventSnapshot.__pdsTopLayerDialogWasModalAtEscape) !== null && _d !== void 0 ? _d : false)) {
|
|
18686
18789
|
return;
|
|
18687
18790
|
}
|
|
18791
|
+
// An open popover inside takes Escape from its own document listener, which runs after this
|
|
18792
|
+
// one, so leave the key for it. Its preventDefault() keeps the native dialog open.
|
|
18793
|
+
if (this.modalRef && hasOpenPopover(this.modalRef))
|
|
18794
|
+
return;
|
|
18688
18795
|
// Always prevent native dialog close behavior
|
|
18689
18796
|
e.preventDefault();
|
|
18690
18797
|
// Only close if backdropDismiss is enabled and this is the innermost modal
|
|
18691
|
-
if (this.backdropDismiss && this.
|
|
18798
|
+
if (this.backdropDismiss && eventSnapshot.__pdsInnermostModalAtEscape === this.el) {
|
|
18692
18799
|
this.hideModal();
|
|
18693
18800
|
}
|
|
18694
18801
|
return;
|
|
@@ -18708,7 +18815,7 @@ class PdsModal {
|
|
|
18708
18815
|
// Every open modal hears this keydown. When focus is in a modal dialog opened above this one,
|
|
18709
18816
|
// that dialog traps Tab: this modal's list also holds its controls, so it would wrap first. A
|
|
18710
18817
|
// non-modal dialog inside (a disableTopLayer modal) doesn't trap, so this one still does.
|
|
18711
|
-
const activeElement = deepActiveElement();
|
|
18818
|
+
const activeElement = deepActiveElement$1();
|
|
18712
18819
|
if (!activeElement || this.modalDialogAbove(activeElement))
|
|
18713
18820
|
return;
|
|
18714
18821
|
// Content can change while the modal is open (rows fetched in, sections shown), so the
|
|
@@ -18748,8 +18855,6 @@ class PdsModal {
|
|
|
18748
18855
|
}
|
|
18749
18856
|
componentDidLoad() {
|
|
18750
18857
|
this.modalRef = this.el.querySelector('.pds-modal__backdrop');
|
|
18751
|
-
// Add keyboard event listener
|
|
18752
|
-
document.addEventListener('keydown', this.handleKeyDown);
|
|
18753
18858
|
// @Watch('open') only fires on a later change, not the prop's initial
|
|
18754
18859
|
// value — a modal mounted with `open` already true (static markup, or a
|
|
18755
18860
|
// framework passing it on first render) would otherwise never call
|
|
@@ -18765,9 +18870,18 @@ class PdsModal {
|
|
|
18765
18870
|
componentDidRender() {
|
|
18766
18871
|
unwrapReconnectedContent(this.el.querySelector('.pds-modal'), 'dialog.pds-modal__backdrop', '.pds-modal');
|
|
18767
18872
|
}
|
|
18873
|
+
// Here rather than in componentDidLoad, which runs once: a modal taken out of the page and put
|
|
18874
|
+
// back (a morph or a framework moving it) gets its keyboard handling, and its place among the
|
|
18875
|
+
// open modals, back too. Adding the same listener twice is a no-op.
|
|
18876
|
+
connectedCallback() {
|
|
18877
|
+
document.addEventListener('keydown', this.handleKeyDown);
|
|
18878
|
+
if (this.open && !openModals.has(this.el))
|
|
18879
|
+
openModals.set(this.el, ++openSequence);
|
|
18880
|
+
}
|
|
18768
18881
|
disconnectedCallback() {
|
|
18769
18882
|
// Clean up event listener
|
|
18770
18883
|
document.removeEventListener('keydown', this.handleKeyDown);
|
|
18884
|
+
openModals.delete(this.el);
|
|
18771
18885
|
}
|
|
18772
18886
|
handleOpenChange(newValue) {
|
|
18773
18887
|
if (newValue) {
|
|
@@ -18832,6 +18946,9 @@ class PdsModal {
|
|
|
18832
18946
|
this.modalRef.showModal();
|
|
18833
18947
|
}
|
|
18834
18948
|
this.open = true;
|
|
18949
|
+
// Showing an open modal again doesn't move it above one opened after it.
|
|
18950
|
+
if (!openModals.has(this.el))
|
|
18951
|
+
openModals.set(this.el, ++openSequence);
|
|
18835
18952
|
// Update focusable elements and set initial focus
|
|
18836
18953
|
// Using a longer timeout to ensure all components are fully rendered
|
|
18837
18954
|
setTimeout(() => {
|
|
@@ -18894,6 +19011,7 @@ class PdsModal {
|
|
|
18894
19011
|
const focusAlreadyMovedElsewhere = activeElement !== null && activeElement !== document.body && !this.modalRef.contains(activeElement);
|
|
18895
19012
|
this.modalRef.close();
|
|
18896
19013
|
this.open = false;
|
|
19014
|
+
openModals.delete(this.el);
|
|
18897
19015
|
// Restore focus to the element that was focused before the modal was opened
|
|
18898
19016
|
if (!focusAlreadyMovedElsewhere &&
|
|
18899
19017
|
this.previousActiveElement &&
|
|
@@ -18912,7 +19030,9 @@ class PdsModal {
|
|
|
18912
19030
|
*/
|
|
18913
19031
|
getBackdropZIndex(modal) {
|
|
18914
19032
|
const backdrop = modal.querySelector('.pds-modal__backdrop');
|
|
18915
|
-
|
|
19033
|
+
// `auto` (no z-index token loaded) parses to NaN, which no comparison can rank.
|
|
19034
|
+
const zIndex = backdrop ? parseInt(getComputedStyle(backdrop).zIndex, 10) : -1;
|
|
19035
|
+
return Number.isNaN(zIndex) ? 0 : zIndex;
|
|
18916
19036
|
}
|
|
18917
19037
|
/**
|
|
18918
19038
|
* Whether `active` sits inside a surface actually stacked above this modal.
|
|
@@ -18939,7 +19059,8 @@ class PdsModal {
|
|
|
18939
19059
|
* lose that evidence depending on listener order.
|
|
18940
19060
|
*/
|
|
18941
19061
|
isStackedAboveOverlay(active, topLayerDialog, topLayerDialogWasModal) {
|
|
18942
|
-
|
|
19062
|
+
// A top-layer dialog this modal sits inside is underneath it, not an overlay above.
|
|
19063
|
+
if (topLayerDialog && topLayerDialog !== this.modalRef && topLayerDialogWasModal && !containsComposed(topLayerDialog, this.el)) {
|
|
18943
19064
|
return true;
|
|
18944
19065
|
}
|
|
18945
19066
|
const ownZIndex = this.getBackdropZIndex(this.el);
|
|
@@ -18955,24 +19076,37 @@ class PdsModal {
|
|
|
18955
19076
|
return false;
|
|
18956
19077
|
}
|
|
18957
19078
|
/**
|
|
18958
|
-
*
|
|
19079
|
+
* The open modal that takes Escape or a backdrop click, among those with no other open modal
|
|
19080
|
+
* inside them (a nested modal's backdrop can share its outer modal's z-index). A top-layer dialog
|
|
19081
|
+
* (or a modal inside one) paints above anything outside it, and within the top layer the last
|
|
19082
|
+
* opened is on top. Modals in the same layer (the page, or one top-layer dialog) then rank by
|
|
19083
|
+
* the highest backdrop, then the one later in the page.
|
|
18959
19084
|
*/
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
const
|
|
18963
|
-
|
|
18964
|
-
|
|
18965
|
-
//
|
|
18966
|
-
const
|
|
18967
|
-
|
|
18968
|
-
|
|
18969
|
-
|
|
18970
|
-
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
18974
|
-
|
|
18975
|
-
|
|
19085
|
+
innermostOpenModal() {
|
|
19086
|
+
const open = Array.from(openModals.keys()).filter(modal => modal.isConnected);
|
|
19087
|
+
const innermost = open.filter(modal => !open.some(other => other !== modal && containsComposed(modal, other)));
|
|
19088
|
+
const byDocumentOrder = [...innermost].sort((a, b) => (precedesComposed(a, b) ? -1 : 1));
|
|
19089
|
+
// A modal inside a top-layer dialog paints in that dialog's place in the top layer, even when it
|
|
19090
|
+
// isn't in the top layer itself (disableTopLayer), so that dialog's open order ranks it first.
|
|
19091
|
+
const rank = (modal) => {
|
|
19092
|
+
var _a;
|
|
19093
|
+
const backdrop = modal.querySelector('.pds-modal__backdrop');
|
|
19094
|
+
const topLayerDialog = backdrop ? closest$1('dialog:modal', backdrop) : null;
|
|
19095
|
+
const topLayerModal = topLayerDialog === null || topLayerDialog === void 0 ? void 0 : topLayerDialog.closest('pds-modal');
|
|
19096
|
+
const layer = topLayerDialog ? ((_a = (topLayerModal && openModals.get(topLayerModal))) !== null && _a !== void 0 ? _a : 0) : 0;
|
|
19097
|
+
return [topLayerDialog ? 1 : 0, layer, this.getBackdropZIndex(modal), byDocumentOrder.indexOf(modal)];
|
|
19098
|
+
};
|
|
19099
|
+
let top = null;
|
|
19100
|
+
let topRank = [-1, -1, -1, -1];
|
|
19101
|
+
for (const modal of innermost) {
|
|
19102
|
+
const modalRank = rank(modal);
|
|
19103
|
+
const above = modalRank.findIndex((value, i) => value !== topRank[i]);
|
|
19104
|
+
if (above >= 0 && modalRank[above] > topRank[above]) {
|
|
19105
|
+
top = modal;
|
|
19106
|
+
topRank = modalRank;
|
|
19107
|
+
}
|
|
19108
|
+
}
|
|
19109
|
+
return top;
|
|
18976
19110
|
}
|
|
18977
19111
|
/** Whether a modal dialog other than this one sits between the focused element and this modal. */
|
|
18978
19112
|
modalDialogAbove(active) {
|
|
@@ -19012,14 +19146,14 @@ class PdsModal {
|
|
|
19012
19146
|
}
|
|
19013
19147
|
render() {
|
|
19014
19148
|
const [sizeClass = 'md', customSize] = this.resolveSize();
|
|
19015
|
-
return (hAsync("dialog", { key: '
|
|
19149
|
+
return (hAsync("dialog", { key: '0633d4e8a7cb81f2f9280e754564960a00a4d60b', class: {
|
|
19016
19150
|
'pds-modal__backdrop': true,
|
|
19017
19151
|
'open': this.open
|
|
19018
|
-
}, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick }, hAsync("div", { key: '
|
|
19152
|
+
}, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick, onCancel: this.handleCancel }, hAsync("div", { key: '466f8a3476cf066817554f47ec7d3a0e3ab10b89', class: {
|
|
19019
19153
|
'pds-modal': true,
|
|
19020
19154
|
[`pds-modal--${sizeClass}`]: true,
|
|
19021
19155
|
'pds-modal--scrollable': this.scrollable
|
|
19022
|
-
}, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, hAsync("slot", { key: '
|
|
19156
|
+
}, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, hAsync("slot", { key: '01ca45c96540416216a1082bad52b137720f0f4d' }))));
|
|
19023
19157
|
}
|
|
19024
19158
|
get el() { return getElement(this); }
|
|
19025
19159
|
static get watchers() { return {
|
|
@@ -19852,11 +19986,12 @@ class PdsMultiselect {
|
|
|
19852
19986
|
}
|
|
19853
19987
|
/**
|
|
19854
19988
|
* Handle global keyboard events for accessibility.
|
|
19855
|
-
* Closes dropdown on Escape key press regardless of focus location.
|
|
19989
|
+
* Closes dropdown on Escape key press regardless of focus location. Taken in document's capture
|
|
19990
|
+
* phase, before a modal around the multiselect hears it on document and closes too.
|
|
19856
19991
|
*/
|
|
19857
19992
|
handleWindowKeyDown(event) {
|
|
19858
19993
|
var _a;
|
|
19859
|
-
if (!this.isOpen)
|
|
19994
|
+
if (!this.isOpen || event.defaultPrevented)
|
|
19860
19995
|
return;
|
|
19861
19996
|
if (event.key === 'Escape') {
|
|
19862
19997
|
event.preventDefault();
|
|
@@ -20546,10 +20681,10 @@ class PdsMultiselect {
|
|
|
20546
20681
|
}
|
|
20547
20682
|
render() {
|
|
20548
20683
|
const hasSelections = this.selectedItems.length > 0;
|
|
20549
|
-
return (hAsync(Host, { key: '
|
|
20684
|
+
return (hAsync(Host, { key: 'fcc35a82c16d5cf35a49ce997f19618104f9cc45', "aria-disabled": this.disabled ? 'true' : null }, hAsync("div", { key: '72d1fdf759d9173f54bac80ec50aff651fd2b357', class: "pds-multiselect", onFocusout: this.handleContainerFocusOut }, this.label && (hAsync("label", { key: 'e28f02c2beb23dc2c0deefadbd0645b20d938d91', id: `${this.componentId}-label`, htmlFor: this.componentId, class: {
|
|
20550
20685
|
'pds-multiselect__label': true,
|
|
20551
20686
|
'visually-hidden': this.hideLabel,
|
|
20552
|
-
} }, this.label)), hAsync("div", { key: '
|
|
20687
|
+
} }, this.label)), hAsync("div", { key: '06539bf2c4b8da2889505a9f042d5cd6721b1853', class: "pds-multiselect__wrapper", ref: el => (this.containerEl = el), style: { width: this.triggerWidth } }, this.slottedTriggerEl ? (hAsync("slot", { name: "trigger" })) : this.selectedDisplay === 'pill' && this.pillPosition === 'inline' ? (hAsync("div", { ref: el => (this.pillInlineTriggerEl = el || undefined), part: "trigger", class: {
|
|
20553
20688
|
'pds-multiselect__trigger': true,
|
|
20554
20689
|
'pds-multiselect__trigger--open': this.isOpen,
|
|
20555
20690
|
'pds-multiselect__trigger--disabled': this.disabled,
|
|
@@ -20565,7 +20700,7 @@ class PdsMultiselect {
|
|
|
20565
20700
|
}, 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 }, hAsync("span", { class: {
|
|
20566
20701
|
'pds-multiselect__trigger-text': true,
|
|
20567
20702
|
'pds-multiselect__trigger-text--placeholder': !hasSelections || (this.selectedDisplay === 'pill' && this.pillPosition === 'below'),
|
|
20568
|
-
} }, this.getTriggerText()), hAsync("pds-icon", { "aria-hidden": "true", class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), hAsync("span", { key: '
|
|
20703
|
+
} }, this.getTriggerText()), hAsync("pds-icon", { "aria-hidden": "true", class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), hAsync("span", { key: '3364fc00bc744fcd599436a9cb6dc563564d89d9', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (hAsync("p", { key: 'bf712c65b9acb66e2998a43686fed408fc1ff48a', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (hAsync("p", { key: 'b485db6c2c3ae312cce2b90db60e850ad6dfdcf5', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, hAsync("pds-icon", { key: '20daf861cf9584f33f5a9574e9581acc487e7dfe', icon: danger, size: "small" }), this.errorMessage)), hAsync("div", { key: '018d333254771695a8c191f1cea40af6e78427a2', style: { display: 'none' } }, hAsync("slot", { key: '2ef4a01fbe5d294a9ead5cc1183c28341834539b' })))));
|
|
20569
20704
|
}
|
|
20570
20705
|
static get formAssociated() { return true; }
|
|
20571
20706
|
get el() { return getElement(this); }
|
|
@@ -20655,7 +20790,7 @@ class PdsMultiselect {
|
|
|
20655
20790
|
"clear": [64],
|
|
20656
20791
|
"refreshOptions": [64]
|
|
20657
20792
|
},
|
|
20658
|
-
"$listeners$": [[
|
|
20793
|
+
"$listeners$": [[6, "keydown", "handleWindowKeyDown"]],
|
|
20659
20794
|
"$lazyBundleId$": "-",
|
|
20660
20795
|
"$attrsToReflect$": []
|
|
20661
20796
|
}; }
|
|
@@ -20705,6 +20840,16 @@ const cssEscape = (value) => {
|
|
|
20705
20840
|
|
|
20706
20841
|
const pdsPopoverCss = () => `:host{--sizing-max-width-default:352px;display:inline-block}:host .pds-popover__trigger-wrapper{display:inline-block}:host .pds-popover__content-slot-wrapper{display:none}`;
|
|
20707
20842
|
|
|
20843
|
+
/** Open auto popovers, in the order they opened: Escape goes to the last one it applies to. */
|
|
20844
|
+
const openAutoPopovers = [];
|
|
20845
|
+
/** The focused element, followed down through shadow roots to the control that has focus. */
|
|
20846
|
+
function deepActiveElement() {
|
|
20847
|
+
var _a;
|
|
20848
|
+
let active = document.activeElement;
|
|
20849
|
+
while ((_a = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement)
|
|
20850
|
+
active = active.shadowRoot.activeElement;
|
|
20851
|
+
return active;
|
|
20852
|
+
}
|
|
20708
20853
|
/**
|
|
20709
20854
|
* @slot trigger - The trigger element for the popover
|
|
20710
20855
|
* @slot (default) - The content to display inside the popover
|
|
@@ -20740,7 +20885,7 @@ class PdsPopover {
|
|
|
20740
20885
|
*/
|
|
20741
20886
|
this.triggerObserver = null;
|
|
20742
20887
|
/**
|
|
20743
|
-
* Portal element
|
|
20888
|
+
* Portal element: in document.body, or in the open dialog the popover is in
|
|
20744
20889
|
*/
|
|
20745
20890
|
this.portalEl = null;
|
|
20746
20891
|
/**
|
|
@@ -20836,6 +20981,26 @@ class PdsPopover {
|
|
|
20836
20981
|
break;
|
|
20837
20982
|
}
|
|
20838
20983
|
};
|
|
20984
|
+
/** The focus style copied into a shadow root the panel opened in, which `document.head` can't reach. */
|
|
20985
|
+
this.shadowFocusStyle = null;
|
|
20986
|
+
/** The dialog the panel was opened in, closed along with it. */
|
|
20987
|
+
this.watchedDialog = null;
|
|
20988
|
+
this.onDialogClose = () => {
|
|
20989
|
+
this.hide();
|
|
20990
|
+
};
|
|
20991
|
+
/**
|
|
20992
|
+
* Inside a dialog, the panel can sit in a form that wraps the dialog, which a body portal never
|
|
20993
|
+
* did. A submit from the panel (a button in it, or Enter in a field in it) is stopped, so the
|
|
20994
|
+
* panel behaves as it does in the body.
|
|
20995
|
+
*/
|
|
20996
|
+
this.handleSubmitFromPanel = (event) => {
|
|
20997
|
+
if (!this.portalEl || !containsComposed$1(event.target, this.portalEl))
|
|
20998
|
+
return;
|
|
20999
|
+
if (containsComposed$1(this.portalEl, event.submitter) || containsComposed$1(this.portalEl, deepActiveElement())) {
|
|
21000
|
+
event.preventDefault();
|
|
21001
|
+
event.stopPropagation();
|
|
21002
|
+
}
|
|
21003
|
+
};
|
|
20839
21004
|
}
|
|
20840
21005
|
restorePlacementDefault(newValue) {
|
|
20841
21006
|
this.placement = restoreReflectedDefault(this.el, 'placement', newValue, 'right');
|
|
@@ -20898,19 +21063,23 @@ class PdsPopover {
|
|
|
20898
21063
|
(_a = this.triggerEl) === null || _a === void 0 ? void 0 : _a.addEventListener('click', this.handleTriggerClick);
|
|
20899
21064
|
this.observeTrigger();
|
|
20900
21065
|
this.linkTriggerToPortal();
|
|
20901
|
-
// Still open after a move: the trigger moved, so the portal follows it
|
|
21066
|
+
// Still open after a move: the trigger moved, so the portal follows it, into the dialog it
|
|
21067
|
+
// is in now, if any.
|
|
20902
21068
|
if (this.active) {
|
|
21069
|
+
this.placePortal();
|
|
20903
21070
|
requestAnimationFrame(() => this.handlePopoverPositioning());
|
|
20904
21071
|
}
|
|
20905
21072
|
}
|
|
20906
21073
|
disconnectedCallback() {
|
|
20907
21074
|
var _a;
|
|
20908
21075
|
// Moved in one operation (a DOM morph, or a framework reparenting it), the popover is
|
|
20909
|
-
// already back in the page. Its portal is
|
|
20910
|
-
// where it was.
|
|
21076
|
+
// already back in the page. Its portal is outside the popover, so it stays open, with focus
|
|
21077
|
+
// where it was; connectedCallback moves it to follow the popover.
|
|
20911
21078
|
if (this.el.isConnected)
|
|
20912
21079
|
return;
|
|
20913
21080
|
this.isComponentMounted = false;
|
|
21081
|
+
this.unwatchDialogClose();
|
|
21082
|
+
this.forgetOpen();
|
|
20914
21083
|
// Open, the content sits in the portal; put it back before the portal goes. Only listeners on
|
|
20915
21084
|
// the popover itself hear the close event now, but those are the ones mirroring its state.
|
|
20916
21085
|
if (this.active) {
|
|
@@ -20931,6 +21100,7 @@ class PdsPopover {
|
|
|
20931
21100
|
// Clean up all event listeners
|
|
20932
21101
|
this.removeLightDismissListeners();
|
|
20933
21102
|
this.removeScrollAndResizeListeners();
|
|
21103
|
+
document.removeEventListener('submit', this.handleSubmitFromPanel, true);
|
|
20934
21104
|
// Clear any pending debounce timers
|
|
20935
21105
|
this.clearDebounceTimers();
|
|
20936
21106
|
// Remove portal from DOM
|
|
@@ -20975,9 +21145,6 @@ class PdsPopover {
|
|
|
20975
21145
|
else {
|
|
20976
21146
|
this.portalEl.id = `${this.componentId}-portal`;
|
|
20977
21147
|
}
|
|
20978
|
-
// Add accessibility attributes for screen readers
|
|
20979
|
-
// Note: Native Popover API doesn't add a specific role, keeping semantic HTML
|
|
20980
|
-
this.portalEl.setAttribute('aria-modal', 'false'); // Not a modal, can interact with rest of page
|
|
20981
21148
|
// Append to body
|
|
20982
21149
|
document.body.appendChild(this.portalEl);
|
|
20983
21150
|
// Add global focus styles to match Pine design system
|
|
@@ -21061,7 +21228,27 @@ class PdsPopover {
|
|
|
21061
21228
|
// Clear tracking array
|
|
21062
21229
|
this.movedNodes = [];
|
|
21063
21230
|
}
|
|
21231
|
+
copyFocusStylesInto(root) {
|
|
21232
|
+
var _a, _b, _c;
|
|
21233
|
+
// Outside a shadow root the document's own style applies, so drop a copy left in one.
|
|
21234
|
+
if (!(root instanceof ShadowRoot)) {
|
|
21235
|
+
(_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
|
|
21236
|
+
this.shadowFocusStyle = null;
|
|
21237
|
+
return;
|
|
21238
|
+
}
|
|
21239
|
+
if (((_b = this.shadowFocusStyle) === null || _b === void 0 ? void 0 : _b.parentNode) === root || !this.portalEl)
|
|
21240
|
+
return;
|
|
21241
|
+
const source = document.querySelector(`style[data-pds-popover-focus="${cssEscape(this.portalEl.id)}"]`);
|
|
21242
|
+
if (!source)
|
|
21243
|
+
return;
|
|
21244
|
+
(_c = this.shadowFocusStyle) === null || _c === void 0 ? void 0 : _c.remove();
|
|
21245
|
+
this.shadowFocusStyle = source.cloneNode(true);
|
|
21246
|
+
root.appendChild(this.shadowFocusStyle);
|
|
21247
|
+
}
|
|
21064
21248
|
removePortal() {
|
|
21249
|
+
var _a;
|
|
21250
|
+
(_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
|
|
21251
|
+
this.shadowFocusStyle = null;
|
|
21065
21252
|
if (this.portalEl) {
|
|
21066
21253
|
// Remove the portal element from DOM
|
|
21067
21254
|
if (this.portalEl.parentNode) {
|
|
@@ -21086,9 +21273,13 @@ class PdsPopover {
|
|
|
21086
21273
|
// Record open timestamp to prevent immediate close from opening click
|
|
21087
21274
|
this.openTimestamp = Date.now();
|
|
21088
21275
|
this.linkTriggerToPortal();
|
|
21276
|
+
this.placePortal();
|
|
21089
21277
|
// Update portal content with latest slot content
|
|
21090
21278
|
this.updatePortalContent();
|
|
21091
|
-
// Show portal
|
|
21279
|
+
// Show portal. The attribute tells a modal around it that this popover takes Escape first; only
|
|
21280
|
+
// an auto popover listens for Escape.
|
|
21281
|
+
if (this.popoverType === 'auto')
|
|
21282
|
+
this.portalEl.setAttribute('data-pds-popover-open', '');
|
|
21092
21283
|
this.portalEl.style.display = 'block';
|
|
21093
21284
|
this.portalEl.style.opacity = '1';
|
|
21094
21285
|
this.portalEl.style.visibility = 'visible';
|
|
@@ -21100,8 +21291,10 @@ class PdsPopover {
|
|
|
21100
21291
|
});
|
|
21101
21292
|
// Add scroll and resize listeners for repositioning (always)
|
|
21102
21293
|
this.addScrollAndResizeListeners();
|
|
21294
|
+
document.addEventListener('submit', this.handleSubmitFromPanel, true);
|
|
21103
21295
|
// Add document listeners for light dismiss and escape key (auto type only)
|
|
21104
21296
|
if (this.popoverType === 'auto') {
|
|
21297
|
+
openAutoPopovers.push(this);
|
|
21105
21298
|
this.addLightDismissListeners();
|
|
21106
21299
|
}
|
|
21107
21300
|
// Emit open event
|
|
@@ -21117,12 +21310,16 @@ class PdsPopover {
|
|
|
21117
21310
|
if (!this.active || !this.portalEl)
|
|
21118
21311
|
return;
|
|
21119
21312
|
this.active = false;
|
|
21120
|
-
|
|
21121
|
-
|
|
21313
|
+
this.unwatchDialogClose();
|
|
21314
|
+
// Restoring the content drops its focus to the body, so check where focus is first. In a
|
|
21315
|
+
// shadow root, document.activeElement is only its host.
|
|
21316
|
+
const focusWasInside = containsComposed$1(this.portalEl, deepActiveElement());
|
|
21122
21317
|
this.linkTriggerToPortal();
|
|
21123
21318
|
// Restore content back to original slot positions
|
|
21124
21319
|
this.restorePortalContent();
|
|
21125
|
-
// Hide portal
|
|
21320
|
+
// Hide portal. The dark-mode border set in a shadow root is worked out again on the next open.
|
|
21321
|
+
this.portalEl.style.border = '';
|
|
21322
|
+
this.portalEl.removeAttribute('data-pds-popover-open');
|
|
21126
21323
|
this.portalEl.style.display = 'none';
|
|
21127
21324
|
this.portalEl.style.opacity = '0';
|
|
21128
21325
|
this.portalEl.style.visibility = 'hidden';
|
|
@@ -21132,8 +21329,10 @@ class PdsPopover {
|
|
|
21132
21329
|
this.returnFocusToTrigger();
|
|
21133
21330
|
}
|
|
21134
21331
|
// Remove all listeners
|
|
21332
|
+
this.forgetOpen();
|
|
21135
21333
|
this.removeLightDismissListeners();
|
|
21136
21334
|
this.removeScrollAndResizeListeners();
|
|
21335
|
+
document.removeEventListener('submit', this.handleSubmitFromPanel, true);
|
|
21137
21336
|
// Clear any pending timers
|
|
21138
21337
|
this.clearDebounceTimers();
|
|
21139
21338
|
// Emit close event
|
|
@@ -21153,6 +21352,59 @@ class PdsPopover {
|
|
|
21153
21352
|
this.show();
|
|
21154
21353
|
}
|
|
21155
21354
|
}
|
|
21355
|
+
/**
|
|
21356
|
+
* Puts the panel where it shows above everything around the popover. In an open dialog, it goes
|
|
21357
|
+
* inside it: a modal dialog sits in the top layer above the body and makes the rest of the page
|
|
21358
|
+
* inert, and a non-modal one sits above it by z-index. Right after the popover, it's next in the
|
|
21359
|
+
* Tab order. In another component's slot, though, it would have no slot to render in, and in a
|
|
21360
|
+
* form its buttons would submit it, so there it goes at the end of the dialog.
|
|
21361
|
+
*/
|
|
21362
|
+
placePortal() {
|
|
21363
|
+
var _a, _b;
|
|
21364
|
+
if (!this.portalEl)
|
|
21365
|
+
return;
|
|
21366
|
+
const dialog = closest$1('dialog[open]', this.el);
|
|
21367
|
+
if (!dialog) {
|
|
21368
|
+
this.unwatchDialogClose();
|
|
21369
|
+
this.portalEl.style.border = '';
|
|
21370
|
+
if (this.portalEl.parentElement !== document.body)
|
|
21371
|
+
document.body.appendChild(this.portalEl);
|
|
21372
|
+
this.copyFocusStylesInto(document);
|
|
21373
|
+
return;
|
|
21374
|
+
}
|
|
21375
|
+
const form = closest$1('form', this.el);
|
|
21376
|
+
const besidePopover = !((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.shadowRoot) && !(form && containsComposed$1(dialog, form));
|
|
21377
|
+
if (besidePopover) {
|
|
21378
|
+
if (this.el.nextElementSibling !== this.portalEl)
|
|
21379
|
+
(_b = this.el.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(this.portalEl, this.el.nextSibling);
|
|
21380
|
+
}
|
|
21381
|
+
else if (this.portalEl.parentNode !== dialog) {
|
|
21382
|
+
dialog.appendChild(this.portalEl);
|
|
21383
|
+
}
|
|
21384
|
+
this.watchDialogClose(dialog);
|
|
21385
|
+
const root = this.portalEl.getRootNode();
|
|
21386
|
+
this.copyFocusStylesInto(root);
|
|
21387
|
+
// In a shadow root, the copied dark-mode rule can't see a [data-theme="dark"] on the page.
|
|
21388
|
+
this.portalEl.style.border = root instanceof ShadowRoot && closest$1('[data-theme="dark"]', this.el) ? 'var(--pine-border)' : '';
|
|
21389
|
+
}
|
|
21390
|
+
forgetOpen() {
|
|
21391
|
+
const index = openAutoPopovers.indexOf(this);
|
|
21392
|
+
if (index >= 0)
|
|
21393
|
+
openAutoPopovers.splice(index, 1);
|
|
21394
|
+
}
|
|
21395
|
+
/**
|
|
21396
|
+
* Whether an Escape is this popover's. One from a dialog the popover isn't in belongs to that
|
|
21397
|
+
* dialog when it's above it: a top-layer dialog or a pds-modal. A plain non-modal dialog inside
|
|
21398
|
+
* the popover's modal doesn't close on Escape, so the popover takes it.
|
|
21399
|
+
*/
|
|
21400
|
+
takesEscapeFrom(event) {
|
|
21401
|
+
var _a, _b;
|
|
21402
|
+
const origin = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
|
|
21403
|
+
const dialog = closest$1('dialog[open]', origin);
|
|
21404
|
+
if (!dialog || containsComposed$1(dialog, this.portalEl))
|
|
21405
|
+
return true;
|
|
21406
|
+
return !(dialog.classList.contains('pds-modal__backdrop') || dialog.matches(':modal'));
|
|
21407
|
+
}
|
|
21156
21408
|
/**
|
|
21157
21409
|
* Adds light dismiss listeners (click outside and escape key)
|
|
21158
21410
|
*/
|
|
@@ -21161,6 +21413,19 @@ class PdsPopover {
|
|
|
21161
21413
|
document.addEventListener('click', this.boundClickOutsideHandler, true);
|
|
21162
21414
|
document.addEventListener('keydown', this.boundEscapeKeyHandler);
|
|
21163
21415
|
}
|
|
21416
|
+
/** Closes the popover when the dialog it opened in closes, so it isn't left open inside. */
|
|
21417
|
+
watchDialogClose(dialog) {
|
|
21418
|
+
if (this.watchedDialog === dialog)
|
|
21419
|
+
return;
|
|
21420
|
+
this.unwatchDialogClose();
|
|
21421
|
+
this.watchedDialog = dialog;
|
|
21422
|
+
dialog.addEventListener('close', this.onDialogClose);
|
|
21423
|
+
}
|
|
21424
|
+
unwatchDialogClose() {
|
|
21425
|
+
var _a;
|
|
21426
|
+
(_a = this.watchedDialog) === null || _a === void 0 ? void 0 : _a.removeEventListener('close', this.onDialogClose);
|
|
21427
|
+
this.watchedDialog = null;
|
|
21428
|
+
}
|
|
21164
21429
|
/**
|
|
21165
21430
|
* Removes light dismiss listeners
|
|
21166
21431
|
*/
|
|
@@ -21186,7 +21451,7 @@ class PdsPopover {
|
|
|
21186
21451
|
* Handles clicks outside the popover for light dismiss (auto type only)
|
|
21187
21452
|
*/
|
|
21188
21453
|
handleClickOutside(event) {
|
|
21189
|
-
var _a, _b
|
|
21454
|
+
var _a, _b;
|
|
21190
21455
|
// Ignore events that occurred at or before the popover opened
|
|
21191
21456
|
// This prevents the opening click from immediately closing the popover
|
|
21192
21457
|
// Convert event.timeStamp (DOMHighResTimeStamp from performance.now()) to epoch time
|
|
@@ -21197,16 +21462,18 @@ class PdsPopover {
|
|
|
21197
21462
|
if (eventTime <= this.openTimestamp) {
|
|
21198
21463
|
return;
|
|
21199
21464
|
}
|
|
21200
|
-
|
|
21465
|
+
// In a shadow root, event.target is only its host.
|
|
21466
|
+
const target = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
|
|
21201
21467
|
// A datepicker's calendar is portaled to the body: a click in the calendar of a datepicker
|
|
21202
|
-
// inside this popover, in its content or its trigger, isn't outside it.
|
|
21203
|
-
|
|
21468
|
+
// inside this popover, in its content or its trigger, isn't outside it. The target can be
|
|
21469
|
+
// inside the calendar's shadow root, so look up across it.
|
|
21470
|
+
const calendar = closest$1('.pds-datepicker-calendar-portal', target);
|
|
21204
21471
|
const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
|
|
21205
21472
|
if (owner && (containsComposed$1(this.portalEl, owner) || containsComposed$1(this.triggerEl, owner)))
|
|
21206
21473
|
return;
|
|
21207
21474
|
// Check if click is outside both the popover portal and the trigger
|
|
21208
|
-
const clickedInsidePopover = (
|
|
21209
|
-
const clickedInsideTrigger = (
|
|
21475
|
+
const clickedInsidePopover = containsComposed$1(this.portalEl, target);
|
|
21476
|
+
const clickedInsideTrigger = containsComposed$1(this.triggerEl, target);
|
|
21210
21477
|
if (!clickedInsidePopover && !clickedInsideTrigger) {
|
|
21211
21478
|
this.hide();
|
|
21212
21479
|
}
|
|
@@ -21227,14 +21494,19 @@ class PdsPopover {
|
|
|
21227
21494
|
* Mirrors native Popover API: Escape closes and returns focus to trigger
|
|
21228
21495
|
*/
|
|
21229
21496
|
handleEscapeKey(event) {
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21237
|
-
|
|
21497
|
+
// A control inside that closes on Escape (a datepicker, a combobox) has handled it already.
|
|
21498
|
+
if (event.key !== 'Escape' || event.defaultPrevented)
|
|
21499
|
+
return;
|
|
21500
|
+
// Like the native Popover API, Escape closes only the top popover: the last one opened that
|
|
21501
|
+
// it applies to. Every open popover hears it, so each checks whether it's that one.
|
|
21502
|
+
const top = [...openAutoPopovers].reverse().find(popover => popover.takesEscapeFrom(event));
|
|
21503
|
+
if (top !== this)
|
|
21504
|
+
return;
|
|
21505
|
+
// Take the key, so the dialog or modal around it doesn't close too.
|
|
21506
|
+
event.preventDefault();
|
|
21507
|
+
event.stopPropagation();
|
|
21508
|
+
// Close popover and return focus to trigger
|
|
21509
|
+
this.hide();
|
|
21238
21510
|
}
|
|
21239
21511
|
/**
|
|
21240
21512
|
* Handles scroll events to reposition the popover (debounced for performance)
|
|
@@ -21339,13 +21611,20 @@ class PdsPopover {
|
|
|
21339
21611
|
}
|
|
21340
21612
|
this.portalEl.style.top = `${top}px`;
|
|
21341
21613
|
this.portalEl.style.left = `${left}px`;
|
|
21614
|
+
// `position: fixed` measures from the viewport unless an ancestor becomes its containing block,
|
|
21615
|
+
// as a modal dialog does with its backdrop filter. Shift by however far it landed from the spot.
|
|
21616
|
+
const placed = this.portalEl.getBoundingClientRect();
|
|
21617
|
+
if (Math.abs(placed.top - top) > 0.5 || Math.abs(placed.left - left) > 0.5) {
|
|
21618
|
+
this.portalEl.style.top = `${2 * top - placed.top}px`;
|
|
21619
|
+
this.portalEl.style.left = `${2 * left - placed.left}px`;
|
|
21620
|
+
}
|
|
21342
21621
|
// Reset the repositioning guard after a short delay
|
|
21343
21622
|
setTimeout(() => {
|
|
21344
21623
|
this.isRepositioning = false;
|
|
21345
21624
|
}, 16); // ~1 frame at 60fps
|
|
21346
21625
|
}
|
|
21347
21626
|
render() {
|
|
21348
|
-
return (hAsync(Host, { key: '
|
|
21627
|
+
return (hAsync(Host, { key: 'da8a0c715df1199231b1265085f3f9ae0234032d', id: this.componentId }, hAsync("span", { key: 'f35023492399420829cec2e88556462f5ac1663e', class: "pds-popover__trigger-wrapper" }, hAsync("slot", { key: '38ebe92eebb87665467b3f92ff94dc8095450063', name: "trigger", onSlotchange: this.handleTriggerSlotChange })), hAsync("div", { key: '8917930f4520544d14bbd68b4c7936dd60af19e3', class: "pds-popover__content-slot-wrapper" }, hAsync("slot", { key: '28d3f9112256edd95721a79a7072a9e35a3712bf', onSlotchange: this.handleContentSlotChange }))));
|
|
21349
21628
|
}
|
|
21350
21629
|
get el() { return getElement(this); }
|
|
21351
21630
|
static get watchers() { return {
|