@ionic/core 8.7.17-dev.11767639327.19c404a6 → 8.7.17-dev.11767647939.17c197c2
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/modal.js +32 -15
- package/components/popover.js +13 -0
- package/dist/cjs/ion-modal.cjs.entry.js +32 -15
- package/dist/cjs/ion-popover.cjs.entry.js +13 -0
- package/dist/collection/components/modal/modal.js +32 -15
- package/dist/collection/components/popover/utils.js +13 -0
- package/dist/docs.json +1 -1
- package/dist/esm/ion-modal.entry.js +32 -15
- package/dist/esm/ion-popover.entry.js +13 -0
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-a4827773.entry.js +4 -0
- package/dist/ionic/p-fedca459.entry.js +4 -0
- package/dist/types/components/modal/modal.d.ts +6 -1
- package/hydrate/index.js +45 -15
- package/hydrate/index.mjs +45 -15
- package/package.json +1 -1
- package/dist/ionic/p-301ad219.entry.js +0 -4
- package/dist/ionic/p-71fa7adc.entry.js +0 -4
package/components/modal.js
CHANGED
|
@@ -2103,8 +2103,10 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2103
2103
|
*/
|
|
2104
2104
|
setInitialSafeAreaOverrides(presentingElement) {
|
|
2105
2105
|
const style = this.el.style;
|
|
2106
|
+
const mode = getIonMode(this);
|
|
2106
2107
|
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2107
|
-
|
|
2108
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
2109
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2108
2110
|
const isTablet = window.innerWidth >= 768;
|
|
2109
2111
|
// Sheet modals always touch bottom edge, never top/left/right
|
|
2110
2112
|
if (isSheetModal) {
|
|
@@ -2170,9 +2172,22 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2170
2172
|
style.setProperty('--ion-safe-area-left', '0px');
|
|
2171
2173
|
style.setProperty('--ion-safe-area-right', '0px');
|
|
2172
2174
|
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Gets the root safe-area values from the document element.
|
|
2177
|
+
* These represent the actual device safe areas before any overlay overrides.
|
|
2178
|
+
*/
|
|
2179
|
+
getRootSafeAreaValues() {
|
|
2180
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
2181
|
+
return {
|
|
2182
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
2183
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
2184
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
2185
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2173
2188
|
/**
|
|
2174
2189
|
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2175
|
-
*
|
|
2190
|
+
* extends into each safe-area region. Called after animation
|
|
2176
2191
|
* and during gestures to handle dynamic position changes.
|
|
2177
2192
|
*/
|
|
2178
2193
|
updateSafeAreaOverrides() {
|
|
@@ -2184,18 +2199,20 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2184
2199
|
return;
|
|
2185
2200
|
}
|
|
2186
2201
|
const rect = wrapper.getBoundingClientRect();
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2189
|
-
const
|
|
2190
|
-
const
|
|
2191
|
-
const
|
|
2202
|
+
const safeAreas = this.getRootSafeAreaValues();
|
|
2203
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
2204
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
2205
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
2206
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
2192
2207
|
const style = this.el.style;
|
|
2193
|
-
|
|
2194
|
-
|
|
2208
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2209
|
+
extendsIntoBottom
|
|
2195
2210
|
? style.removeProperty('--ion-safe-area-bottom')
|
|
2196
2211
|
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2197
|
-
|
|
2198
|
-
|
|
2212
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2213
|
+
extendsIntoRight
|
|
2214
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
2215
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
2199
2216
|
}
|
|
2200
2217
|
sheetOnDismiss() {
|
|
2201
2218
|
/**
|
|
@@ -2540,20 +2557,20 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2540
2557
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2541
2558
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2542
2559
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2543
|
-
return (h(Host, Object.assign({ key: '
|
|
2560
|
+
return (h(Host, Object.assign({ key: '07ebca6a70eb99f8a2236e1d66a03097a7bb67d8', "no-router": true,
|
|
2544
2561
|
// Allow the modal to be navigable when the handle is focusable
|
|
2545
2562
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2546
2563
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2547
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '
|
|
2564
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '1b6850d9b9f6e8f3865b49e0a14399e2ef43a5d6', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: 'eab52c0ebccb820781e92392dc6fa90db93525d5', class: "modal-shadow" }), h("div", Object.assign({ key: 'ab9448cabdf03a633319999771ce1ca1edce5699',
|
|
2548
2565
|
/*
|
|
2549
2566
|
role and aria-modal must be used on the
|
|
2550
2567
|
same element. They must also be set inside the
|
|
2551
2568
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2552
2569
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2553
2570
|
*/
|
|
2554
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
2571
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: 'b2b8c0a8d8add0d43e928dd3d3519f184551e62b', class: "modal-handle",
|
|
2555
2572
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2556
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '
|
|
2573
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'b994f206765f7b340971d378f00999c0da334102', onSlotchange: this.onSlotChange }))));
|
|
2557
2574
|
}
|
|
2558
2575
|
get el() { return this; }
|
|
2559
2576
|
static get watchers() { return {
|
package/components/popover.js
CHANGED
|
@@ -730,6 +730,19 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
730
730
|
checkSafeAreaBottom = true;
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Final check: If the popover extends into any safe-area region,
|
|
735
|
+
* ensure the corresponding flag is set regardless of side.
|
|
736
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
737
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
738
|
+
*/
|
|
739
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
740
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
741
|
+
checkSafeAreaBottom = true;
|
|
742
|
+
}
|
|
743
|
+
if (top < safeAreaMargin) {
|
|
744
|
+
checkSafeAreaTop = true;
|
|
745
|
+
}
|
|
733
746
|
return {
|
|
734
747
|
top,
|
|
735
748
|
left,
|
|
@@ -2102,8 +2102,10 @@ const Modal = class {
|
|
|
2102
2102
|
*/
|
|
2103
2103
|
setInitialSafeAreaOverrides(presentingElement) {
|
|
2104
2104
|
const style = this.el.style;
|
|
2105
|
+
const mode = ionicGlobal.getIonMode(this);
|
|
2105
2106
|
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2106
|
-
|
|
2107
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
2108
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2107
2109
|
const isTablet = window.innerWidth >= 768;
|
|
2108
2110
|
// Sheet modals always touch bottom edge, never top/left/right
|
|
2109
2111
|
if (isSheetModal) {
|
|
@@ -2169,9 +2171,22 @@ const Modal = class {
|
|
|
2169
2171
|
style.setProperty('--ion-safe-area-left', '0px');
|
|
2170
2172
|
style.setProperty('--ion-safe-area-right', '0px');
|
|
2171
2173
|
}
|
|
2174
|
+
/**
|
|
2175
|
+
* Gets the root safe-area values from the document element.
|
|
2176
|
+
* These represent the actual device safe areas before any overlay overrides.
|
|
2177
|
+
*/
|
|
2178
|
+
getRootSafeAreaValues() {
|
|
2179
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
2180
|
+
return {
|
|
2181
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
2182
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
2183
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
2184
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2172
2187
|
/**
|
|
2173
2188
|
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2174
|
-
*
|
|
2189
|
+
* extends into each safe-area region. Called after animation
|
|
2175
2190
|
* and during gestures to handle dynamic position changes.
|
|
2176
2191
|
*/
|
|
2177
2192
|
updateSafeAreaOverrides() {
|
|
@@ -2183,18 +2198,20 @@ const Modal = class {
|
|
|
2183
2198
|
return;
|
|
2184
2199
|
}
|
|
2185
2200
|
const rect = wrapper.getBoundingClientRect();
|
|
2186
|
-
const
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2189
|
-
const
|
|
2190
|
-
const
|
|
2201
|
+
const safeAreas = this.getRootSafeAreaValues();
|
|
2202
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
2203
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
2204
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
2205
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
2191
2206
|
const style = this.el.style;
|
|
2192
|
-
|
|
2193
|
-
|
|
2207
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2208
|
+
extendsIntoBottom
|
|
2194
2209
|
? style.removeProperty('--ion-safe-area-bottom')
|
|
2195
2210
|
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2196
|
-
|
|
2197
|
-
|
|
2211
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2212
|
+
extendsIntoRight
|
|
2213
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
2214
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
2198
2215
|
}
|
|
2199
2216
|
sheetOnDismiss() {
|
|
2200
2217
|
/**
|
|
@@ -2539,20 +2556,20 @@ const Modal = class {
|
|
|
2539
2556
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2540
2557
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2541
2558
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2542
|
-
return (index$3.h(index$3.Host, Object.assign({ key: '
|
|
2559
|
+
return (index$3.h(index$3.Host, Object.assign({ key: '07ebca6a70eb99f8a2236e1d66a03097a7bb67d8', "no-router": true,
|
|
2543
2560
|
// Allow the modal to be navigable when the handle is focusable
|
|
2544
2561
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2545
2562
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2546
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: '
|
|
2563
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: '1b6850d9b9f6e8f3865b49e0a14399e2ef43a5d6', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && index$3.h("div", { key: 'eab52c0ebccb820781e92392dc6fa90db93525d5', class: "modal-shadow" }), index$3.h("div", Object.assign({ key: 'ab9448cabdf03a633319999771ce1ca1edce5699',
|
|
2547
2564
|
/*
|
|
2548
2565
|
role and aria-modal must be used on the
|
|
2549
2566
|
same element. They must also be set inside the
|
|
2550
2567
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2551
2568
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2552
2569
|
*/
|
|
2553
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: '
|
|
2570
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: 'b2b8c0a8d8add0d43e928dd3d3519f184551e62b', class: "modal-handle",
|
|
2554
2571
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2555
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), index$3.h("slot", { key: '
|
|
2572
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), index$3.h("slot", { key: 'b994f206765f7b340971d378f00999c0da334102', onSlotchange: this.onSlotChange }))));
|
|
2556
2573
|
}
|
|
2557
2574
|
get el() { return index$3.getElement(this); }
|
|
2558
2575
|
static get watchers() { return {
|
|
@@ -733,6 +733,19 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
733
733
|
checkSafeAreaBottom = true;
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
|
+
/**
|
|
737
|
+
* Final check: If the popover extends into any safe-area region,
|
|
738
|
+
* ensure the corresponding flag is set regardless of side.
|
|
739
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
740
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
741
|
+
*/
|
|
742
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
743
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
744
|
+
checkSafeAreaBottom = true;
|
|
745
|
+
}
|
|
746
|
+
if (top < safeAreaMargin) {
|
|
747
|
+
checkSafeAreaTop = true;
|
|
748
|
+
}
|
|
736
749
|
return {
|
|
737
750
|
top,
|
|
738
751
|
left,
|
|
@@ -641,8 +641,10 @@ export class Modal {
|
|
|
641
641
|
*/
|
|
642
642
|
setInitialSafeAreaOverrides(presentingElement) {
|
|
643
643
|
const style = this.el.style;
|
|
644
|
+
const mode = getIonMode(this);
|
|
644
645
|
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
645
|
-
|
|
646
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
647
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
646
648
|
const isTablet = window.innerWidth >= 768;
|
|
647
649
|
// Sheet modals always touch bottom edge, never top/left/right
|
|
648
650
|
if (isSheetModal) {
|
|
@@ -708,9 +710,22 @@ export class Modal {
|
|
|
708
710
|
style.setProperty('--ion-safe-area-left', '0px');
|
|
709
711
|
style.setProperty('--ion-safe-area-right', '0px');
|
|
710
712
|
}
|
|
713
|
+
/**
|
|
714
|
+
* Gets the root safe-area values from the document element.
|
|
715
|
+
* These represent the actual device safe areas before any overlay overrides.
|
|
716
|
+
*/
|
|
717
|
+
getRootSafeAreaValues() {
|
|
718
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
719
|
+
return {
|
|
720
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
721
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
722
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
723
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
724
|
+
};
|
|
725
|
+
}
|
|
711
726
|
/**
|
|
712
727
|
* Updates safe-area CSS variable overrides based on whether the modal
|
|
713
|
-
*
|
|
728
|
+
* extends into each safe-area region. Called after animation
|
|
714
729
|
* and during gestures to handle dynamic position changes.
|
|
715
730
|
*/
|
|
716
731
|
updateSafeAreaOverrides() {
|
|
@@ -722,18 +737,20 @@ export class Modal {
|
|
|
722
737
|
return;
|
|
723
738
|
}
|
|
724
739
|
const rect = wrapper.getBoundingClientRect();
|
|
725
|
-
const
|
|
726
|
-
const
|
|
727
|
-
const
|
|
728
|
-
const
|
|
729
|
-
const
|
|
740
|
+
const safeAreas = this.getRootSafeAreaValues();
|
|
741
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
742
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
743
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
744
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
730
745
|
const style = this.el.style;
|
|
731
|
-
|
|
732
|
-
|
|
746
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
747
|
+
extendsIntoBottom
|
|
733
748
|
? style.removeProperty('--ion-safe-area-bottom')
|
|
734
749
|
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
735
|
-
|
|
736
|
-
|
|
750
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
751
|
+
extendsIntoRight
|
|
752
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
753
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
737
754
|
}
|
|
738
755
|
sheetOnDismiss() {
|
|
739
756
|
/**
|
|
@@ -1086,20 +1103,20 @@ export class Modal {
|
|
|
1086
1103
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
1087
1104
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
1088
1105
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
1089
|
-
return (h(Host, Object.assign({ key: '
|
|
1106
|
+
return (h(Host, Object.assign({ key: '07ebca6a70eb99f8a2236e1d66a03097a7bb67d8', "no-router": true,
|
|
1090
1107
|
// Allow the modal to be navigable when the handle is focusable
|
|
1091
1108
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
1092
1109
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
1093
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '
|
|
1110
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '1b6850d9b9f6e8f3865b49e0a14399e2ef43a5d6', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: 'eab52c0ebccb820781e92392dc6fa90db93525d5', class: "modal-shadow" }), h("div", Object.assign({ key: 'ab9448cabdf03a633319999771ce1ca1edce5699',
|
|
1094
1111
|
/*
|
|
1095
1112
|
role and aria-modal must be used on the
|
|
1096
1113
|
same element. They must also be set inside the
|
|
1097
1114
|
shadow DOM otherwise ion-button will not be highlighted
|
|
1098
1115
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
1099
1116
|
*/
|
|
1100
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
1117
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: 'b2b8c0a8d8add0d43e928dd3d3519f184551e62b', class: "modal-handle",
|
|
1101
1118
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
1102
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '
|
|
1119
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'b994f206765f7b340971d378f00999c0da334102', onSlotchange: this.onSlotChange }))));
|
|
1103
1120
|
}
|
|
1104
1121
|
static get is() { return "ion-modal"; }
|
|
1105
1122
|
static get encapsulation() { return "shadow"; }
|
|
@@ -721,6 +721,19 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
|
|
|
721
721
|
checkSafeAreaBottom = true;
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* Final check: If the popover extends into any safe-area region,
|
|
726
|
+
* ensure the corresponding flag is set regardless of side.
|
|
727
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
728
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
729
|
+
*/
|
|
730
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
731
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
732
|
+
checkSafeAreaBottom = true;
|
|
733
|
+
}
|
|
734
|
+
if (top < safeAreaMargin) {
|
|
735
|
+
checkSafeAreaTop = true;
|
|
736
|
+
}
|
|
724
737
|
return {
|
|
725
738
|
top,
|
|
726
739
|
left,
|
package/dist/docs.json
CHANGED
|
@@ -2100,8 +2100,10 @@ const Modal = class {
|
|
|
2100
2100
|
*/
|
|
2101
2101
|
setInitialSafeAreaOverrides(presentingElement) {
|
|
2102
2102
|
const style = this.el.style;
|
|
2103
|
+
const mode = getIonMode(this);
|
|
2103
2104
|
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2104
|
-
|
|
2105
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
2106
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2105
2107
|
const isTablet = window.innerWidth >= 768;
|
|
2106
2108
|
// Sheet modals always touch bottom edge, never top/left/right
|
|
2107
2109
|
if (isSheetModal) {
|
|
@@ -2167,9 +2169,22 @@ const Modal = class {
|
|
|
2167
2169
|
style.setProperty('--ion-safe-area-left', '0px');
|
|
2168
2170
|
style.setProperty('--ion-safe-area-right', '0px');
|
|
2169
2171
|
}
|
|
2172
|
+
/**
|
|
2173
|
+
* Gets the root safe-area values from the document element.
|
|
2174
|
+
* These represent the actual device safe areas before any overlay overrides.
|
|
2175
|
+
*/
|
|
2176
|
+
getRootSafeAreaValues() {
|
|
2177
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
2178
|
+
return {
|
|
2179
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
2180
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
2181
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
2182
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2170
2185
|
/**
|
|
2171
2186
|
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2172
|
-
*
|
|
2187
|
+
* extends into each safe-area region. Called after animation
|
|
2173
2188
|
* and during gestures to handle dynamic position changes.
|
|
2174
2189
|
*/
|
|
2175
2190
|
updateSafeAreaOverrides() {
|
|
@@ -2181,18 +2196,20 @@ const Modal = class {
|
|
|
2181
2196
|
return;
|
|
2182
2197
|
}
|
|
2183
2198
|
const rect = wrapper.getBoundingClientRect();
|
|
2184
|
-
const
|
|
2185
|
-
const
|
|
2186
|
-
const
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2199
|
+
const safeAreas = this.getRootSafeAreaValues();
|
|
2200
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
2201
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
2202
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
2203
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
2189
2204
|
const style = this.el.style;
|
|
2190
|
-
|
|
2191
|
-
|
|
2205
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2206
|
+
extendsIntoBottom
|
|
2192
2207
|
? style.removeProperty('--ion-safe-area-bottom')
|
|
2193
2208
|
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2194
|
-
|
|
2195
|
-
|
|
2209
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2210
|
+
extendsIntoRight
|
|
2211
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
2212
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
2196
2213
|
}
|
|
2197
2214
|
sheetOnDismiss() {
|
|
2198
2215
|
/**
|
|
@@ -2537,20 +2554,20 @@ const Modal = class {
|
|
|
2537
2554
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2538
2555
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2539
2556
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2540
|
-
return (h(Host, Object.assign({ key: '
|
|
2557
|
+
return (h(Host, Object.assign({ key: '07ebca6a70eb99f8a2236e1d66a03097a7bb67d8', "no-router": true,
|
|
2541
2558
|
// Allow the modal to be navigable when the handle is focusable
|
|
2542
2559
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2543
2560
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2544
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '
|
|
2561
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '1b6850d9b9f6e8f3865b49e0a14399e2ef43a5d6', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: 'eab52c0ebccb820781e92392dc6fa90db93525d5', class: "modal-shadow" }), h("div", Object.assign({ key: 'ab9448cabdf03a633319999771ce1ca1edce5699',
|
|
2545
2562
|
/*
|
|
2546
2563
|
role and aria-modal must be used on the
|
|
2547
2564
|
same element. They must also be set inside the
|
|
2548
2565
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2549
2566
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2550
2567
|
*/
|
|
2551
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
2568
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: 'b2b8c0a8d8add0d43e928dd3d3519f184551e62b', class: "modal-handle",
|
|
2552
2569
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2553
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '
|
|
2570
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'b994f206765f7b340971d378f00999c0da334102', onSlotchange: this.onSlotChange }))));
|
|
2554
2571
|
}
|
|
2555
2572
|
get el() { return getElement(this); }
|
|
2556
2573
|
static get watchers() { return {
|
|
@@ -731,6 +731,19 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
731
731
|
checkSafeAreaBottom = true;
|
|
732
732
|
}
|
|
733
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* Final check: If the popover extends into any safe-area region,
|
|
736
|
+
* ensure the corresponding flag is set regardless of side.
|
|
737
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
738
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
739
|
+
*/
|
|
740
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
741
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
742
|
+
checkSafeAreaBottom = true;
|
|
743
|
+
}
|
|
744
|
+
if (top < safeAreaMargin) {
|
|
745
|
+
checkSafeAreaTop = true;
|
|
746
|
+
}
|
|
734
747
|
return {
|
|
735
748
|
top,
|
|
736
749
|
left,
|