@ionic/core 8.7.18-dev.11769439446.189f4fd6 → 8.7.18-dev.11769790854.11895f8f
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 +220 -12
- package/components/popover.js +83 -11
- package/dist/cjs/ion-modal.cjs.entry.js +220 -12
- package/dist/cjs/ion-popover.cjs.entry.js +83 -11
- package/dist/collection/components/modal/gestures/sheet.js +3 -1
- package/dist/collection/components/modal/gestures/swipe-to-close.js +3 -1
- package/dist/collection/components/modal/modal.ios.css +0 -4
- package/dist/collection/components/modal/modal.js +215 -7
- package/dist/collection/components/modal/modal.md.css +0 -4
- package/dist/collection/components/popover/animations/ios.enter.js +21 -5
- package/dist/collection/components/popover/animations/md.enter.js +30 -5
- package/dist/collection/components/popover/utils.js +32 -1
- package/dist/docs.json +1 -1
- package/dist/esm/ion-modal.entry.js +220 -12
- package/dist/esm/ion-popover.entry.js +83 -11
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-ec9ca3fe.entry.js +4 -0
- package/dist/ionic/p-ef4256eb.entry.js +4 -0
- package/dist/types/components/modal/gestures/sheet.d.ts +1 -1
- package/dist/types/components/modal/gestures/swipe-to-close.d.ts +1 -1
- package/dist/types/components/modal/modal.d.ts +47 -0
- package/dist/types/components/popover/utils.d.ts +2 -0
- package/hydrate/index.js +302 -22
- package/hydrate/index.mjs +302 -22
- package/package.json +1 -1
- package/dist/ionic/p-91840a80.entry.js +0 -4
- package/dist/ionic/p-f9061316.entry.js +0 -4
package/hydrate/index.js
CHANGED
|
@@ -21581,7 +21581,7 @@ const calculateSpringStep = (t) => {
|
|
|
21581
21581
|
const SwipeToCloseDefaults = {
|
|
21582
21582
|
MIN_PRESENTING_SCALE: 0.915,
|
|
21583
21583
|
};
|
|
21584
|
-
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
21584
|
+
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onGestureMove) => {
|
|
21585
21585
|
/**
|
|
21586
21586
|
* The step value at which a card modal
|
|
21587
21587
|
* is eligible for dismissing via gesture.
|
|
@@ -21738,6 +21738,8 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) =>
|
|
|
21738
21738
|
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
|
|
21739
21739
|
const clampedStep = clamp(0.0001, processedStep, maxStep);
|
|
21740
21740
|
animation.progressStep(clampedStep);
|
|
21741
|
+
// Notify modal of position change for safe-area updates
|
|
21742
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
21741
21743
|
/**
|
|
21742
21744
|
* When swiping down half way, the status bar style
|
|
21743
21745
|
* should be reset to its default value.
|
|
@@ -22281,7 +22283,7 @@ const mdLeaveAnimation$2 = (baseEl, opts) => {
|
|
|
22281
22283
|
return baseAnimation;
|
|
22282
22284
|
};
|
|
22283
22285
|
|
|
22284
|
-
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
|
|
22286
|
+
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onGestureMove) => {
|
|
22285
22287
|
// Defaults for the sheet swipe animation
|
|
22286
22288
|
const defaultBackdrop = [
|
|
22287
22289
|
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
|
|
@@ -22612,6 +22614,8 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
22612
22614
|
: step;
|
|
22613
22615
|
offset = clamp(0.0001, processedStep, maxStep);
|
|
22614
22616
|
animation.progressStep(offset);
|
|
22617
|
+
// Notify modal of position change for safe-area updates
|
|
22618
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
22615
22619
|
};
|
|
22616
22620
|
const onEnd = (detail) => {
|
|
22617
22621
|
/**
|
|
@@ -22806,9 +22810,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
22806
22810
|
};
|
|
22807
22811
|
};
|
|
22808
22812
|
|
|
22809
|
-
const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px
|
|
22813
|
+
const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}";
|
|
22810
22814
|
|
|
22811
|
-
const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px
|
|
22815
|
+
const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}";
|
|
22812
22816
|
|
|
22813
22817
|
// TODO(FW-2832): types
|
|
22814
22818
|
/**
|
|
@@ -22841,6 +22845,10 @@ class Modal {
|
|
|
22841
22845
|
this.inline = false;
|
|
22842
22846
|
// Whether or not modal is being dismissed via gesture
|
|
22843
22847
|
this.gestureAnimationDismissing = false;
|
|
22848
|
+
// Whether to skip coordinate-based safe-area detection (for fullscreen phone modals)
|
|
22849
|
+
this.skipSafeAreaCoordinateDetection = false;
|
|
22850
|
+
// Track previous safe-area state to avoid redundant DOM writes
|
|
22851
|
+
this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
|
|
22844
22852
|
this.presented = false;
|
|
22845
22853
|
/** @internal */
|
|
22846
22854
|
this.hasController = false;
|
|
@@ -23031,7 +23039,10 @@ class Modal {
|
|
|
23031
23039
|
}
|
|
23032
23040
|
}
|
|
23033
23041
|
onWindowResize() {
|
|
23034
|
-
//
|
|
23042
|
+
// Invalidate safe-area cache on resize (device rotation may change values)
|
|
23043
|
+
this.cachedSafeAreas = undefined;
|
|
23044
|
+
this.updateSafeAreaOverrides();
|
|
23045
|
+
// Only handle view transition for iOS card modals when no custom animations are provided
|
|
23035
23046
|
if (getIonMode$1(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
23036
23047
|
return;
|
|
23037
23048
|
}
|
|
@@ -23054,6 +23065,8 @@ class Modal {
|
|
|
23054
23065
|
this.triggerController.removeClickListener();
|
|
23055
23066
|
this.cleanupViewTransitionListener();
|
|
23056
23067
|
this.cleanupParentRemovalObserver();
|
|
23068
|
+
// Reset safe-area state to handle removal without dismiss (e.g., framework unmount)
|
|
23069
|
+
this.resetSafeAreaState();
|
|
23057
23070
|
}
|
|
23058
23071
|
componentWillLoad() {
|
|
23059
23072
|
var _a;
|
|
@@ -23213,6 +23226,8 @@ class Modal {
|
|
|
23213
23226
|
else if (!this.keepContentsMounted) {
|
|
23214
23227
|
await waitForMount();
|
|
23215
23228
|
}
|
|
23229
|
+
// Predict safe-area needs based on modal configuration to avoid visual snap
|
|
23230
|
+
this.setInitialSafeAreaOverrides(presentingElement);
|
|
23216
23231
|
writeTask(() => this.el.classList.add('show-modal'));
|
|
23217
23232
|
const hasCardModal = presentingElement !== undefined;
|
|
23218
23233
|
/**
|
|
@@ -23274,6 +23289,8 @@ class Modal {
|
|
|
23274
23289
|
else if (hasCardModal) {
|
|
23275
23290
|
this.initSwipeToClose();
|
|
23276
23291
|
}
|
|
23292
|
+
// Now that animation is complete, update safe-area based on actual position
|
|
23293
|
+
this.updateSafeAreaOverrides();
|
|
23277
23294
|
// Initialize view transition listener for iOS card modals
|
|
23278
23295
|
this.initViewTransitionListener();
|
|
23279
23296
|
// Initialize parent removal observer
|
|
@@ -23325,7 +23342,7 @@ class Modal {
|
|
|
23325
23342
|
await this.dismiss(undefined, GESTURE);
|
|
23326
23343
|
this.gestureAnimationDismissing = false;
|
|
23327
23344
|
});
|
|
23328
|
-
});
|
|
23345
|
+
}, () => this.updateSafeAreaOverrides());
|
|
23329
23346
|
this.gesture.enable(true);
|
|
23330
23347
|
}
|
|
23331
23348
|
initSheetGesture() {
|
|
@@ -23346,7 +23363,8 @@ class Modal {
|
|
|
23346
23363
|
this.currentBreakpoint = breakpoint;
|
|
23347
23364
|
this.ionBreakpointDidChange.emit({ breakpoint });
|
|
23348
23365
|
}
|
|
23349
|
-
|
|
23366
|
+
this.updateSafeAreaOverrides();
|
|
23367
|
+
}, () => this.updateSafeAreaOverrides());
|
|
23350
23368
|
this.gesture = gesture;
|
|
23351
23369
|
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
|
|
23352
23370
|
this.gesture.enable(true);
|
|
@@ -23424,6 +23442,194 @@ class Modal {
|
|
|
23424
23442
|
// Clear the cached reference
|
|
23425
23443
|
this.cachedPageParent = undefined;
|
|
23426
23444
|
}
|
|
23445
|
+
/**
|
|
23446
|
+
* Sets initial safe-area overrides based on modal configuration before
|
|
23447
|
+
* the modal becomes visible. This predicts whether the modal will touch
|
|
23448
|
+
* screen edges to avoid a visual snap after animation completes.
|
|
23449
|
+
*/
|
|
23450
|
+
setInitialSafeAreaOverrides(presentingElement) {
|
|
23451
|
+
const style = this.el.style;
|
|
23452
|
+
const mode = getIonMode$1(this);
|
|
23453
|
+
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
23454
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
23455
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
23456
|
+
const isTablet = window.innerWidth >= 768;
|
|
23457
|
+
// Sheet modals always touch bottom edge, never top/left/right
|
|
23458
|
+
if (isSheetModal) {
|
|
23459
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
23460
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
23461
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
23462
|
+
return;
|
|
23463
|
+
}
|
|
23464
|
+
// Card modals have rounded top corners
|
|
23465
|
+
if (isCardModal) {
|
|
23466
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
23467
|
+
if (isTablet) {
|
|
23468
|
+
// On tablets, card modals are inset from all edges
|
|
23469
|
+
this.zeroAllSafeAreas();
|
|
23470
|
+
}
|
|
23471
|
+
else {
|
|
23472
|
+
// On phones, card modals still extend to the bottom edge
|
|
23473
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
23474
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
23475
|
+
this.applyFullscreenSafeArea();
|
|
23476
|
+
}
|
|
23477
|
+
return;
|
|
23478
|
+
}
|
|
23479
|
+
// Check if modal is fullscreen via CSS custom properties
|
|
23480
|
+
// This applies to both phone and tablet sizes - custom modals may have
|
|
23481
|
+
// non-fullscreen dimensions even on phones (e.g., --height: 70%)
|
|
23482
|
+
const computedStyle = getComputedStyle(this.el);
|
|
23483
|
+
const width = computedStyle.getPropertyValue('--width').trim();
|
|
23484
|
+
const height = computedStyle.getPropertyValue('--height').trim();
|
|
23485
|
+
const isFullscreen = width === '100%' && height === '100%';
|
|
23486
|
+
if (isFullscreen) {
|
|
23487
|
+
this.applyFullscreenSafeArea();
|
|
23488
|
+
}
|
|
23489
|
+
else if (isTablet) {
|
|
23490
|
+
// Centered dialog on tablet doesn't touch edges
|
|
23491
|
+
this.zeroAllSafeAreas();
|
|
23492
|
+
}
|
|
23493
|
+
else ;
|
|
23494
|
+
}
|
|
23495
|
+
/**
|
|
23496
|
+
* Applies safe-area handling for fullscreen modals.
|
|
23497
|
+
* Adds wrapper padding when no footer is present to prevent
|
|
23498
|
+
* content from overlapping system navigation areas.
|
|
23499
|
+
*/
|
|
23500
|
+
applyFullscreenSafeArea() {
|
|
23501
|
+
this.skipSafeAreaCoordinateDetection = true;
|
|
23502
|
+
this.updateFooterPadding();
|
|
23503
|
+
// Watch for dynamic footer additions/removals (e.g., async data loading)
|
|
23504
|
+
// Use subtree:true to support wrapped footers in framework components
|
|
23505
|
+
// (e.g., <my-footer><ion-footer>...</ion-footer></my-footer>)
|
|
23506
|
+
if (!this.footerObserver && win$1 !== undefined && 'MutationObserver' in win$1) {
|
|
23507
|
+
this.footerObserver = new MutationObserver(() => this.updateFooterPadding());
|
|
23508
|
+
this.footerObserver.observe(this.el, { childList: true, subtree: true });
|
|
23509
|
+
}
|
|
23510
|
+
}
|
|
23511
|
+
/**
|
|
23512
|
+
* Updates wrapper and shadow padding based on footer presence.
|
|
23513
|
+
* Called initially and when footer is dynamically added/removed.
|
|
23514
|
+
* Both elements must be styled identically to prevent visual mismatches.
|
|
23515
|
+
*/
|
|
23516
|
+
updateFooterPadding() {
|
|
23517
|
+
if (!this.wrapperEl)
|
|
23518
|
+
return;
|
|
23519
|
+
const hasFooter = this.el.querySelector('ion-footer') !== null;
|
|
23520
|
+
// Apply to both wrapper and shadow to keep them in sync
|
|
23521
|
+
const elements = [this.wrapperEl, this.shadowEl].filter(Boolean);
|
|
23522
|
+
if (hasFooter) {
|
|
23523
|
+
elements.forEach((el) => {
|
|
23524
|
+
el.style.removeProperty('padding-bottom');
|
|
23525
|
+
el.style.removeProperty('box-sizing');
|
|
23526
|
+
});
|
|
23527
|
+
}
|
|
23528
|
+
else {
|
|
23529
|
+
elements.forEach((el) => {
|
|
23530
|
+
el.style.setProperty('padding-bottom', 'var(--ion-safe-area-bottom, 0px)');
|
|
23531
|
+
el.style.setProperty('box-sizing', 'border-box');
|
|
23532
|
+
});
|
|
23533
|
+
}
|
|
23534
|
+
}
|
|
23535
|
+
/**
|
|
23536
|
+
* Sets all safe-area CSS variables to 0px for modals that
|
|
23537
|
+
* don't touch screen edges.
|
|
23538
|
+
*/
|
|
23539
|
+
zeroAllSafeAreas() {
|
|
23540
|
+
const style = this.el.style;
|
|
23541
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
23542
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
23543
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
23544
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
23545
|
+
}
|
|
23546
|
+
/**
|
|
23547
|
+
* Resets all safe-area related state and styles.
|
|
23548
|
+
* Called during dismiss and disconnectedCallback to ensure clean state
|
|
23549
|
+
* for re-presentation of inline modals.
|
|
23550
|
+
*/
|
|
23551
|
+
resetSafeAreaState() {
|
|
23552
|
+
var _a;
|
|
23553
|
+
this.skipSafeAreaCoordinateDetection = false;
|
|
23554
|
+
this.cachedSafeAreas = undefined;
|
|
23555
|
+
this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
|
|
23556
|
+
(_a = this.footerObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
23557
|
+
this.footerObserver = undefined;
|
|
23558
|
+
// Clear wrapper and shadow styles that may have been set for safe-area handling
|
|
23559
|
+
[this.wrapperEl, this.shadowEl].forEach((el) => {
|
|
23560
|
+
if (el) {
|
|
23561
|
+
el.style.removeProperty('padding-bottom');
|
|
23562
|
+
el.style.removeProperty('box-sizing');
|
|
23563
|
+
}
|
|
23564
|
+
});
|
|
23565
|
+
// Clear safe-area CSS variable overrides
|
|
23566
|
+
const style = this.el.style;
|
|
23567
|
+
style.removeProperty('--ion-safe-area-top');
|
|
23568
|
+
style.removeProperty('--ion-safe-area-bottom');
|
|
23569
|
+
style.removeProperty('--ion-safe-area-left');
|
|
23570
|
+
style.removeProperty('--ion-safe-area-right');
|
|
23571
|
+
}
|
|
23572
|
+
/**
|
|
23573
|
+
* Gets the root safe-area values from the document element.
|
|
23574
|
+
* Uses cached values during gestures to avoid getComputedStyle calls.
|
|
23575
|
+
*/
|
|
23576
|
+
getSafeAreaValues() {
|
|
23577
|
+
if (!this.cachedSafeAreas) {
|
|
23578
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
23579
|
+
this.cachedSafeAreas = {
|
|
23580
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
23581
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
23582
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
23583
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
23584
|
+
};
|
|
23585
|
+
}
|
|
23586
|
+
return this.cachedSafeAreas;
|
|
23587
|
+
}
|
|
23588
|
+
/**
|
|
23589
|
+
* Updates safe-area CSS variable overrides based on whether the modal
|
|
23590
|
+
* extends into each safe-area region. Called after animation
|
|
23591
|
+
* and during gestures to handle dynamic position changes.
|
|
23592
|
+
*
|
|
23593
|
+
* Optimized to avoid redundant DOM writes by tracking previous state.
|
|
23594
|
+
*/
|
|
23595
|
+
updateSafeAreaOverrides() {
|
|
23596
|
+
if (this.skipSafeAreaCoordinateDetection) {
|
|
23597
|
+
return;
|
|
23598
|
+
}
|
|
23599
|
+
const wrapper = this.wrapperEl;
|
|
23600
|
+
if (!wrapper) {
|
|
23601
|
+
return;
|
|
23602
|
+
}
|
|
23603
|
+
const rect = wrapper.getBoundingClientRect();
|
|
23604
|
+
const safeAreas = this.getSafeAreaValues();
|
|
23605
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
23606
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
23607
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
23608
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
23609
|
+
// Only update DOM when state actually changes
|
|
23610
|
+
const prev = this.prevSafeAreaState;
|
|
23611
|
+
const style = this.el.style;
|
|
23612
|
+
if (extendsIntoTop !== prev.top) {
|
|
23613
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
23614
|
+
prev.top = extendsIntoTop;
|
|
23615
|
+
}
|
|
23616
|
+
if (extendsIntoBottom !== prev.bottom) {
|
|
23617
|
+
extendsIntoBottom
|
|
23618
|
+
? style.removeProperty('--ion-safe-area-bottom')
|
|
23619
|
+
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
23620
|
+
prev.bottom = extendsIntoBottom;
|
|
23621
|
+
}
|
|
23622
|
+
if (extendsIntoLeft !== prev.left) {
|
|
23623
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
23624
|
+
prev.left = extendsIntoLeft;
|
|
23625
|
+
}
|
|
23626
|
+
if (extendsIntoRight !== prev.right) {
|
|
23627
|
+
extendsIntoRight
|
|
23628
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
23629
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
23630
|
+
prev.right = extendsIntoRight;
|
|
23631
|
+
}
|
|
23632
|
+
}
|
|
23427
23633
|
sheetOnDismiss() {
|
|
23428
23634
|
/**
|
|
23429
23635
|
* While the gesture animation is finishing
|
|
@@ -23516,6 +23722,8 @@ class Modal {
|
|
|
23516
23722
|
}
|
|
23517
23723
|
this.currentBreakpoint = undefined;
|
|
23518
23724
|
this.animation = undefined;
|
|
23725
|
+
// Reset safe-area state for potential re-presentation
|
|
23726
|
+
this.resetSafeAreaState();
|
|
23519
23727
|
unlock();
|
|
23520
23728
|
return dismissed;
|
|
23521
23729
|
}
|
|
@@ -23765,20 +23973,20 @@ class Modal {
|
|
|
23765
23973
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
23766
23974
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
23767
23975
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
23768
|
-
return (hAsync(Host, Object.assign({ key: '
|
|
23976
|
+
return (hAsync(Host, Object.assign({ key: '8f42c71ec9c9270b4218ca7eec57ca998871ac07', "no-router": true,
|
|
23769
23977
|
// Allow the modal to be navigable when the handle is focusable
|
|
23770
23978
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
23771
23979
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
23772
|
-
}, 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 }), hAsync("ion-backdrop", { key: '
|
|
23980
|
+
}, 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 }), hAsync("ion-backdrop", { key: '2f7b08b019c66cbfceacafa9a68b91f8da1f4084', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && hAsync("div", { key: '6b0d1ae90e8483332f74371be5dcbd0a7b2661ba', class: "modal-shadow", ref: (el) => (this.shadowEl = el) }), hAsync("div", Object.assign({ key: 'c96f671fb25e5de45231ea65ac52500547b2e262',
|
|
23773
23981
|
/*
|
|
23774
23982
|
role and aria-modal must be used on the
|
|
23775
23983
|
same element. They must also be set inside the
|
|
23776
23984
|
shadow DOM otherwise ion-button will not be highlighted
|
|
23777
23985
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
23778
23986
|
*/
|
|
23779
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (hAsync("button", { key: '
|
|
23987
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (hAsync("button", { key: 'e07419b01a588c0ba62ed9607c843cac7bd26337', class: "modal-handle",
|
|
23780
23988
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
23781
|
-
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) })), hAsync("slot", { key: '
|
|
23989
|
+
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) })), hAsync("slot", { key: '65f35079df8eb8b6cd262e3a08297866715ce7ea', onSlotchange: this.onSlotChange }))));
|
|
23782
23990
|
}
|
|
23783
23991
|
get el() { return getElement(this); }
|
|
23784
23992
|
static get watchers() { return {
|
|
@@ -27356,6 +27564,8 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
27356
27564
|
let bottom;
|
|
27357
27565
|
let originX = contentOriginX;
|
|
27358
27566
|
let originY = contentOriginY;
|
|
27567
|
+
let checkSafeAreaTop = false;
|
|
27568
|
+
let checkSafeAreaBottom = false;
|
|
27359
27569
|
let checkSafeAreaLeft = false;
|
|
27360
27570
|
let checkSafeAreaRight = false;
|
|
27361
27571
|
const triggerTop = triggerCoordinates
|
|
@@ -27400,10 +27610,18 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
27400
27610
|
* We chose 12 here so that the popover position looks a bit nicer as
|
|
27401
27611
|
* it is not right up against the edge of the screen.
|
|
27402
27612
|
*/
|
|
27403
|
-
top = Math.max(
|
|
27613
|
+
top = Math.max(bodyPadding, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
|
|
27404
27614
|
arrowTop = top + contentHeight;
|
|
27405
27615
|
originY = 'bottom';
|
|
27406
27616
|
addPopoverBottomClass = true;
|
|
27617
|
+
/**
|
|
27618
|
+
* If the popover is positioned near the top edge, account for safe area.
|
|
27619
|
+
* This ensures the popover doesn't overlap with status bars or notches.
|
|
27620
|
+
*/
|
|
27621
|
+
if (top <= bodyPadding + safeAreaMargin) {
|
|
27622
|
+
checkSafeAreaTop = true;
|
|
27623
|
+
top = bodyPadding;
|
|
27624
|
+
}
|
|
27407
27625
|
/**
|
|
27408
27626
|
* If not enough room for popover to appear
|
|
27409
27627
|
* above trigger, then cut it off.
|
|
@@ -27411,14 +27629,35 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
27411
27629
|
}
|
|
27412
27630
|
else {
|
|
27413
27631
|
bottom = bodyPadding;
|
|
27632
|
+
/**
|
|
27633
|
+
* When the popover is pinned to the bottom, account for safe area.
|
|
27634
|
+
* This ensures the popover doesn't overlap with home indicators
|
|
27635
|
+
* or navigation bars (e.g., Android API 36+ edge-to-edge).
|
|
27636
|
+
*/
|
|
27637
|
+
checkSafeAreaBottom = true;
|
|
27414
27638
|
}
|
|
27415
27639
|
}
|
|
27640
|
+
/**
|
|
27641
|
+
* Final check: If the popover extends into any safe-area region,
|
|
27642
|
+
* ensure the corresponding flag is set regardless of side.
|
|
27643
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
27644
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
27645
|
+
*/
|
|
27646
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
27647
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
27648
|
+
checkSafeAreaBottom = true;
|
|
27649
|
+
}
|
|
27650
|
+
if (top < safeAreaMargin) {
|
|
27651
|
+
checkSafeAreaTop = true;
|
|
27652
|
+
}
|
|
27416
27653
|
return {
|
|
27417
27654
|
top,
|
|
27418
27655
|
left,
|
|
27419
27656
|
bottom,
|
|
27420
27657
|
originX,
|
|
27421
27658
|
originY,
|
|
27659
|
+
checkSafeAreaTop,
|
|
27660
|
+
checkSafeAreaBottom,
|
|
27422
27661
|
checkSafeAreaLeft,
|
|
27423
27662
|
checkSafeAreaRight,
|
|
27424
27663
|
arrowTop,
|
|
@@ -27479,7 +27718,7 @@ const iosEnterAnimation$1 = (baseEl, opts) => {
|
|
|
27479
27718
|
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, arrowWidth, arrowHeight, reference, side, align, defaultPosition, trigger, ev);
|
|
27480
27719
|
const padding = size === 'cover' ? 0 : POPOVER_IOS_BODY_PADDING;
|
|
27481
27720
|
const margin = size === 'cover' ? 0 : 25;
|
|
27482
|
-
const { originX, originY, top, left, bottom, checkSafeAreaLeft, checkSafeAreaRight, arrowTop, arrowLeft, addPopoverBottomClass, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, margin, results.originX, results.originY, results.referenceCoordinates, results.arrowTop, results.arrowLeft, arrowHeight);
|
|
27721
|
+
const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, arrowTop, arrowLeft, addPopoverBottomClass, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, margin, results.originX, results.originY, results.referenceCoordinates, results.arrowTop, results.arrowLeft, arrowHeight);
|
|
27483
27722
|
const baseAnimation = createAnimation();
|
|
27484
27723
|
const backdropAnimation = createAnimation();
|
|
27485
27724
|
const contentAnimation = createAnimation();
|
|
@@ -27509,19 +27748,35 @@ const iosEnterAnimation$1 = (baseEl, opts) => {
|
|
|
27509
27748
|
if (addPopoverBottomClass) {
|
|
27510
27749
|
baseEl.classList.add('popover-bottom');
|
|
27511
27750
|
}
|
|
27512
|
-
|
|
27513
|
-
|
|
27514
|
-
|
|
27751
|
+
/**
|
|
27752
|
+
* Safe area CSS variable adjustments.
|
|
27753
|
+
* When the popover is positioned near an edge, we add the corresponding
|
|
27754
|
+
* safe-area inset to ensure the popover doesn't overlap with system UI
|
|
27755
|
+
* (status bars, home indicators, navigation bars on Android API 36+, etc.)
|
|
27756
|
+
*/
|
|
27757
|
+
const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
|
|
27758
|
+
const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
|
|
27515
27759
|
const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
|
|
27516
27760
|
const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
|
|
27761
|
+
let topValue = `${top}px`;
|
|
27762
|
+
let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
|
|
27517
27763
|
let leftValue = `${left}px`;
|
|
27764
|
+
if (checkSafeAreaTop) {
|
|
27765
|
+
topValue = `${top}px${safeAreaTop}`;
|
|
27766
|
+
}
|
|
27767
|
+
if (checkSafeAreaBottom && bottomValue !== undefined) {
|
|
27768
|
+
bottomValue = `${bottom}px${safeAreaBottom}`;
|
|
27769
|
+
}
|
|
27518
27770
|
if (checkSafeAreaLeft) {
|
|
27519
27771
|
leftValue = `${left}px${safeAreaLeft}`;
|
|
27520
27772
|
}
|
|
27521
27773
|
if (checkSafeAreaRight) {
|
|
27522
27774
|
leftValue = `${left}px${safeAreaRight}`;
|
|
27523
27775
|
}
|
|
27524
|
-
|
|
27776
|
+
if (bottomValue !== undefined) {
|
|
27777
|
+
contentEl.style.setProperty('bottom', `calc(${bottomValue})`);
|
|
27778
|
+
}
|
|
27779
|
+
contentEl.style.setProperty('top', `calc(${topValue} + var(--offset-y, 0))`);
|
|
27525
27780
|
contentEl.style.setProperty('left', `calc(${leftValue} + var(--offset-x, 0))`);
|
|
27526
27781
|
contentEl.style.setProperty('transform-origin', `${originY} ${originX}`);
|
|
27527
27782
|
if (arrowEl !== null) {
|
|
@@ -27597,7 +27852,32 @@ const mdEnterAnimation$1 = (baseEl, opts) => {
|
|
|
27597
27852
|
};
|
|
27598
27853
|
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, 0, 0, reference, side, align, defaultPosition, trigger, ev);
|
|
27599
27854
|
const padding = size === 'cover' ? 0 : POPOVER_MD_BODY_PADDING;
|
|
27600
|
-
const { originX, originY, top, left, bottom } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
|
|
27855
|
+
const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
|
|
27856
|
+
/**
|
|
27857
|
+
* Safe area CSS variable adjustments.
|
|
27858
|
+
* When the popover is positioned near an edge, we add the corresponding
|
|
27859
|
+
* safe-area inset to ensure the popover doesn't overlap with system UI
|
|
27860
|
+
* (status bars, home indicators, navigation bars on Android API 36+, etc.)
|
|
27861
|
+
*/
|
|
27862
|
+
const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
|
|
27863
|
+
const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
|
|
27864
|
+
const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
|
|
27865
|
+
const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
|
|
27866
|
+
let topValue = `${top}px`;
|
|
27867
|
+
let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
|
|
27868
|
+
let leftValue = `${left}px`;
|
|
27869
|
+
if (checkSafeAreaTop) {
|
|
27870
|
+
topValue = `${top}px${safeAreaTop}`;
|
|
27871
|
+
}
|
|
27872
|
+
if (checkSafeAreaBottom && bottomValue !== undefined) {
|
|
27873
|
+
bottomValue = `${bottom}px${safeAreaBottom}`;
|
|
27874
|
+
}
|
|
27875
|
+
if (checkSafeAreaLeft) {
|
|
27876
|
+
leftValue = `${left}px${safeAreaLeft}`;
|
|
27877
|
+
}
|
|
27878
|
+
if (checkSafeAreaRight) {
|
|
27879
|
+
leftValue = `${left}px${safeAreaRight}`;
|
|
27880
|
+
}
|
|
27601
27881
|
const baseAnimation = createAnimation();
|
|
27602
27882
|
const backdropAnimation = createAnimation();
|
|
27603
27883
|
const wrapperAnimation = createAnimation();
|
|
@@ -27614,13 +27894,13 @@ const mdEnterAnimation$1 = (baseEl, opts) => {
|
|
|
27614
27894
|
contentAnimation
|
|
27615
27895
|
.addElement(contentEl)
|
|
27616
27896
|
.beforeStyles({
|
|
27617
|
-
top: `calc(${
|
|
27618
|
-
left: `calc(${
|
|
27897
|
+
top: `calc(${topValue} + var(--offset-y, 0px))`,
|
|
27898
|
+
left: `calc(${leftValue} + var(--offset-x, 0px))`,
|
|
27619
27899
|
'transform-origin': `${originY} ${originX}`,
|
|
27620
27900
|
})
|
|
27621
27901
|
.beforeAddWrite(() => {
|
|
27622
|
-
if (
|
|
27623
|
-
contentEl.style.setProperty('bottom',
|
|
27902
|
+
if (bottomValue !== undefined) {
|
|
27903
|
+
contentEl.style.setProperty('bottom', `calc(${bottomValue})`);
|
|
27624
27904
|
}
|
|
27625
27905
|
})
|
|
27626
27906
|
.fromTo('transform', 'scale(0.8)', 'scale(1)');
|