@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.mjs
CHANGED
|
@@ -11623,6 +11623,9 @@ class PdsCombobox {
|
|
|
11623
11623
|
};
|
|
11624
11624
|
// Handler for button trigger click
|
|
11625
11625
|
this.onButtonTriggerClick = () => {
|
|
11626
|
+
// The button and chip triggers are divs, so a click reaches them even while disabled.
|
|
11627
|
+
if (this.disabled)
|
|
11628
|
+
return;
|
|
11626
11629
|
this.isOpen = !this.isOpen;
|
|
11627
11630
|
if (this.isOpen) {
|
|
11628
11631
|
this.prepareExpandFilterListOnOpen();
|
|
@@ -11642,6 +11645,13 @@ class PdsCombobox {
|
|
|
11642
11645
|
};
|
|
11643
11646
|
// Handler for button trigger keyboard events
|
|
11644
11647
|
this.onButtonTriggerKeyDown = (e) => {
|
|
11648
|
+
// Disabled takes it out of the tab order, but setFocus() or a click can still focus it.
|
|
11649
|
+
if (this.disabled) {
|
|
11650
|
+
// Keep Space from scrolling the page, as on a native disabled button.
|
|
11651
|
+
if (e.key === ' ')
|
|
11652
|
+
e.preventDefault();
|
|
11653
|
+
return;
|
|
11654
|
+
}
|
|
11645
11655
|
// Escape closes an open group before the dropdown. Other keys reach the tree through handleKeyDown.
|
|
11646
11656
|
if (this.isOpen && e.key === 'Escape' && this.handleGroupedPanelKey(e))
|
|
11647
11657
|
return;
|
|
@@ -11662,8 +11672,9 @@ class PdsCombobox {
|
|
|
11662
11672
|
}, 0);
|
|
11663
11673
|
}
|
|
11664
11674
|
else if (e.key === 'Escape') {
|
|
11665
|
-
|
|
11675
|
+
// Only an open dropdown claims Escape; a closed one leaves it to a modal or popover around it.
|
|
11666
11676
|
if (this.isOpen) {
|
|
11677
|
+
e.preventDefault();
|
|
11667
11678
|
this.isOpen = false;
|
|
11668
11679
|
this.highlightedIndex = -1;
|
|
11669
11680
|
this.clearExpandFilterList();
|
|
@@ -11908,6 +11919,22 @@ class PdsCombobox {
|
|
|
11908
11919
|
if (this.isOpen && this.hidesPanelSearch && this.panelTreeEl)
|
|
11909
11920
|
this.focusPanel(this.panelTreeEl);
|
|
11910
11921
|
}
|
|
11922
|
+
disabledChanged(disabled) {
|
|
11923
|
+
var _a, _b, _c, _d, _e;
|
|
11924
|
+
if (!disabled || !this.isOpen)
|
|
11925
|
+
return;
|
|
11926
|
+
const shadowActive = (_b = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement) !== null && _b !== void 0 ? _b : null;
|
|
11927
|
+
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)));
|
|
11928
|
+
this.isOpen = false;
|
|
11929
|
+
this.highlightedIndex = -1;
|
|
11930
|
+
this.isArrowKeyNavigationMode = false;
|
|
11931
|
+
this.clearExpandFilterList();
|
|
11932
|
+
this.updateAriaActiveDescendant();
|
|
11933
|
+
// Closing removes the search field or option that held focus. A button or chip trigger can still
|
|
11934
|
+
// take it (aria-disabled), so focus doesn't fall to the page; a disabled input can't, as natively.
|
|
11935
|
+
if (focusInDropdown && this.trigger !== 'input')
|
|
11936
|
+
this.restoreFocusToTrigger();
|
|
11937
|
+
}
|
|
11911
11938
|
isOpenChanged(isOpen) {
|
|
11912
11939
|
if (!isOpen) {
|
|
11913
11940
|
this.revealedGroupLabel = null;
|
|
@@ -13622,13 +13649,13 @@ class PdsCombobox {
|
|
|
13622
13649
|
]
|
|
13623
13650
|
.filter(Boolean)
|
|
13624
13651
|
.join(' ');
|
|
13625
|
-
return (hAsync(Host, { key: '
|
|
13652
|
+
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 => {
|
|
13626
13653
|
this.inputEl = el;
|
|
13627
13654
|
this.triggerEl = el;
|
|
13628
13655
|
}, class: {
|
|
13629
13656
|
'pds-combobox__input': true,
|
|
13630
13657
|
'pds-combobox__input--invalid': this.isInvalid(),
|
|
13631
|
-
}, 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: '
|
|
13658
|
+
}, 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' && [
|
|
13632
13659
|
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 : ''),
|
|
13633
13660
|
// Its own region: sharing one, revealing a row then opening it would leave the text the
|
|
13634
13661
|
// same, and opening the group would go unannounced.
|
|
@@ -13647,6 +13674,9 @@ class PdsCombobox {
|
|
|
13647
13674
|
"flyoutFallback": [{
|
|
13648
13675
|
"flyoutFallbackChanged": 0
|
|
13649
13676
|
}],
|
|
13677
|
+
"disabled": [{
|
|
13678
|
+
"disabledChanged": 0
|
|
13679
|
+
}],
|
|
13650
13680
|
"isOpen": [{
|
|
13651
13681
|
"isOpenChanged": 0
|
|
13652
13682
|
}],
|
|
@@ -16080,22 +16110,24 @@ function unwrapReconnectedContent(container, selector, contentSelector) {
|
|
|
16080
16110
|
}
|
|
16081
16111
|
}
|
|
16082
16112
|
|
|
16083
|
-
const pdsDrawerCss = () => `.pds-drawer__modal>.pds-modal__backdrop{-ms-flex-align:stretch;align-items:stretch
|
|
16113
|
+
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}`;
|
|
16084
16114
|
|
|
16085
|
-
// Known selectors for content Pine components portal
|
|
16086
|
-
//
|
|
16115
|
+
// Known selectors for content Pine components portal out of place rather than
|
|
16116
|
+
// rendering where they are — pds-tooltip and pds-combobox's dropdown in
|
|
16117
|
+
// document.body, pds-popover in the body or the open dialog it's in.
|
|
16087
16118
|
// A pointerdown landing on one of these is not "outside" the drawer in the
|
|
16088
16119
|
// sense light dismiss cares about: it belongs to an overlay something inside
|
|
16089
16120
|
// the drawer opened, even though it is not a DOM descendant of the drawer.
|
|
16090
16121
|
const PORTALED_OVERLAY_SELECTOR = '.pds-popover, .pds-tooltip, .pds-combobox-dropdown-portal';
|
|
16091
16122
|
/**
|
|
16092
|
-
* A
|
|
16123
|
+
* A side panel composed from `pds-modal`, non-modal by default.
|
|
16093
16124
|
*
|
|
16094
|
-
*
|
|
16095
|
-
* dimming, no blur, no scroll lock, no click blocking.
|
|
16096
|
-
* `pds-modal` internally with `disableTopLayer`
|
|
16097
|
-
* suppressed, and adds the edge, width and dismiss behavior a
|
|
16098
|
-
* needs on top.
|
|
16125
|
+
* By default, unlike `pds-modal`, the page stays interactive while a drawer
|
|
16126
|
+
* is open: no dimming, no blur, no scroll lock, no click blocking.
|
|
16127
|
+
* `pds-drawer` renders a `pds-modal` internally with `disableTopLayer` on and
|
|
16128
|
+
* its backdrop suppressed, and adds the edge, width and dismiss behavior a
|
|
16129
|
+
* side panel needs on top. With `modal`, it opens that `pds-modal` in the top
|
|
16130
|
+
* layer instead and keeps its backdrop. It does not reimplement focus, Escape or dialog semantics —
|
|
16099
16131
|
* those come from `pds-modal` unchanged.
|
|
16100
16132
|
* @lightDom renders-markup
|
|
16101
16133
|
*/
|
|
@@ -16126,8 +16158,18 @@ class PdsDrawer {
|
|
|
16126
16158
|
*/
|
|
16127
16159
|
this.scrollable = true;
|
|
16128
16160
|
/**
|
|
16129
|
-
* Whether the drawer
|
|
16130
|
-
*
|
|
16161
|
+
* Whether the drawer is modal. A modal drawer dims the page behind it with a
|
|
16162
|
+
* backdrop, makes the page inert, and keeps focus inside the drawer, like
|
|
16163
|
+
* `pds-modal`. Use it for a task the page should wait on. Leave it off for a
|
|
16164
|
+
* panel people work alongside the page. Read when the drawer opens; changing
|
|
16165
|
+
* it while the drawer is open is not supported.
|
|
16166
|
+
* @default false
|
|
16167
|
+
*/
|
|
16168
|
+
this.modal = false;
|
|
16169
|
+
/**
|
|
16170
|
+
* Whether the drawer can be dismissed with a pointerdown outside it (in a
|
|
16171
|
+
* `modal` drawer, a click on its backdrop).
|
|
16172
|
+
* Replaces `pds-modal`'s `backdropDismiss`.
|
|
16131
16173
|
* This also gates Escape, matching how `backdropDismiss` gates Escape on
|
|
16132
16174
|
* `pds-modal` today: setting this to `false` means the close button is the
|
|
16133
16175
|
* only way out.
|
|
@@ -16146,7 +16188,8 @@ class PdsDrawer {
|
|
|
16146
16188
|
* background event while the user is mid-task elsewhere on the page —
|
|
16147
16189
|
* moving focus there would interrupt them, and the page stays live under
|
|
16148
16190
|
* a non-modal drawer, so it is a genuine data-entry risk, not just an
|
|
16149
|
-
* annoyance.
|
|
16191
|
+
* annoyance. A `modal` drawer ignores `none`: the page behind it is inert,
|
|
16192
|
+
* so focus starts in the drawer.
|
|
16150
16193
|
* @default 'auto'
|
|
16151
16194
|
*/
|
|
16152
16195
|
this.initialFocus = 'auto';
|
|
@@ -16192,7 +16235,8 @@ class PdsDrawer {
|
|
|
16192
16235
|
// page underneath stays genuinely clickable, which means a click there
|
|
16193
16236
|
// never reaches pds-modal's backdrop element at all.
|
|
16194
16237
|
handleOutsidePointerDown(e) {
|
|
16195
|
-
|
|
16238
|
+
// A modal drawer's backdrop takes the click instead, through pds-modal.
|
|
16239
|
+
if (this.modal || !this.lightDismiss || !this.open)
|
|
16196
16240
|
return;
|
|
16197
16241
|
const target = e.target;
|
|
16198
16242
|
if (!target)
|
|
@@ -16202,7 +16246,7 @@ class PdsDrawer {
|
|
|
16202
16246
|
if (target.closest(PORTALED_OVERLAY_SELECTOR))
|
|
16203
16247
|
return;
|
|
16204
16248
|
// A datepicker's portaled calendar counts as inside only when its datepicker is in the drawer,
|
|
16205
|
-
// or in an overlay portaled from it (a pds-popover in the drawer puts its content
|
|
16249
|
+
// or in an overlay portaled from it (a pds-popover in the drawer puts its content beside it).
|
|
16206
16250
|
const calendar = target.closest('.pds-datepicker-calendar-portal');
|
|
16207
16251
|
const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
|
|
16208
16252
|
if (owner && (containsComposed$1(this.el, owner) || closest$1(PORTALED_OVERLAY_SELECTOR, owner)))
|
|
@@ -16218,11 +16262,11 @@ class PdsDrawer {
|
|
|
16218
16262
|
this.open = false;
|
|
16219
16263
|
}
|
|
16220
16264
|
render() {
|
|
16221
|
-
return (hAsync(Host, { key: '
|
|
16265
|
+
return (hAsync(Host, { key: '287bf043c991209488eb1b617031acffb59ff9af', class: {
|
|
16222
16266
|
'pds-drawer': true,
|
|
16223
16267
|
[`pds-drawer--${this.side}`]: true,
|
|
16224
16268
|
[`pds-drawer--${this.size}`]: true,
|
|
16225
|
-
} }, hAsync("pds-modal", { key: '
|
|
16269
|
+
} }, 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' }))));
|
|
16226
16270
|
}
|
|
16227
16271
|
get el() { return getElement(this); }
|
|
16228
16272
|
static get style() { return pdsDrawerCss(); }
|
|
@@ -16235,6 +16279,7 @@ class PdsDrawer {
|
|
|
16235
16279
|
"side": [1],
|
|
16236
16280
|
"size": [1],
|
|
16237
16281
|
"scrollable": [4],
|
|
16282
|
+
"modal": [4],
|
|
16238
16283
|
"lightDismiss": [4, "light-dismiss"],
|
|
16239
16284
|
"initialFocus": [1, "initial-focus"]
|
|
16240
16285
|
},
|
|
@@ -16586,15 +16631,19 @@ class PdsDropdownMenu {
|
|
|
16586
16631
|
this.focusItemByIndex(prevIndex);
|
|
16587
16632
|
}
|
|
16588
16633
|
}
|
|
16634
|
+
// Escape is taken in document's capture phase, before a modal around the menu hears it on
|
|
16635
|
+
// document and closes too.
|
|
16636
|
+
handleEscapeKeyDown(event) {
|
|
16637
|
+
if (!this.isOpen || event.key !== 'Escape' || event.defaultPrevented)
|
|
16638
|
+
return;
|
|
16639
|
+
event.preventDefault();
|
|
16640
|
+
this.closeDropdown();
|
|
16641
|
+
}
|
|
16589
16642
|
// Handle keyboard events for the dropdown
|
|
16590
16643
|
handleKeyDown(event) {
|
|
16591
16644
|
if (!this.isOpen)
|
|
16592
16645
|
return;
|
|
16593
16646
|
switch (event.key) {
|
|
16594
|
-
case 'Escape':
|
|
16595
|
-
event.preventDefault();
|
|
16596
|
-
this.closeDropdown();
|
|
16597
|
-
break;
|
|
16598
16647
|
case 'ArrowDown':
|
|
16599
16648
|
event.preventDefault();
|
|
16600
16649
|
this.focusNextItem();
|
|
@@ -16686,7 +16735,7 @@ class PdsDropdownMenu {
|
|
|
16686
16735
|
}
|
|
16687
16736
|
}
|
|
16688
16737
|
render() {
|
|
16689
|
-
return (hAsync(Host, { key: '
|
|
16738
|
+
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 })))));
|
|
16690
16739
|
}
|
|
16691
16740
|
get host() { return getElement(this); }
|
|
16692
16741
|
static get style() { return pdsDropdownMenuCss(); }
|
|
@@ -16699,7 +16748,7 @@ class PdsDropdownMenu {
|
|
|
16699
16748
|
"currentFocusIndex": [32],
|
|
16700
16749
|
"hasHeader": [32]
|
|
16701
16750
|
},
|
|
16702
|
-
"$listeners$": [[8, "keydown", "handleKeyDown"], [8, "click", "handleWindowClick"]],
|
|
16751
|
+
"$listeners$": [[6, "keydown", "handleEscapeKeyDown"], [8, "keydown", "handleKeyDown"], [8, "click", "handleWindowClick"]],
|
|
16703
16752
|
"$lazyBundleId$": "-",
|
|
16704
16753
|
"$attrsToReflect$": []
|
|
16705
16754
|
}; }
|
|
@@ -18568,8 +18617,36 @@ function containsComposed(ancestor, node) {
|
|
|
18568
18617
|
}
|
|
18569
18618
|
return false;
|
|
18570
18619
|
}
|
|
18620
|
+
/**
|
|
18621
|
+
* Every open modal, with the order it opened in, which ranks top-layer modals and the modals
|
|
18622
|
+
* inside them. Kept here rather than queried from the document, which can't see a modal inside
|
|
18623
|
+
* another component's shadow root.
|
|
18624
|
+
*/
|
|
18625
|
+
const openModals = new Map();
|
|
18626
|
+
let openSequence = 0;
|
|
18627
|
+
/** Whether an open auto popover's panel sits in `root`, including inside shadow roots under it. */
|
|
18628
|
+
function hasOpenPopover(root) {
|
|
18629
|
+
if (root.querySelector('[data-pds-popover-open]'))
|
|
18630
|
+
return true;
|
|
18631
|
+
return Array.from(root.querySelectorAll('*')).some(el => !!el.shadowRoot && hasOpenPopover(el.shadowRoot));
|
|
18632
|
+
}
|
|
18633
|
+
/**
|
|
18634
|
+
* Whether `a` comes before `b` in the page. `compareDocumentPosition` is arbitrary across a shadow
|
|
18635
|
+
* boundary, so each side climbs to its host until both are in the same tree.
|
|
18636
|
+
*/
|
|
18637
|
+
function precedesComposed(a, b) {
|
|
18638
|
+
// A document has no host, which ends each climb.
|
|
18639
|
+
for (let x = a; x; x = x.getRootNode().host) {
|
|
18640
|
+
for (let y = b; y; y = y.getRootNode().host) {
|
|
18641
|
+
if (x.getRootNode() === y.getRootNode()) {
|
|
18642
|
+
return !!(x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING);
|
|
18643
|
+
}
|
|
18644
|
+
}
|
|
18645
|
+
}
|
|
18646
|
+
return false;
|
|
18647
|
+
}
|
|
18571
18648
|
/** The focused element, followed down through shadow roots to the control that has focus. */
|
|
18572
|
-
function deepActiveElement() {
|
|
18649
|
+
function deepActiveElement$1() {
|
|
18573
18650
|
var _a;
|
|
18574
18651
|
let active = document.activeElement;
|
|
18575
18652
|
while ((_a = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement)
|
|
@@ -18586,7 +18663,8 @@ class PdsModal {
|
|
|
18586
18663
|
this.pdsModalClose = createEvent(this, "pdsModalClose");
|
|
18587
18664
|
this.focusableElements = [];
|
|
18588
18665
|
/**
|
|
18589
|
-
* Whether the modal can be dismissed by clicking the backdrop
|
|
18666
|
+
* Whether the modal can be dismissed by clicking the backdrop, pressing Escape, or the browser's
|
|
18667
|
+
* own close request (such as a back gesture)
|
|
18590
18668
|
* @default true
|
|
18591
18669
|
*/
|
|
18592
18670
|
this.backdropDismiss = true;
|
|
@@ -18634,19 +18712,33 @@ class PdsModal {
|
|
|
18634
18712
|
* Stores the list of focusable elements in the modal
|
|
18635
18713
|
*/
|
|
18636
18714
|
this.focusableElementsArray = [];
|
|
18715
|
+
// The browser's own close request (an Escape nothing prevented, a back gesture) would close the
|
|
18716
|
+
// dialog without updating `open`, so close it through hideModal() instead, or not at all.
|
|
18717
|
+
this.handleCancel = (e) => {
|
|
18718
|
+
e.preventDefault();
|
|
18719
|
+
if (!this.open)
|
|
18720
|
+
return;
|
|
18721
|
+
// The request reaches the top-layer dialog even when a disableTopLayer modal inside it is on
|
|
18722
|
+
// top; that one closes first, as it would on Escape.
|
|
18723
|
+
const top = this.innermostOpenModal();
|
|
18724
|
+
const target = (top && containsComposed(this.el, top) ? top : this.el);
|
|
18725
|
+
if (target.backdropDismiss)
|
|
18726
|
+
target.hideModal();
|
|
18727
|
+
};
|
|
18637
18728
|
this.handleBackdropClick = (e) => {
|
|
18638
18729
|
if (!this.backdropDismiss || !this.open)
|
|
18639
18730
|
return;
|
|
18640
|
-
|
|
18731
|
+
// This modal's own backdrop; a nested modal's backdrop handles its own clicks.
|
|
18732
|
+
if (e.target === this.modalRef) {
|
|
18641
18733
|
e.stopPropagation();
|
|
18642
18734
|
// Only close if this is the innermost modal
|
|
18643
|
-
if (this.
|
|
18735
|
+
if (this.innermostOpenModal() === this.el) {
|
|
18644
18736
|
this.hideModal();
|
|
18645
18737
|
}
|
|
18646
18738
|
}
|
|
18647
18739
|
};
|
|
18648
18740
|
this.handleKeyDown = (e) => {
|
|
18649
|
-
var _a, _b, _c;
|
|
18741
|
+
var _a, _b, _c, _d;
|
|
18650
18742
|
// If the modal is not open, don't handle any keyboard events
|
|
18651
18743
|
if (!this.open)
|
|
18652
18744
|
return;
|
|
@@ -18669,24 +18761,39 @@ class PdsModal {
|
|
|
18669
18761
|
if (!('__pdsActiveElementAtEscape' in eventSnapshot)) {
|
|
18670
18762
|
const activeAtDispatch = document.activeElement;
|
|
18671
18763
|
eventSnapshot.__pdsActiveElementAtEscape = activeAtDispatch;
|
|
18764
|
+
// Followed into shadow roots: for a modal inside one, document.activeElement is only the host.
|
|
18765
|
+
eventSnapshot.__pdsDeepActiveElementAtEscape = deepActiveElement$1();
|
|
18672
18766
|
const topLayerDialog = (_a = activeAtDispatch === null || activeAtDispatch === void 0 ? void 0 : activeAtDispatch.closest('dialog')) !== null && _a !== void 0 ? _a : null;
|
|
18673
18767
|
eventSnapshot.__pdsTopLayerDialogAtEscape = topLayerDialog;
|
|
18674
18768
|
eventSnapshot.__pdsTopLayerDialogWasModalAtEscape = !!(topLayerDialog && topLayerDialog.matches(':modal'));
|
|
18769
|
+
// A control that closed on this Escape (a combobox on its own element, a dropdown menu or
|
|
18770
|
+
// multiselect in document's capture phase) has prevented it before this bubble listener.
|
|
18771
|
+
// Read before any modal prevents it below.
|
|
18772
|
+
eventSnapshot.__pdsEscapeHandledInside = e.defaultPrevented;
|
|
18773
|
+
// Which modal is innermost is read once too: the inner one closing first would make its
|
|
18774
|
+
// outer modal the innermost by the time that modal's listener runs.
|
|
18775
|
+
eventSnapshot.__pdsInnermostModalAtEscape = this.innermostOpenModal();
|
|
18675
18776
|
}
|
|
18777
|
+
if (eventSnapshot.__pdsEscapeHandledInside)
|
|
18778
|
+
return;
|
|
18676
18779
|
// Leave Escape to a genuinely stacked-above overlay (disableTopLayer's
|
|
18677
18780
|
// reason for existing) — not just to anything outside this modal.
|
|
18678
18781
|
const active = eventSnapshot.__pdsActiveElementAtEscape;
|
|
18679
18782
|
if (this.disableTopLayer &&
|
|
18680
18783
|
active &&
|
|
18681
18784
|
active !== document.body &&
|
|
18682
|
-
!this.el.
|
|
18683
|
-
this.isStackedAboveOverlay(active, (
|
|
18785
|
+
!containsComposed(this.el, (_b = eventSnapshot.__pdsDeepActiveElementAtEscape) !== null && _b !== void 0 ? _b : active) &&
|
|
18786
|
+
this.isStackedAboveOverlay(active, (_c = eventSnapshot.__pdsTopLayerDialogAtEscape) !== null && _c !== void 0 ? _c : null, (_d = eventSnapshot.__pdsTopLayerDialogWasModalAtEscape) !== null && _d !== void 0 ? _d : false)) {
|
|
18684
18787
|
return;
|
|
18685
18788
|
}
|
|
18789
|
+
// An open popover inside takes Escape from its own document listener, which runs after this
|
|
18790
|
+
// one, so leave the key for it. Its preventDefault() keeps the native dialog open.
|
|
18791
|
+
if (this.modalRef && hasOpenPopover(this.modalRef))
|
|
18792
|
+
return;
|
|
18686
18793
|
// Always prevent native dialog close behavior
|
|
18687
18794
|
e.preventDefault();
|
|
18688
18795
|
// Only close if backdropDismiss is enabled and this is the innermost modal
|
|
18689
|
-
if (this.backdropDismiss && this.
|
|
18796
|
+
if (this.backdropDismiss && eventSnapshot.__pdsInnermostModalAtEscape === this.el) {
|
|
18690
18797
|
this.hideModal();
|
|
18691
18798
|
}
|
|
18692
18799
|
return;
|
|
@@ -18706,7 +18813,7 @@ class PdsModal {
|
|
|
18706
18813
|
// Every open modal hears this keydown. When focus is in a modal dialog opened above this one,
|
|
18707
18814
|
// that dialog traps Tab: this modal's list also holds its controls, so it would wrap first. A
|
|
18708
18815
|
// non-modal dialog inside (a disableTopLayer modal) doesn't trap, so this one still does.
|
|
18709
|
-
const activeElement = deepActiveElement();
|
|
18816
|
+
const activeElement = deepActiveElement$1();
|
|
18710
18817
|
if (!activeElement || this.modalDialogAbove(activeElement))
|
|
18711
18818
|
return;
|
|
18712
18819
|
// Content can change while the modal is open (rows fetched in, sections shown), so the
|
|
@@ -18746,8 +18853,6 @@ class PdsModal {
|
|
|
18746
18853
|
}
|
|
18747
18854
|
componentDidLoad() {
|
|
18748
18855
|
this.modalRef = this.el.querySelector('.pds-modal__backdrop');
|
|
18749
|
-
// Add keyboard event listener
|
|
18750
|
-
document.addEventListener('keydown', this.handleKeyDown);
|
|
18751
18856
|
// @Watch('open') only fires on a later change, not the prop's initial
|
|
18752
18857
|
// value — a modal mounted with `open` already true (static markup, or a
|
|
18753
18858
|
// framework passing it on first render) would otherwise never call
|
|
@@ -18763,9 +18868,18 @@ class PdsModal {
|
|
|
18763
18868
|
componentDidRender() {
|
|
18764
18869
|
unwrapReconnectedContent(this.el.querySelector('.pds-modal'), 'dialog.pds-modal__backdrop', '.pds-modal');
|
|
18765
18870
|
}
|
|
18871
|
+
// Here rather than in componentDidLoad, which runs once: a modal taken out of the page and put
|
|
18872
|
+
// back (a morph or a framework moving it) gets its keyboard handling, and its place among the
|
|
18873
|
+
// open modals, back too. Adding the same listener twice is a no-op.
|
|
18874
|
+
connectedCallback() {
|
|
18875
|
+
document.addEventListener('keydown', this.handleKeyDown);
|
|
18876
|
+
if (this.open && !openModals.has(this.el))
|
|
18877
|
+
openModals.set(this.el, ++openSequence);
|
|
18878
|
+
}
|
|
18766
18879
|
disconnectedCallback() {
|
|
18767
18880
|
// Clean up event listener
|
|
18768
18881
|
document.removeEventListener('keydown', this.handleKeyDown);
|
|
18882
|
+
openModals.delete(this.el);
|
|
18769
18883
|
}
|
|
18770
18884
|
handleOpenChange(newValue) {
|
|
18771
18885
|
if (newValue) {
|
|
@@ -18830,6 +18944,9 @@ class PdsModal {
|
|
|
18830
18944
|
this.modalRef.showModal();
|
|
18831
18945
|
}
|
|
18832
18946
|
this.open = true;
|
|
18947
|
+
// Showing an open modal again doesn't move it above one opened after it.
|
|
18948
|
+
if (!openModals.has(this.el))
|
|
18949
|
+
openModals.set(this.el, ++openSequence);
|
|
18833
18950
|
// Update focusable elements and set initial focus
|
|
18834
18951
|
// Using a longer timeout to ensure all components are fully rendered
|
|
18835
18952
|
setTimeout(() => {
|
|
@@ -18892,6 +19009,7 @@ class PdsModal {
|
|
|
18892
19009
|
const focusAlreadyMovedElsewhere = activeElement !== null && activeElement !== document.body && !this.modalRef.contains(activeElement);
|
|
18893
19010
|
this.modalRef.close();
|
|
18894
19011
|
this.open = false;
|
|
19012
|
+
openModals.delete(this.el);
|
|
18895
19013
|
// Restore focus to the element that was focused before the modal was opened
|
|
18896
19014
|
if (!focusAlreadyMovedElsewhere &&
|
|
18897
19015
|
this.previousActiveElement &&
|
|
@@ -18910,7 +19028,9 @@ class PdsModal {
|
|
|
18910
19028
|
*/
|
|
18911
19029
|
getBackdropZIndex(modal) {
|
|
18912
19030
|
const backdrop = modal.querySelector('.pds-modal__backdrop');
|
|
18913
|
-
|
|
19031
|
+
// `auto` (no z-index token loaded) parses to NaN, which no comparison can rank.
|
|
19032
|
+
const zIndex = backdrop ? parseInt(getComputedStyle(backdrop).zIndex, 10) : -1;
|
|
19033
|
+
return Number.isNaN(zIndex) ? 0 : zIndex;
|
|
18914
19034
|
}
|
|
18915
19035
|
/**
|
|
18916
19036
|
* Whether `active` sits inside a surface actually stacked above this modal.
|
|
@@ -18937,7 +19057,8 @@ class PdsModal {
|
|
|
18937
19057
|
* lose that evidence depending on listener order.
|
|
18938
19058
|
*/
|
|
18939
19059
|
isStackedAboveOverlay(active, topLayerDialog, topLayerDialogWasModal) {
|
|
18940
|
-
|
|
19060
|
+
// A top-layer dialog this modal sits inside is underneath it, not an overlay above.
|
|
19061
|
+
if (topLayerDialog && topLayerDialog !== this.modalRef && topLayerDialogWasModal && !containsComposed(topLayerDialog, this.el)) {
|
|
18941
19062
|
return true;
|
|
18942
19063
|
}
|
|
18943
19064
|
const ownZIndex = this.getBackdropZIndex(this.el);
|
|
@@ -18953,24 +19074,37 @@ class PdsModal {
|
|
|
18953
19074
|
return false;
|
|
18954
19075
|
}
|
|
18955
19076
|
/**
|
|
18956
|
-
*
|
|
19077
|
+
* The open modal that takes Escape or a backdrop click, among those with no other open modal
|
|
19078
|
+
* inside them (a nested modal's backdrop can share its outer modal's z-index). A top-layer dialog
|
|
19079
|
+
* (or a modal inside one) paints above anything outside it, and within the top layer the last
|
|
19080
|
+
* opened is on top. Modals in the same layer (the page, or one top-layer dialog) then rank by
|
|
19081
|
+
* the highest backdrop, then the one later in the page.
|
|
18957
19082
|
*/
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
const
|
|
18961
|
-
|
|
18962
|
-
|
|
18963
|
-
//
|
|
18964
|
-
const
|
|
18965
|
-
|
|
18966
|
-
|
|
18967
|
-
|
|
18968
|
-
|
|
18969
|
-
|
|
18970
|
-
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
19083
|
+
innermostOpenModal() {
|
|
19084
|
+
const open = Array.from(openModals.keys()).filter(modal => modal.isConnected);
|
|
19085
|
+
const innermost = open.filter(modal => !open.some(other => other !== modal && containsComposed(modal, other)));
|
|
19086
|
+
const byDocumentOrder = [...innermost].sort((a, b) => (precedesComposed(a, b) ? -1 : 1));
|
|
19087
|
+
// A modal inside a top-layer dialog paints in that dialog's place in the top layer, even when it
|
|
19088
|
+
// isn't in the top layer itself (disableTopLayer), so that dialog's open order ranks it first.
|
|
19089
|
+
const rank = (modal) => {
|
|
19090
|
+
var _a;
|
|
19091
|
+
const backdrop = modal.querySelector('.pds-modal__backdrop');
|
|
19092
|
+
const topLayerDialog = backdrop ? closest$1('dialog:modal', backdrop) : null;
|
|
19093
|
+
const topLayerModal = topLayerDialog === null || topLayerDialog === void 0 ? void 0 : topLayerDialog.closest('pds-modal');
|
|
19094
|
+
const layer = topLayerDialog ? ((_a = (topLayerModal && openModals.get(topLayerModal))) !== null && _a !== void 0 ? _a : 0) : 0;
|
|
19095
|
+
return [topLayerDialog ? 1 : 0, layer, this.getBackdropZIndex(modal), byDocumentOrder.indexOf(modal)];
|
|
19096
|
+
};
|
|
19097
|
+
let top = null;
|
|
19098
|
+
let topRank = [-1, -1, -1, -1];
|
|
19099
|
+
for (const modal of innermost) {
|
|
19100
|
+
const modalRank = rank(modal);
|
|
19101
|
+
const above = modalRank.findIndex((value, i) => value !== topRank[i]);
|
|
19102
|
+
if (above >= 0 && modalRank[above] > topRank[above]) {
|
|
19103
|
+
top = modal;
|
|
19104
|
+
topRank = modalRank;
|
|
19105
|
+
}
|
|
19106
|
+
}
|
|
19107
|
+
return top;
|
|
18974
19108
|
}
|
|
18975
19109
|
/** Whether a modal dialog other than this one sits between the focused element and this modal. */
|
|
18976
19110
|
modalDialogAbove(active) {
|
|
@@ -19010,14 +19144,14 @@ class PdsModal {
|
|
|
19010
19144
|
}
|
|
19011
19145
|
render() {
|
|
19012
19146
|
const [sizeClass = 'md', customSize] = this.resolveSize();
|
|
19013
|
-
return (hAsync("dialog", { key: '
|
|
19147
|
+
return (hAsync("dialog", { key: '0633d4e8a7cb81f2f9280e754564960a00a4d60b', class: {
|
|
19014
19148
|
'pds-modal__backdrop': true,
|
|
19015
19149
|
'open': this.open
|
|
19016
|
-
}, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick }, hAsync("div", { key: '
|
|
19150
|
+
}, "aria-modal": this.disableTopLayer ? 'false' : 'true', "aria-labelledby": `${this.componentId}-heading`, onClick: this.handleBackdropClick, onCancel: this.handleCancel }, hAsync("div", { key: '466f8a3476cf066817554f47ec7d3a0e3ab10b89', class: {
|
|
19017
19151
|
'pds-modal': true,
|
|
19018
19152
|
[`pds-modal--${sizeClass}`]: true,
|
|
19019
19153
|
'pds-modal--scrollable': this.scrollable
|
|
19020
|
-
}, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, hAsync("slot", { key: '
|
|
19154
|
+
}, style: customSize !== undefined ? { '--pds-modal-max-width': customSize } : undefined, part: "modal" }, hAsync("slot", { key: '01ca45c96540416216a1082bad52b137720f0f4d' }))));
|
|
19021
19155
|
}
|
|
19022
19156
|
get el() { return getElement(this); }
|
|
19023
19157
|
static get watchers() { return {
|
|
@@ -19850,11 +19984,12 @@ class PdsMultiselect {
|
|
|
19850
19984
|
}
|
|
19851
19985
|
/**
|
|
19852
19986
|
* Handle global keyboard events for accessibility.
|
|
19853
|
-
* Closes dropdown on Escape key press regardless of focus location.
|
|
19987
|
+
* Closes dropdown on Escape key press regardless of focus location. Taken in document's capture
|
|
19988
|
+
* phase, before a modal around the multiselect hears it on document and closes too.
|
|
19854
19989
|
*/
|
|
19855
19990
|
handleWindowKeyDown(event) {
|
|
19856
19991
|
var _a;
|
|
19857
|
-
if (!this.isOpen)
|
|
19992
|
+
if (!this.isOpen || event.defaultPrevented)
|
|
19858
19993
|
return;
|
|
19859
19994
|
if (event.key === 'Escape') {
|
|
19860
19995
|
event.preventDefault();
|
|
@@ -20544,10 +20679,10 @@ class PdsMultiselect {
|
|
|
20544
20679
|
}
|
|
20545
20680
|
render() {
|
|
20546
20681
|
const hasSelections = this.selectedItems.length > 0;
|
|
20547
|
-
return (hAsync(Host, { key: '
|
|
20682
|
+
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: {
|
|
20548
20683
|
'pds-multiselect__label': true,
|
|
20549
20684
|
'visually-hidden': this.hideLabel,
|
|
20550
|
-
} }, this.label)), hAsync("div", { key: '
|
|
20685
|
+
} }, 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: {
|
|
20551
20686
|
'pds-multiselect__trigger': true,
|
|
20552
20687
|
'pds-multiselect__trigger--open': this.isOpen,
|
|
20553
20688
|
'pds-multiselect__trigger--disabled': this.disabled,
|
|
@@ -20563,7 +20698,7 @@ class PdsMultiselect {
|
|
|
20563
20698
|
}, 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: {
|
|
20564
20699
|
'pds-multiselect__trigger-text': true,
|
|
20565
20700
|
'pds-multiselect__trigger-text--placeholder': !hasSelections || (this.selectedDisplay === 'pill' && this.pillPosition === 'below'),
|
|
20566
|
-
} }, 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: '
|
|
20701
|
+
} }, 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' })))));
|
|
20567
20702
|
}
|
|
20568
20703
|
static get formAssociated() { return true; }
|
|
20569
20704
|
get el() { return getElement(this); }
|
|
@@ -20653,7 +20788,7 @@ class PdsMultiselect {
|
|
|
20653
20788
|
"clear": [64],
|
|
20654
20789
|
"refreshOptions": [64]
|
|
20655
20790
|
},
|
|
20656
|
-
"$listeners$": [[
|
|
20791
|
+
"$listeners$": [[6, "keydown", "handleWindowKeyDown"]],
|
|
20657
20792
|
"$lazyBundleId$": "-",
|
|
20658
20793
|
"$attrsToReflect$": []
|
|
20659
20794
|
}; }
|
|
@@ -20703,6 +20838,16 @@ const cssEscape = (value) => {
|
|
|
20703
20838
|
|
|
20704
20839
|
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}`;
|
|
20705
20840
|
|
|
20841
|
+
/** Open auto popovers, in the order they opened: Escape goes to the last one it applies to. */
|
|
20842
|
+
const openAutoPopovers = [];
|
|
20843
|
+
/** The focused element, followed down through shadow roots to the control that has focus. */
|
|
20844
|
+
function deepActiveElement() {
|
|
20845
|
+
var _a;
|
|
20846
|
+
let active = document.activeElement;
|
|
20847
|
+
while ((_a = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement)
|
|
20848
|
+
active = active.shadowRoot.activeElement;
|
|
20849
|
+
return active;
|
|
20850
|
+
}
|
|
20706
20851
|
/**
|
|
20707
20852
|
* @slot trigger - The trigger element for the popover
|
|
20708
20853
|
* @slot (default) - The content to display inside the popover
|
|
@@ -20738,7 +20883,7 @@ class PdsPopover {
|
|
|
20738
20883
|
*/
|
|
20739
20884
|
this.triggerObserver = null;
|
|
20740
20885
|
/**
|
|
20741
|
-
* Portal element
|
|
20886
|
+
* Portal element: in document.body, or in the open dialog the popover is in
|
|
20742
20887
|
*/
|
|
20743
20888
|
this.portalEl = null;
|
|
20744
20889
|
/**
|
|
@@ -20834,6 +20979,26 @@ class PdsPopover {
|
|
|
20834
20979
|
break;
|
|
20835
20980
|
}
|
|
20836
20981
|
};
|
|
20982
|
+
/** The focus style copied into a shadow root the panel opened in, which `document.head` can't reach. */
|
|
20983
|
+
this.shadowFocusStyle = null;
|
|
20984
|
+
/** The dialog the panel was opened in, closed along with it. */
|
|
20985
|
+
this.watchedDialog = null;
|
|
20986
|
+
this.onDialogClose = () => {
|
|
20987
|
+
this.hide();
|
|
20988
|
+
};
|
|
20989
|
+
/**
|
|
20990
|
+
* Inside a dialog, the panel can sit in a form that wraps the dialog, which a body portal never
|
|
20991
|
+
* did. A submit from the panel (a button in it, or Enter in a field in it) is stopped, so the
|
|
20992
|
+
* panel behaves as it does in the body.
|
|
20993
|
+
*/
|
|
20994
|
+
this.handleSubmitFromPanel = (event) => {
|
|
20995
|
+
if (!this.portalEl || !containsComposed$1(event.target, this.portalEl))
|
|
20996
|
+
return;
|
|
20997
|
+
if (containsComposed$1(this.portalEl, event.submitter) || containsComposed$1(this.portalEl, deepActiveElement())) {
|
|
20998
|
+
event.preventDefault();
|
|
20999
|
+
event.stopPropagation();
|
|
21000
|
+
}
|
|
21001
|
+
};
|
|
20837
21002
|
}
|
|
20838
21003
|
restorePlacementDefault(newValue) {
|
|
20839
21004
|
this.placement = restoreReflectedDefault(this.el, 'placement', newValue, 'right');
|
|
@@ -20896,19 +21061,23 @@ class PdsPopover {
|
|
|
20896
21061
|
(_a = this.triggerEl) === null || _a === void 0 ? void 0 : _a.addEventListener('click', this.handleTriggerClick);
|
|
20897
21062
|
this.observeTrigger();
|
|
20898
21063
|
this.linkTriggerToPortal();
|
|
20899
|
-
// Still open after a move: the trigger moved, so the portal follows it
|
|
21064
|
+
// Still open after a move: the trigger moved, so the portal follows it, into the dialog it
|
|
21065
|
+
// is in now, if any.
|
|
20900
21066
|
if (this.active) {
|
|
21067
|
+
this.placePortal();
|
|
20901
21068
|
requestAnimationFrame(() => this.handlePopoverPositioning());
|
|
20902
21069
|
}
|
|
20903
21070
|
}
|
|
20904
21071
|
disconnectedCallback() {
|
|
20905
21072
|
var _a;
|
|
20906
21073
|
// Moved in one operation (a DOM morph, or a framework reparenting it), the popover is
|
|
20907
|
-
// already back in the page. Its portal is
|
|
20908
|
-
// where it was.
|
|
21074
|
+
// already back in the page. Its portal is outside the popover, so it stays open, with focus
|
|
21075
|
+
// where it was; connectedCallback moves it to follow the popover.
|
|
20909
21076
|
if (this.el.isConnected)
|
|
20910
21077
|
return;
|
|
20911
21078
|
this.isComponentMounted = false;
|
|
21079
|
+
this.unwatchDialogClose();
|
|
21080
|
+
this.forgetOpen();
|
|
20912
21081
|
// Open, the content sits in the portal; put it back before the portal goes. Only listeners on
|
|
20913
21082
|
// the popover itself hear the close event now, but those are the ones mirroring its state.
|
|
20914
21083
|
if (this.active) {
|
|
@@ -20929,6 +21098,7 @@ class PdsPopover {
|
|
|
20929
21098
|
// Clean up all event listeners
|
|
20930
21099
|
this.removeLightDismissListeners();
|
|
20931
21100
|
this.removeScrollAndResizeListeners();
|
|
21101
|
+
document.removeEventListener('submit', this.handleSubmitFromPanel, true);
|
|
20932
21102
|
// Clear any pending debounce timers
|
|
20933
21103
|
this.clearDebounceTimers();
|
|
20934
21104
|
// Remove portal from DOM
|
|
@@ -20973,9 +21143,6 @@ class PdsPopover {
|
|
|
20973
21143
|
else {
|
|
20974
21144
|
this.portalEl.id = `${this.componentId}-portal`;
|
|
20975
21145
|
}
|
|
20976
|
-
// Add accessibility attributes for screen readers
|
|
20977
|
-
// Note: Native Popover API doesn't add a specific role, keeping semantic HTML
|
|
20978
|
-
this.portalEl.setAttribute('aria-modal', 'false'); // Not a modal, can interact with rest of page
|
|
20979
21146
|
// Append to body
|
|
20980
21147
|
document.body.appendChild(this.portalEl);
|
|
20981
21148
|
// Add global focus styles to match Pine design system
|
|
@@ -21059,7 +21226,27 @@ class PdsPopover {
|
|
|
21059
21226
|
// Clear tracking array
|
|
21060
21227
|
this.movedNodes = [];
|
|
21061
21228
|
}
|
|
21229
|
+
copyFocusStylesInto(root) {
|
|
21230
|
+
var _a, _b, _c;
|
|
21231
|
+
// Outside a shadow root the document's own style applies, so drop a copy left in one.
|
|
21232
|
+
if (!(root instanceof ShadowRoot)) {
|
|
21233
|
+
(_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
|
|
21234
|
+
this.shadowFocusStyle = null;
|
|
21235
|
+
return;
|
|
21236
|
+
}
|
|
21237
|
+
if (((_b = this.shadowFocusStyle) === null || _b === void 0 ? void 0 : _b.parentNode) === root || !this.portalEl)
|
|
21238
|
+
return;
|
|
21239
|
+
const source = document.querySelector(`style[data-pds-popover-focus="${cssEscape(this.portalEl.id)}"]`);
|
|
21240
|
+
if (!source)
|
|
21241
|
+
return;
|
|
21242
|
+
(_c = this.shadowFocusStyle) === null || _c === void 0 ? void 0 : _c.remove();
|
|
21243
|
+
this.shadowFocusStyle = source.cloneNode(true);
|
|
21244
|
+
root.appendChild(this.shadowFocusStyle);
|
|
21245
|
+
}
|
|
21062
21246
|
removePortal() {
|
|
21247
|
+
var _a;
|
|
21248
|
+
(_a = this.shadowFocusStyle) === null || _a === void 0 ? void 0 : _a.remove();
|
|
21249
|
+
this.shadowFocusStyle = null;
|
|
21063
21250
|
if (this.portalEl) {
|
|
21064
21251
|
// Remove the portal element from DOM
|
|
21065
21252
|
if (this.portalEl.parentNode) {
|
|
@@ -21084,9 +21271,13 @@ class PdsPopover {
|
|
|
21084
21271
|
// Record open timestamp to prevent immediate close from opening click
|
|
21085
21272
|
this.openTimestamp = Date.now();
|
|
21086
21273
|
this.linkTriggerToPortal();
|
|
21274
|
+
this.placePortal();
|
|
21087
21275
|
// Update portal content with latest slot content
|
|
21088
21276
|
this.updatePortalContent();
|
|
21089
|
-
// Show portal
|
|
21277
|
+
// Show portal. The attribute tells a modal around it that this popover takes Escape first; only
|
|
21278
|
+
// an auto popover listens for Escape.
|
|
21279
|
+
if (this.popoverType === 'auto')
|
|
21280
|
+
this.portalEl.setAttribute('data-pds-popover-open', '');
|
|
21090
21281
|
this.portalEl.style.display = 'block';
|
|
21091
21282
|
this.portalEl.style.opacity = '1';
|
|
21092
21283
|
this.portalEl.style.visibility = 'visible';
|
|
@@ -21098,8 +21289,10 @@ class PdsPopover {
|
|
|
21098
21289
|
});
|
|
21099
21290
|
// Add scroll and resize listeners for repositioning (always)
|
|
21100
21291
|
this.addScrollAndResizeListeners();
|
|
21292
|
+
document.addEventListener('submit', this.handleSubmitFromPanel, true);
|
|
21101
21293
|
// Add document listeners for light dismiss and escape key (auto type only)
|
|
21102
21294
|
if (this.popoverType === 'auto') {
|
|
21295
|
+
openAutoPopovers.push(this);
|
|
21103
21296
|
this.addLightDismissListeners();
|
|
21104
21297
|
}
|
|
21105
21298
|
// Emit open event
|
|
@@ -21115,12 +21308,16 @@ class PdsPopover {
|
|
|
21115
21308
|
if (!this.active || !this.portalEl)
|
|
21116
21309
|
return;
|
|
21117
21310
|
this.active = false;
|
|
21118
|
-
|
|
21119
|
-
|
|
21311
|
+
this.unwatchDialogClose();
|
|
21312
|
+
// Restoring the content drops its focus to the body, so check where focus is first. In a
|
|
21313
|
+
// shadow root, document.activeElement is only its host.
|
|
21314
|
+
const focusWasInside = containsComposed$1(this.portalEl, deepActiveElement());
|
|
21120
21315
|
this.linkTriggerToPortal();
|
|
21121
21316
|
// Restore content back to original slot positions
|
|
21122
21317
|
this.restorePortalContent();
|
|
21123
|
-
// Hide portal
|
|
21318
|
+
// Hide portal. The dark-mode border set in a shadow root is worked out again on the next open.
|
|
21319
|
+
this.portalEl.style.border = '';
|
|
21320
|
+
this.portalEl.removeAttribute('data-pds-popover-open');
|
|
21124
21321
|
this.portalEl.style.display = 'none';
|
|
21125
21322
|
this.portalEl.style.opacity = '0';
|
|
21126
21323
|
this.portalEl.style.visibility = 'hidden';
|
|
@@ -21130,8 +21327,10 @@ class PdsPopover {
|
|
|
21130
21327
|
this.returnFocusToTrigger();
|
|
21131
21328
|
}
|
|
21132
21329
|
// Remove all listeners
|
|
21330
|
+
this.forgetOpen();
|
|
21133
21331
|
this.removeLightDismissListeners();
|
|
21134
21332
|
this.removeScrollAndResizeListeners();
|
|
21333
|
+
document.removeEventListener('submit', this.handleSubmitFromPanel, true);
|
|
21135
21334
|
// Clear any pending timers
|
|
21136
21335
|
this.clearDebounceTimers();
|
|
21137
21336
|
// Emit close event
|
|
@@ -21151,6 +21350,59 @@ class PdsPopover {
|
|
|
21151
21350
|
this.show();
|
|
21152
21351
|
}
|
|
21153
21352
|
}
|
|
21353
|
+
/**
|
|
21354
|
+
* Puts the panel where it shows above everything around the popover. In an open dialog, it goes
|
|
21355
|
+
* inside it: a modal dialog sits in the top layer above the body and makes the rest of the page
|
|
21356
|
+
* inert, and a non-modal one sits above it by z-index. Right after the popover, it's next in the
|
|
21357
|
+
* Tab order. In another component's slot, though, it would have no slot to render in, and in a
|
|
21358
|
+
* form its buttons would submit it, so there it goes at the end of the dialog.
|
|
21359
|
+
*/
|
|
21360
|
+
placePortal() {
|
|
21361
|
+
var _a, _b;
|
|
21362
|
+
if (!this.portalEl)
|
|
21363
|
+
return;
|
|
21364
|
+
const dialog = closest$1('dialog[open]', this.el);
|
|
21365
|
+
if (!dialog) {
|
|
21366
|
+
this.unwatchDialogClose();
|
|
21367
|
+
this.portalEl.style.border = '';
|
|
21368
|
+
if (this.portalEl.parentElement !== document.body)
|
|
21369
|
+
document.body.appendChild(this.portalEl);
|
|
21370
|
+
this.copyFocusStylesInto(document);
|
|
21371
|
+
return;
|
|
21372
|
+
}
|
|
21373
|
+
const form = closest$1('form', this.el);
|
|
21374
|
+
const besidePopover = !((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.shadowRoot) && !(form && containsComposed$1(dialog, form));
|
|
21375
|
+
if (besidePopover) {
|
|
21376
|
+
if (this.el.nextElementSibling !== this.portalEl)
|
|
21377
|
+
(_b = this.el.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(this.portalEl, this.el.nextSibling);
|
|
21378
|
+
}
|
|
21379
|
+
else if (this.portalEl.parentNode !== dialog) {
|
|
21380
|
+
dialog.appendChild(this.portalEl);
|
|
21381
|
+
}
|
|
21382
|
+
this.watchDialogClose(dialog);
|
|
21383
|
+
const root = this.portalEl.getRootNode();
|
|
21384
|
+
this.copyFocusStylesInto(root);
|
|
21385
|
+
// In a shadow root, the copied dark-mode rule can't see a [data-theme="dark"] on the page.
|
|
21386
|
+
this.portalEl.style.border = root instanceof ShadowRoot && closest$1('[data-theme="dark"]', this.el) ? 'var(--pine-border)' : '';
|
|
21387
|
+
}
|
|
21388
|
+
forgetOpen() {
|
|
21389
|
+
const index = openAutoPopovers.indexOf(this);
|
|
21390
|
+
if (index >= 0)
|
|
21391
|
+
openAutoPopovers.splice(index, 1);
|
|
21392
|
+
}
|
|
21393
|
+
/**
|
|
21394
|
+
* Whether an Escape is this popover's. One from a dialog the popover isn't in belongs to that
|
|
21395
|
+
* dialog when it's above it: a top-layer dialog or a pds-modal. A plain non-modal dialog inside
|
|
21396
|
+
* the popover's modal doesn't close on Escape, so the popover takes it.
|
|
21397
|
+
*/
|
|
21398
|
+
takesEscapeFrom(event) {
|
|
21399
|
+
var _a, _b;
|
|
21400
|
+
const origin = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
|
|
21401
|
+
const dialog = closest$1('dialog[open]', origin);
|
|
21402
|
+
if (!dialog || containsComposed$1(dialog, this.portalEl))
|
|
21403
|
+
return true;
|
|
21404
|
+
return !(dialog.classList.contains('pds-modal__backdrop') || dialog.matches(':modal'));
|
|
21405
|
+
}
|
|
21154
21406
|
/**
|
|
21155
21407
|
* Adds light dismiss listeners (click outside and escape key)
|
|
21156
21408
|
*/
|
|
@@ -21159,6 +21411,19 @@ class PdsPopover {
|
|
|
21159
21411
|
document.addEventListener('click', this.boundClickOutsideHandler, true);
|
|
21160
21412
|
document.addEventListener('keydown', this.boundEscapeKeyHandler);
|
|
21161
21413
|
}
|
|
21414
|
+
/** Closes the popover when the dialog it opened in closes, so it isn't left open inside. */
|
|
21415
|
+
watchDialogClose(dialog) {
|
|
21416
|
+
if (this.watchedDialog === dialog)
|
|
21417
|
+
return;
|
|
21418
|
+
this.unwatchDialogClose();
|
|
21419
|
+
this.watchedDialog = dialog;
|
|
21420
|
+
dialog.addEventListener('close', this.onDialogClose);
|
|
21421
|
+
}
|
|
21422
|
+
unwatchDialogClose() {
|
|
21423
|
+
var _a;
|
|
21424
|
+
(_a = this.watchedDialog) === null || _a === void 0 ? void 0 : _a.removeEventListener('close', this.onDialogClose);
|
|
21425
|
+
this.watchedDialog = null;
|
|
21426
|
+
}
|
|
21162
21427
|
/**
|
|
21163
21428
|
* Removes light dismiss listeners
|
|
21164
21429
|
*/
|
|
@@ -21184,7 +21449,7 @@ class PdsPopover {
|
|
|
21184
21449
|
* Handles clicks outside the popover for light dismiss (auto type only)
|
|
21185
21450
|
*/
|
|
21186
21451
|
handleClickOutside(event) {
|
|
21187
|
-
var _a, _b
|
|
21452
|
+
var _a, _b;
|
|
21188
21453
|
// Ignore events that occurred at or before the popover opened
|
|
21189
21454
|
// This prevents the opening click from immediately closing the popover
|
|
21190
21455
|
// Convert event.timeStamp (DOMHighResTimeStamp from performance.now()) to epoch time
|
|
@@ -21195,16 +21460,18 @@ class PdsPopover {
|
|
|
21195
21460
|
if (eventTime <= this.openTimestamp) {
|
|
21196
21461
|
return;
|
|
21197
21462
|
}
|
|
21198
|
-
|
|
21463
|
+
// In a shadow root, event.target is only its host.
|
|
21464
|
+
const target = ((_b = (_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)[0]) !== null && _b !== void 0 ? _b : event.target);
|
|
21199
21465
|
// A datepicker's calendar is portaled to the body: a click in the calendar of a datepicker
|
|
21200
|
-
// inside this popover, in its content or its trigger, isn't outside it.
|
|
21201
|
-
|
|
21466
|
+
// inside this popover, in its content or its trigger, isn't outside it. The target can be
|
|
21467
|
+
// inside the calendar's shadow root, so look up across it.
|
|
21468
|
+
const calendar = closest$1('.pds-datepicker-calendar-portal', target);
|
|
21202
21469
|
const owner = calendar === null || calendar === void 0 ? void 0 : calendar.pdsDatepicker;
|
|
21203
21470
|
if (owner && (containsComposed$1(this.portalEl, owner) || containsComposed$1(this.triggerEl, owner)))
|
|
21204
21471
|
return;
|
|
21205
21472
|
// Check if click is outside both the popover portal and the trigger
|
|
21206
|
-
const clickedInsidePopover = (
|
|
21207
|
-
const clickedInsideTrigger = (
|
|
21473
|
+
const clickedInsidePopover = containsComposed$1(this.portalEl, target);
|
|
21474
|
+
const clickedInsideTrigger = containsComposed$1(this.triggerEl, target);
|
|
21208
21475
|
if (!clickedInsidePopover && !clickedInsideTrigger) {
|
|
21209
21476
|
this.hide();
|
|
21210
21477
|
}
|
|
@@ -21225,14 +21492,19 @@ class PdsPopover {
|
|
|
21225
21492
|
* Mirrors native Popover API: Escape closes and returns focus to trigger
|
|
21226
21493
|
*/
|
|
21227
21494
|
handleEscapeKey(event) {
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21495
|
+
// A control inside that closes on Escape (a datepicker, a combobox) has handled it already.
|
|
21496
|
+
if (event.key !== 'Escape' || event.defaultPrevented)
|
|
21497
|
+
return;
|
|
21498
|
+
// Like the native Popover API, Escape closes only the top popover: the last one opened that
|
|
21499
|
+
// it applies to. Every open popover hears it, so each checks whether it's that one.
|
|
21500
|
+
const top = [...openAutoPopovers].reverse().find(popover => popover.takesEscapeFrom(event));
|
|
21501
|
+
if (top !== this)
|
|
21502
|
+
return;
|
|
21503
|
+
// Take the key, so the dialog or modal around it doesn't close too.
|
|
21504
|
+
event.preventDefault();
|
|
21505
|
+
event.stopPropagation();
|
|
21506
|
+
// Close popover and return focus to trigger
|
|
21507
|
+
this.hide();
|
|
21236
21508
|
}
|
|
21237
21509
|
/**
|
|
21238
21510
|
* Handles scroll events to reposition the popover (debounced for performance)
|
|
@@ -21337,13 +21609,20 @@ class PdsPopover {
|
|
|
21337
21609
|
}
|
|
21338
21610
|
this.portalEl.style.top = `${top}px`;
|
|
21339
21611
|
this.portalEl.style.left = `${left}px`;
|
|
21612
|
+
// `position: fixed` measures from the viewport unless an ancestor becomes its containing block,
|
|
21613
|
+
// as a modal dialog does with its backdrop filter. Shift by however far it landed from the spot.
|
|
21614
|
+
const placed = this.portalEl.getBoundingClientRect();
|
|
21615
|
+
if (Math.abs(placed.top - top) > 0.5 || Math.abs(placed.left - left) > 0.5) {
|
|
21616
|
+
this.portalEl.style.top = `${2 * top - placed.top}px`;
|
|
21617
|
+
this.portalEl.style.left = `${2 * left - placed.left}px`;
|
|
21618
|
+
}
|
|
21340
21619
|
// Reset the repositioning guard after a short delay
|
|
21341
21620
|
setTimeout(() => {
|
|
21342
21621
|
this.isRepositioning = false;
|
|
21343
21622
|
}, 16); // ~1 frame at 60fps
|
|
21344
21623
|
}
|
|
21345
21624
|
render() {
|
|
21346
|
-
return (hAsync(Host, { key: '
|
|
21625
|
+
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 }))));
|
|
21347
21626
|
}
|
|
21348
21627
|
get el() { return getElement(this); }
|
|
21349
21628
|
static get watchers() { return {
|