mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(modal, popover): overlays now automatically determine if they are inline (#23434)
This commit is contained in:
4
core/src/components.d.ts
vendored
4
core/src/components.d.ts
vendored
@ -1395,7 +1395,6 @@ export namespace Components {
|
|||||||
* Animation to use when the modal is presented.
|
* Animation to use when the modal is presented.
|
||||||
*/
|
*/
|
||||||
"enterAnimation"?: AnimationBuilder;
|
"enterAnimation"?: AnimationBuilder;
|
||||||
"inline": boolean;
|
|
||||||
/**
|
/**
|
||||||
* If `true`, the modal will open. If `false`, the modal will close. Use this if you need finer grained control over presentation, otherwise just use the modalController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the modal dismisses. You will need to do that in your code.
|
* If `true`, the modal will open. If `false`, the modal will close. Use this if you need finer grained control over presentation, otherwise just use the modalController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the modal dismisses. You will need to do that in your code.
|
||||||
*/
|
*/
|
||||||
@ -1707,7 +1706,6 @@ export namespace Components {
|
|||||||
*/
|
*/
|
||||||
"event": any;
|
"event": any;
|
||||||
"getParentPopover": () => Promise<HTMLIonPopoverElement | null>;
|
"getParentPopover": () => Promise<HTMLIonPopoverElement | null>;
|
||||||
"inline": boolean;
|
|
||||||
/**
|
/**
|
||||||
* If `true`, the popover will open. If `false`, the popover will close. Use this if you need finer grained control over presentation, otherwise just use the popoverController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the popover dismisses. You will need to do that in your code.
|
* If `true`, the popover will open. If `false`, the popover will close. Use this if you need finer grained control over presentation, otherwise just use the popoverController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the popover dismisses. You will need to do that in your code.
|
||||||
*/
|
*/
|
||||||
@ -4854,7 +4852,6 @@ declare namespace LocalJSX {
|
|||||||
* Animation to use when the modal is presented.
|
* Animation to use when the modal is presented.
|
||||||
*/
|
*/
|
||||||
"enterAnimation"?: AnimationBuilder;
|
"enterAnimation"?: AnimationBuilder;
|
||||||
"inline"?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* If `true`, the modal will open. If `false`, the modal will close. Use this if you need finer grained control over presentation, otherwise just use the modalController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the modal dismisses. You will need to do that in your code.
|
* If `true`, the modal will open. If `false`, the modal will close. Use this if you need finer grained control over presentation, otherwise just use the modalController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the modal dismisses. You will need to do that in your code.
|
||||||
*/
|
*/
|
||||||
@ -5099,7 +5096,6 @@ declare namespace LocalJSX {
|
|||||||
* The event to pass to the popover animation.
|
* The event to pass to the popover animation.
|
||||||
*/
|
*/
|
||||||
"event"?: any;
|
"event"?: any;
|
||||||
"inline"?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* If `true`, the popover will open. If `false`, the popover will close. Use this if you need finer grained control over presentation, otherwise just use the popoverController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the popover dismisses. You will need to do that in your code.
|
* If `true`, the popover will open. If `false`, the popover will close. Use this if you need finer grained control over presentation, otherwise just use the popoverController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the popover dismisses. You will need to do that in your code.
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,9 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
|||||||
private currentTransition?: Promise<any>;
|
private currentTransition?: Promise<any>;
|
||||||
private destroyTriggerInteraction?: () => void;
|
private destroyTriggerInteraction?: () => void;
|
||||||
|
|
||||||
|
private inline = false;
|
||||||
|
private workingDelegate?: FrameworkDelegate;
|
||||||
|
|
||||||
// Reference to the user's provided modal content
|
// Reference to the user's provided modal content
|
||||||
private usersElement?: HTMLElement;
|
private usersElement?: HTMLElement;
|
||||||
|
|
||||||
@ -51,9 +54,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
|||||||
|
|
||||||
@Element() el!: HTMLIonModalElement;
|
@Element() el!: HTMLIonModalElement;
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
@Prop() inline = true;
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@Prop() overlayIndex!: number;
|
@Prop() overlayIndex!: number;
|
||||||
|
|
||||||
@ -249,6 +249,39 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
|||||||
this.destroyTriggerInteraction = configureTriggerInteraction(triggerEl, el);
|
this.destroyTriggerInteraction = configureTriggerInteraction(triggerEl, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not an overlay
|
||||||
|
* is being used inline or via a controller/JS
|
||||||
|
* and returns the correct delegate.
|
||||||
|
* By default, subsequent calls to getDelegate
|
||||||
|
* will use a cached version of the delegate.
|
||||||
|
* This is useful for calling dismiss after
|
||||||
|
* present so that the correct delegate is given.
|
||||||
|
*/
|
||||||
|
private getDelegate(force = false) {
|
||||||
|
if (this.workingDelegate && !force) {
|
||||||
|
return {
|
||||||
|
delegate: this.workingDelegate,
|
||||||
|
inline: this.inline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If using overlay inline
|
||||||
|
* we potentially need to use the coreDelegate
|
||||||
|
* so that this works in vanilla JS apps.
|
||||||
|
* If a user has already placed the overlay
|
||||||
|
* as a direct descendant of ion-app or
|
||||||
|
* the body, then we can assume that
|
||||||
|
* the overlay is already in the correct place.
|
||||||
|
*/
|
||||||
|
const parentEl = this.el.parentNode as HTMLElement | null;
|
||||||
|
const inline = this.inline = parentEl !== null && parentEl.tagName !== 'ION-APP' && parentEl.tagName !== 'BODY';
|
||||||
|
const delegate = this.workingDelegate = (inline) ? this.delegate || this.coreDelegate : this.delegate
|
||||||
|
|
||||||
|
return { inline, delegate }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Present the modal overlay after it has been created.
|
* Present the modal overlay after it has been created.
|
||||||
*/
|
*/
|
||||||
@ -275,14 +308,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
|||||||
modal: this.el
|
modal: this.el
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const { inline, delegate } = this.getDelegate(true);
|
||||||
* If using modal inline
|
this.usersElement = await attachComponent(delegate, this.el, this.component, ['ion-page'], data, inline);
|
||||||
* we potentially need to use the coreDelegate
|
|
||||||
* so that this works in vanilla JS apps
|
|
||||||
*/
|
|
||||||
const delegate = (this.inline) ? this.delegate || this.coreDelegate : this.delegate;
|
|
||||||
|
|
||||||
this.usersElement = await attachComponent(delegate, this.el, this.component, ['ion-page'], data, this.inline);
|
|
||||||
|
|
||||||
await deepReady(this.usersElement);
|
await deepReady(this.usersElement);
|
||||||
|
|
||||||
@ -362,7 +389,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
|||||||
const dismissed = await this.currentTransition;
|
const dismissed = await this.currentTransition;
|
||||||
|
|
||||||
if (dismissed) {
|
if (dismissed) {
|
||||||
const delegate = (this.inline) ? this.delegate || this.coreDelegate : this.delegate;
|
const { delegate } = this.getDelegate();
|
||||||
await detachComponent(delegate, this.usersElement);
|
await detachComponent(delegate, this.usersElement);
|
||||||
if (this.animation) {
|
if (this.animation) {
|
||||||
this.animation.destroy();
|
this.animation.destroy();
|
||||||
|
@ -45,6 +45,9 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
|||||||
private destroyKeyboardInteraction?: () => void;
|
private destroyKeyboardInteraction?: () => void;
|
||||||
private destroyDismissInteraction?: () => void;
|
private destroyDismissInteraction?: () => void;
|
||||||
|
|
||||||
|
private inline = false;
|
||||||
|
private workingDelegate?: FrameworkDelegate;
|
||||||
|
|
||||||
private triggerEv?: Event;
|
private triggerEv?: Event;
|
||||||
private focusDescendantOnPresent = false;
|
private focusDescendantOnPresent = false;
|
||||||
|
|
||||||
@ -54,9 +57,6 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
|||||||
|
|
||||||
@Element() el!: HTMLIonPopoverElement;
|
@Element() el!: HTMLIonPopoverElement;
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
@Prop() inline = true;
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@Prop() delegate?: FrameworkDelegate;
|
@Prop() delegate?: FrameworkDelegate;
|
||||||
|
|
||||||
@ -314,6 +314,39 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
|||||||
this.focusDescendantOnPresent = false;
|
this.focusDescendantOnPresent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not an overlay
|
||||||
|
* is being used inline or via a controller/JS
|
||||||
|
* and returns the correct delegate.
|
||||||
|
* By default, subsequent calls to getDelegate
|
||||||
|
* will use a cached version of the delegate.
|
||||||
|
* This is useful for calling dismiss after
|
||||||
|
* present so that the correct delegate is given.
|
||||||
|
*/
|
||||||
|
private getDelegate(force = false) {
|
||||||
|
if (this.workingDelegate && !force) {
|
||||||
|
return {
|
||||||
|
delegate: this.workingDelegate,
|
||||||
|
inline: this.inline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If using overlay inline
|
||||||
|
* we potentially need to use the coreDelegate
|
||||||
|
* so that this works in vanilla JS apps.
|
||||||
|
* If a user has already placed the overlay
|
||||||
|
* as a direct descendant of ion-app or
|
||||||
|
* the body, then we can assume that
|
||||||
|
* the overlay is already in the correct place.
|
||||||
|
*/
|
||||||
|
const parentEl = this.el.parentNode as HTMLElement | null;
|
||||||
|
const inline = this.inline = parentEl !== null && parentEl.tagName !== 'ION-APP' && parentEl.tagName !== 'BODY';
|
||||||
|
const delegate = this.workingDelegate = (inline) ? this.delegate || this.coreDelegate : this.delegate
|
||||||
|
|
||||||
|
return { inline, delegate }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Present the popover overlay after it has been created.
|
* Present the popover overlay after it has been created.
|
||||||
*/
|
*/
|
||||||
@ -340,14 +373,8 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
|||||||
popover: this.el
|
popover: this.el
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const { inline, delegate } = this.getDelegate(true);
|
||||||
* If using popover inline
|
this.usersElement = await attachComponent(delegate, this.el, this.component, ['popover-viewport'], data, inline);
|
||||||
* we potentially need to use the coreDelegate
|
|
||||||
* so that this works in vanilla JS apps
|
|
||||||
*/
|
|
||||||
const delegate = (this.inline) ? this.delegate || this.coreDelegate : this.delegate;
|
|
||||||
|
|
||||||
this.usersElement = await attachComponent(delegate, this.el, this.component, ['popover-viewport'], data, this.inline);
|
|
||||||
await deepReady(this.usersElement);
|
await deepReady(this.usersElement);
|
||||||
|
|
||||||
this.configureKeyboardInteraction();
|
this.configureKeyboardInteraction();
|
||||||
@ -421,7 +448,7 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
|||||||
* we potentially need to use the coreDelegate
|
* we potentially need to use the coreDelegate
|
||||||
* so that this works in vanilla JS apps
|
* so that this works in vanilla JS apps
|
||||||
*/
|
*/
|
||||||
const delegate = (this.inline) ? this.delegate || this.coreDelegate : this.delegate;
|
const { delegate } = this.getDelegate();
|
||||||
await detachComponent(delegate, this.usersElement);
|
await detachComponent(delegate, this.usersElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +53,8 @@ export const createOverlay = <T extends HTMLIonOverlayElement>(tagName: string,
|
|||||||
/**
|
/**
|
||||||
* Convert the passed in overlay options into props
|
* Convert the passed in overlay options into props
|
||||||
* that get passed down into the new overlay.
|
* that get passed down into the new overlay.
|
||||||
* Inline is needed for ion-popover as it can
|
|
||||||
* be presented via a controller or written
|
|
||||||
* inline in a template.
|
|
||||||
*/
|
*/
|
||||||
Object.assign(element, { ...opts, inline: false });
|
Object.assign(element, { ...opts });
|
||||||
|
|
||||||
// append the overlay element to the document body
|
// append the overlay element to the document body
|
||||||
getAppRoot(document).appendChild(element);
|
getAppRoot(document).appendChild(element);
|
||||||
|
Reference in New Issue
Block a user