mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 10:01:59 +08:00
fix(popover): popover positions correctly on all frameworks (#26306)
Resolves #25337
This commit is contained in:
@ -27,12 +27,7 @@ import { iosEnterAnimation } from './animations/ios.enter';
|
|||||||
import { iosLeaveAnimation } from './animations/ios.leave';
|
import { iosLeaveAnimation } from './animations/ios.leave';
|
||||||
import { mdEnterAnimation } from './animations/md.enter';
|
import { mdEnterAnimation } from './animations/md.enter';
|
||||||
import { mdLeaveAnimation } from './animations/md.leave';
|
import { mdLeaveAnimation } from './animations/md.leave';
|
||||||
import {
|
import { configureDismissInteraction, configureKeyboardInteraction, configureTriggerInteraction } from './utils';
|
||||||
configureDismissInteraction,
|
|
||||||
configureKeyboardInteraction,
|
|
||||||
configureTriggerInteraction,
|
|
||||||
waitOneFrame,
|
|
||||||
} from './utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||||
@ -464,18 +459,21 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
|||||||
}
|
}
|
||||||
this.configureDismissInteraction();
|
this.configureDismissInteraction();
|
||||||
|
|
||||||
// TODO: FW-2773: Apply this to only the lazy build.
|
|
||||||
/**
|
|
||||||
* ionMount only needs to be emitted if the popover is inline.
|
|
||||||
*/
|
|
||||||
this.ionMount.emit();
|
this.ionMount.emit();
|
||||||
/**
|
|
||||||
* Wait one raf before presenting the popover.
|
|
||||||
* This allows the lazy build enough time to
|
|
||||||
* calculate the popover dimensions for the animation.
|
|
||||||
*/
|
|
||||||
await waitOneFrame();
|
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
/**
|
||||||
|
* Wait two request animation frame loops before presenting the popover.
|
||||||
|
* This allows the framework implementations enough time to mount
|
||||||
|
* the popover contents, so the bounding box is set when the popover
|
||||||
|
* transition starts.
|
||||||
|
*
|
||||||
|
* On Angular and React, a single raf is enough time, but for Vue
|
||||||
|
* we need to wait two rafs. As a result we are using two rafs for
|
||||||
|
* all frameworks to ensure the popover is presented correctly.
|
||||||
|
*/
|
||||||
|
raf(() => {
|
||||||
|
raf(async () => {
|
||||||
this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, {
|
this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, {
|
||||||
event: event || this.event,
|
event: event || this.event,
|
||||||
size: this.size,
|
size: this.size,
|
||||||
@ -498,6 +496,11 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
|||||||
if (this.focusDescendantOnPresent) {
|
if (this.focusDescendantOnPresent) {
|
||||||
focusFirstDescendant(this.el, this.el);
|
focusFirstDescendant(this.el, this.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -928,7 +928,3 @@ export const shouldShowArrow = (side: PositionSide, didAdjustBounds = false, ev?
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const waitOneFrame = () => {
|
|
||||||
return new Promise<void>((resolve) => raf(() => resolve()));
|
|
||||||
};
|
|
||||||
|
@ -55,6 +55,17 @@ export const createInlineOverlayComponent = <PropType, ElementType>(
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.componentDidUpdate(this.props);
|
this.componentDidUpdate(this.props);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mount the inner component when the
|
||||||
|
* overlay is about to open.
|
||||||
|
*
|
||||||
|
* For ion-popover, this is when `ionMount` is emitted.
|
||||||
|
* For other overlays, this is when `willPresent` is emitted.
|
||||||
|
*/
|
||||||
|
this.ref.current?.addEventListener('ionMount', () => {
|
||||||
|
this.setState({ isOpen: true });
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount the inner component
|
* Mount the inner component
|
||||||
* when overlay is about to open.
|
* when overlay is about to open.
|
||||||
|
@ -139,6 +139,7 @@ export const defineOverlayContainer = <Props extends object>(name: string, defin
|
|||||||
const elementRef = ref();
|
const elementRef = ref();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
elementRef.value.addEventListener('ion-mount', () => isOpen.value = true);
|
||||||
elementRef.value.addEventListener('will-present', () => isOpen.value = true);
|
elementRef.value.addEventListener('will-present', () => isOpen.value = true);
|
||||||
elementRef.value.addEventListener('did-dismiss', () => isOpen.value = false);
|
elementRef.value.addEventListener('did-dismiss', () => isOpen.value = false);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user