From 34ca337b8af27b144fb44428c8ed8cf07fc79bfc Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Mon, 24 Oct 2022 16:49:17 -0400 Subject: [PATCH] feat(loading): use loading overlay inline (#26153) --- core/api.txt | 6 + core/src/components.d.ts | 36 +++++ core/src/components/loading/loading.tsx | 124 ++++++++++++++- .../components/loading/test/isOpen/index.html | 80 ++++++++++ .../loading/test/isOpen/loading.e2e.ts | 30 ++++ .../loading/test/trigger/index.html | 71 +++++++++ .../loading/test/trigger/loading.e2e.ts | 31 ++++ core/src/utils/framework-delegate.ts | 4 +- core/src/utils/overlays-interface.ts | 1 + core/src/utils/overlays.ts | 150 ++++++++++++++++++ packages/react/src/components/IonLoading.tsx | 10 +- .../specs/overlay-components/IonLoading.cy.ts | 6 +- packages/vue/src/components/Overlays.ts | 2 +- 13 files changed, 536 insertions(+), 15 deletions(-) create mode 100644 core/src/components/loading/test/isOpen/index.html create mode 100644 core/src/components/loading/test/isOpen/loading.e2e.ts create mode 100644 core/src/components/loading/test/trigger/index.html create mode 100644 core/src/components/loading/test/trigger/loading.e2e.ts diff --git a/core/api.txt b/core/api.txt index 9a9ad389c9..17fd18ae3c 100644 --- a/core/api.txt +++ b/core/api.txt @@ -695,6 +695,7 @@ ion-loading,prop,cssClass,string | string[] | undefined,undefined,false,false ion-loading,prop,duration,number,0,false,false ion-loading,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-loading,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false +ion-loading,prop,isOpen,boolean,false,false,false ion-loading,prop,keyboardClose,boolean,true,false,false ion-loading,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-loading,prop,message,IonicSafeString | string | undefined,undefined,false,false @@ -702,14 +703,19 @@ ion-loading,prop,mode,"ios" | "md",undefined,false,false ion-loading,prop,showBackdrop,boolean,true,false,false ion-loading,prop,spinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-sharp" | "lines-sharp-small" | "lines-small" | null | undefined,undefined,false,false ion-loading,prop,translucent,boolean,false,false,false +ion-loading,prop,trigger,string | undefined,undefined,false,false ion-loading,method,dismiss,dismiss(data?: any, role?: string) => Promise ion-loading,method,onDidDismiss,onDidDismiss() => Promise> ion-loading,method,onWillDismiss,onWillDismiss() => Promise> ion-loading,method,present,present() => Promise +ion-loading,event,didDismiss,OverlayEventDetail,true +ion-loading,event,didPresent,void,true ion-loading,event,ionLoadingDidDismiss,OverlayEventDetail,true ion-loading,event,ionLoadingDidPresent,void,true ion-loading,event,ionLoadingWillDismiss,OverlayEventDetail,true ion-loading,event,ionLoadingWillPresent,void,true +ion-loading,event,willDismiss,OverlayEventDetail,true +ion-loading,event,willPresent,void,true ion-loading,css-prop,--backdrop-opacity ion-loading,css-prop,--background ion-loading,css-prop,--height diff --git a/core/src/components.d.ts b/core/src/components.d.ts index ff0cf3c212..32b65254ec 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -1385,6 +1385,7 @@ export namespace Components { * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. */ "cssClass"?: string | string[]; + "delegate"?: FrameworkDelegate; /** * Dismiss the loading overlay after it has been presented. * @param data Any data to emit in the dismiss events. @@ -1399,10 +1400,15 @@ export namespace Components { * Animation to use when the loading indicator is presented. */ "enterAnimation"?: AnimationBuilder; + "hasController": boolean; /** * Additional attributes to pass to the loader. */ "htmlAttributes"?: LoadingAttributes; + /** + * If `true`, the loading indicator will open. If `false`, the loading indicator will close. Use this if you need finer grained control over presentation, otherwise just use the loadingController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the loading indicator dismisses. You will need to do that in your code. + */ + "isOpen": boolean; /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ @@ -1444,6 +1450,10 @@ export namespace Components { * If `true`, the loading indicator will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). */ "translucent": boolean; + /** + * An ID corresponding to the trigger element that causes the loading indicator to open when clicked. + */ + "trigger": string | undefined; } interface IonMenu { /** @@ -5183,6 +5193,7 @@ declare namespace LocalJSX { * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. */ "cssClass"?: string | string[]; + "delegate"?: FrameworkDelegate; /** * Number of milliseconds to wait before dismissing the loading indicator. */ @@ -5191,10 +5202,15 @@ declare namespace LocalJSX { * Animation to use when the loading indicator is presented. */ "enterAnimation"?: AnimationBuilder; + "hasController"?: boolean; /** * Additional attributes to pass to the loader. */ "htmlAttributes"?: LoadingAttributes; + /** + * If `true`, the loading indicator will open. If `false`, the loading indicator will close. Use this if you need finer grained control over presentation, otherwise just use the loadingController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the loading indicator dismisses. You will need to do that in your code. + */ + "isOpen"?: boolean; /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ @@ -5211,6 +5227,14 @@ declare namespace LocalJSX { * The mode determines which platform styles to use. */ "mode"?: "ios" | "md"; + /** + * Emitted after the loading indicator has dismissed. Shorthand for ionLoadingDidDismiss. + */ + "onDidDismiss"?: (event: IonLoadingCustomEvent) => void; + /** + * Emitted after the loading indicator has presented. Shorthand for ionLoadingWillDismiss. + */ + "onDidPresent"?: (event: IonLoadingCustomEvent) => void; /** * Emitted after the loading has dismissed. */ @@ -5227,6 +5251,14 @@ declare namespace LocalJSX { * Emitted before the loading has presented. */ "onIonLoadingWillPresent"?: (event: IonLoadingCustomEvent) => void; + /** + * Emitted before the loading indicator has dismissed. Shorthand for ionLoadingWillDismiss. + */ + "onWillDismiss"?: (event: IonLoadingCustomEvent) => void; + /** + * Emitted before the loading indicator has presented. Shorthand for ionLoadingWillPresent. + */ + "onWillPresent"?: (event: IonLoadingCustomEvent) => void; "overlayIndex": number; /** * If `true`, a backdrop will be displayed behind the loading indicator. @@ -5240,6 +5272,10 @@ declare namespace LocalJSX { * If `true`, the loading indicator will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). */ "translucent"?: boolean; + /** + * An ID corresponding to the trigger element that causes the loading indicator to open when clicked. + */ + "trigger"?: string | undefined; } interface IonMenu { /** diff --git a/core/src/components/loading/loading.tsx b/core/src/components/loading/loading.tsx index a7c19affe1..65c70797f7 100644 --- a/core/src/components/loading/loading.tsx +++ b/core/src/components/loading/loading.tsx @@ -1,16 +1,26 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Component, Element, Event, Host, Method, Prop, h } from '@stencil/core'; +import { Watch, Component, Element, Event, Host, Method, Prop, h } from '@stencil/core'; import { config } from '../../global/config'; import { getIonMode } from '../../global/ionic-global'; import type { AnimationBuilder, + FrameworkDelegate, LoadingAttributes, OverlayEventDetail, OverlayInterface, SpinnerTypes, } from '../../interface'; -import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays'; +import { raf } from '../../utils/helpers'; +import { + BACKDROP, + dismiss, + eventMethod, + prepareOverlay, + present, + createDelegateController, + createTriggerController, +} from '../../utils/overlays'; import type { IonicSafeString } from '../../utils/sanitization'; import { sanitizeDOMString } from '../../utils/sanitization'; import { getClassMap } from '../../utils/theme'; @@ -32,7 +42,10 @@ import { mdLeaveAnimation } from './animations/md.leave'; scoped: true, }) export class Loading implements ComponentInterface, OverlayInterface { + private readonly delegateController = createDelegateController(this); + private readonly triggerController = createTriggerController(); private durationTimeout: any; + private currentTransition?: Promise; presented = false; lastFocus?: HTMLElement; @@ -42,6 +55,12 @@ export class Loading implements ComponentInterface, OverlayInterface { /** @internal */ @Prop() overlayIndex!: number; + /** @internal */ + @Prop() delegate?: FrameworkDelegate; + + /** @internal */ + @Prop() hasController = false; + /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ @@ -105,6 +124,36 @@ export class Loading implements ComponentInterface, OverlayInterface { */ @Prop() htmlAttributes?: LoadingAttributes; + /** + * If `true`, the loading indicator will open. If `false`, the loading indicator will close. + * Use this if you need finer grained control over presentation, otherwise + * just use the loadingController or the `trigger` property. + * Note: `isOpen` will not automatically be set back to `false` when + * the loading indicator dismisses. You will need to do that in your code. + */ + @Prop() isOpen = false; + @Watch('isOpen') + onIsOpenChange(newValue: boolean, oldValue: boolean) { + if (newValue === true && oldValue === false) { + this.present(); + } else if (newValue === false && oldValue === true) { + this.dismiss(); + } + } + + /** + * An ID corresponding to the trigger element that + * causes the loading indicator to open when clicked. + */ + @Prop() trigger: string | undefined; + @Watch('trigger') + triggerChanged() { + const { trigger, el, triggerController } = this; + if (trigger) { + triggerController.addClickListener(el, trigger); + } + } + /** * Emitted after the loading has presented. */ @@ -125,8 +174,33 @@ export class Loading implements ComponentInterface, OverlayInterface { */ @Event({ eventName: 'ionLoadingDidDismiss' }) didDismiss!: EventEmitter; + /** + * Emitted after the loading indicator has presented. + * Shorthand for ionLoadingWillDismiss. + */ + @Event({ eventName: 'didPresent' }) didPresentShorthand!: EventEmitter; + + /** + * Emitted before the loading indicator has presented. + * Shorthand for ionLoadingWillPresent. + */ + @Event({ eventName: 'willPresent' }) willPresentShorthand!: EventEmitter; + + /** + * Emitted before the loading indicator has dismissed. + * Shorthand for ionLoadingWillDismiss. + */ + @Event({ eventName: 'willDismiss' }) willDismissShorthand!: EventEmitter; + + /** + * Emitted after the loading indicator has dismissed. + * Shorthand for ionLoadingDidDismiss. + */ + @Event({ eventName: 'didDismiss' }) didDismissShorthand!: EventEmitter; + connectedCallback() { prepareOverlay(this.el); + this.triggerChanged(); } componentWillLoad() { @@ -136,16 +210,48 @@ export class Loading implements ComponentInterface, OverlayInterface { } } + componentDidLoad() { + /** + * If loading indicator was rendered with isOpen="true" + * then we should open loading indicator immediately. + */ + if (this.isOpen === true) { + raf(() => this.present()); + } + } + + disconnectedCallback() { + this.triggerController.removeClickListener(); + } + /** * Present the loading overlay after it has been created. */ @Method() async present(): Promise { - await present(this, 'loadingEnter', iosEnterAnimation, mdEnterAnimation, undefined); + /** + * When using an inline loading indicator + * and dismissing a loading indicator it is possible to + * quickly present the loading indicator while it is + * dismissing. We need to await any current + * transition to allow the dismiss to finish + * before presenting again. + */ + if (this.currentTransition !== undefined) { + await this.currentTransition; + } + + await this.delegateController.attachViewToDom(); + + this.currentTransition = present(this, 'loadingEnter', iosEnterAnimation, mdEnterAnimation); + + await this.currentTransition; if (this.duration > 0) { this.durationTimeout = setTimeout(() => this.dismiss(), this.duration + 10); } + + this.currentTransition = undefined; } /** @@ -158,11 +264,19 @@ export class Loading implements ComponentInterface, OverlayInterface { * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`. */ @Method() - dismiss(data?: any, role?: string): Promise { + async dismiss(data?: any, role?: string): Promise { if (this.durationTimeout) { clearTimeout(this.durationTimeout); } - return dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation, mdLeaveAnimation); + this.currentTransition = dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation, mdLeaveAnimation); + + const dismissed = await this.currentTransition; + + if (dismissed) { + this.delegateController.removeViewFromDom(); + } + + return dismissed; } /** diff --git a/core/src/components/loading/test/isOpen/index.html b/core/src/components/loading/test/isOpen/index.html new file mode 100644 index 0000000000..6c25f0c1c6 --- /dev/null +++ b/core/src/components/loading/test/isOpen/index.html @@ -0,0 +1,80 @@ + + + + + Loading - isOpen + + + + + + + + + + + + + Loading - isOpen + + + + +
+
+

Default

+ Open Loading +
+
+

Open, then close after 500ms

+ Open Loading +
+
+ + +
+
+ + + + diff --git a/core/src/components/loading/test/isOpen/loading.e2e.ts b/core/src/components/loading/test/isOpen/loading.e2e.ts new file mode 100644 index 0000000000..28de5420cd --- /dev/null +++ b/core/src/components/loading/test/isOpen/loading.e2e.ts @@ -0,0 +1,30 @@ +import { test } from '@utils/test/playwright'; + +test.describe('loading: isOpen', () => { + test.beforeEach(async ({ page, skip }) => { + skip.rtl('isOpen does not behave differently in RTL'); + skip.mode('md', 'isOpen does not behave differently in MD'); + await page.goto('/src/components/loading/test/isOpen'); + }); + + test('should open the loading indicator', async ({ page }) => { + const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent'); + await page.click('#default'); + + await ionLoadingDidPresent.next(); + await page.waitForSelector('ion-loading', { state: 'visible' }); + }); + + test('should open the loading indicator then close after a timeout', async ({ page }) => { + const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent'); + const ionLoadingDidDismiss = await page.spyOnEvent('ionLoadingDidDismiss'); + await page.click('#timeout'); + + await ionLoadingDidPresent.next(); + await page.waitForSelector('ion-loading', { state: 'visible' }); + + await ionLoadingDidDismiss.next(); + + await page.waitForSelector('ion-loading', { state: 'hidden' }); + }); +}); diff --git a/core/src/components/loading/test/trigger/index.html b/core/src/components/loading/test/trigger/index.html new file mode 100644 index 0000000000..e5655e6318 --- /dev/null +++ b/core/src/components/loading/test/trigger/index.html @@ -0,0 +1,71 @@ + + + + + Loading - trigger + + + + + + + + + + + + + Loading - trigger + + + + +
+
+

Default

+ Open Loading +
+
+

Open, then close after 500ms

+ Open Loading +
+
+ + + +
+
+ + + diff --git a/core/src/components/loading/test/trigger/loading.e2e.ts b/core/src/components/loading/test/trigger/loading.e2e.ts new file mode 100644 index 0000000000..2a09cf3722 --- /dev/null +++ b/core/src/components/loading/test/trigger/loading.e2e.ts @@ -0,0 +1,31 @@ +import { test } from '@utils/test/playwright'; + +test.describe('loading: trigger', () => { + test.beforeEach(async ({ page, skip }) => { + skip.rtl('trigger does not behave differently in RTL'); + skip.mode('md'); + await page.goto('/src/components/loading/test/trigger'); + }); + + test('should open the loading indicator', async ({ page }) => { + const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent'); + await page.click('#default'); + + await ionLoadingDidPresent.next(); + await page.waitForSelector('#default-loading', { state: 'visible' }); + }); + + test('should present a previously presented loading indicator', async ({ page }) => { + const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent'); + const ionLoadingDidDismiss = await page.spyOnEvent('ionLoadingDidDismiss'); + + await page.click('#timeout'); + + await ionLoadingDidDismiss.next(); + + await page.click('#timeout'); + + await ionLoadingDidPresent.next(); + await page.waitForSelector('#timeout-loading', { state: 'visible' }); + }); +}); diff --git a/core/src/utils/framework-delegate.ts b/core/src/utils/framework-delegate.ts index d3b6ff382c..2667708df6 100644 --- a/core/src/utils/framework-delegate.ts +++ b/core/src/utils/framework-delegate.ts @@ -53,6 +53,8 @@ export const CoreDelegate = () => { userComponentProps: any = {}, cssClasses: string[] = [] ) => { + const hasUserDefinedComponent = userComponent !== undefined; + BaseComponent = parentElement; /** * If passing in a component via the `component` props @@ -86,7 +88,7 @@ export const CoreDelegate = () => { BaseComponent.appendChild(el); await new Promise((resolve) => componentOnReady(el, resolve)); - } else if (BaseComponent.children.length > 0) { + } else if (hasUserDefinedComponent && BaseComponent.children.length > 0) { // If there is no component, then we need to create a new parent // element to apply the css classes to. const el = BaseComponent.ownerDocument?.createElement('div'); diff --git a/core/src/utils/overlays-interface.ts b/core/src/utils/overlays-interface.ts index 9ae79c95b4..3ff792077f 100644 --- a/core/src/utils/overlays-interface.ts +++ b/core/src/utils/overlays-interface.ts @@ -43,6 +43,7 @@ export interface HTMLIonOverlayElement extends HTMLStencilElement { lastFocus?: HTMLElement; dismiss(data?: any, role?: string): Promise; + present: () => Promise; } export type OverlaySelect = HTMLIonActionSheetElement | HTMLIonAlertElement | HTMLIonPopoverElement; diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index ed6cc722fb..813d5397b8 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -6,6 +6,7 @@ import type { Animation, AnimationBuilder, BackButtonEvent, + FrameworkDelegate, HTMLIonOverlayElement, IonicConfig, LoadingOptions, @@ -16,6 +17,7 @@ import type { ToastOptions, } from '../interface'; +import { CoreDelegate } from './framework-delegate'; import { OVERLAY_BACK_BUTTON_PRIORITY } from './hardware-back-button'; import { addEventListener, componentOnReady, focusElement, getElementRoot, removeEventListener } from './helpers'; @@ -612,3 +614,151 @@ export const safeCall = (handler: any, arg?: any) => { }; export const BACKDROP = 'backdrop'; + +/** + * Creates a delegate controller. + * + * Requires that the component has the following properties: + * - `el: HTMLElement` + * - `hasController: boolean` + * - `delegate?: FrameworkDelegate` + * + * @param ref The component class instance. + */ +export const createDelegateController = (ref: { + el: HTMLElement; + hasController: boolean; + delegate?: FrameworkDelegate; +}) => { + let inline = false; + let workingDelegate: FrameworkDelegate | undefined; + + const coreDelegate: FrameworkDelegate = CoreDelegate(); + + /** +<<<<<<< HEAD + * * Determines whether or not an overlay is being used +======= + * Determines whether or not an overlay is being used +>>>>>>> FW-2334 + * 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. + * @param force `true` to force the non-cached version of the delegate. + * @returns The delegate to use and whether or not the overlay is inline. + */ + const getDelegate = (force = false) => { + if (workingDelegate && !force) { + return { + delegate: workingDelegate, + inline, + }; + } + const { el, hasController, delegate } = ref; + /** + * If using overlay inline + * we potentially need to use the coreDelegate + * so that this works in vanilla JS apps. + * If a developer has presented this component + * via a controller, then we can assume + * the component is already in the + * correct place. + */ + const parentEl = el.parentNode as HTMLElement | null; + inline = parentEl !== null && !hasController; + workingDelegate = inline ? delegate || coreDelegate : delegate; + + return { inline, delegate: workingDelegate }; + }; + + /** + * Attaches a component in the DOM. Teleports the component + * to the root of the app. + * @param component The component to optionally construct and append to the element. + */ + const attachViewToDom = async (component?: any) => { + const { delegate } = getDelegate(true); + if (delegate) { + return await delegate.attachViewToDom(ref.el, component); + } + const { hasController } = ref; + if (hasController && component !== undefined) { + throw new Error('framework delegate is missing'); + } + return null; + }; + + /** + * Moves a component back to its original location in the DOM. + */ + const removeViewFromDom = () => { + const { delegate } = getDelegate(); + if (delegate && ref.el !== undefined) { + delegate.removeViewFromDom(ref.el.parentElement, ref.el); + } + }; + + return { + attachViewToDom, + removeViewFromDom, + }; +}; + +/** + * Constructs a trigger interaction for an overlay. + * Presents an overlay when the trigger is clicked. + * + * Usage: + * ```ts + * triggerController = createTriggerController(); + * triggerController.addClickListener(el, trigger); + * ``` + */ +export const createTriggerController = () => { + let destroyTriggerInteraction: (() => void) | undefined; + + /** + * Removes the click listener from the trigger element. + */ + const removeClickListener = (): void => { + if (destroyTriggerInteraction) { + destroyTriggerInteraction(); + destroyTriggerInteraction = undefined; + } + }; + + /** + * Adds a click listener to the trigger element. + * Presents the overlay when the trigger is clicked. + * @param el The overlay element. + * @param trigger The ID of the element to add a click listener to. + */ + const addClickListener = (el: HTMLIonOverlayElement, trigger: string): void => { + removeClickListener(); + + const triggerEl = trigger !== undefined ? document.getElementById(trigger) : null; + if (!triggerEl) { + return; + } + + const configureTriggerInteraction = (targetEl: HTMLElement, overlayEl: HTMLIonOverlayElement) => { + const openOverlay = () => { + overlayEl.present(); + }; + targetEl.addEventListener('click', openOverlay); + + return () => { + targetEl.removeEventListener('click', openOverlay); + }; + }; + + destroyTriggerInteraction = configureTriggerInteraction(triggerEl, el); + }; + + return { + addClickListener, + removeClickListener, + }; +}; diff --git a/packages/react/src/components/IonLoading.tsx b/packages/react/src/components/IonLoading.tsx index 11528b7346..eca9f168d0 100644 --- a/packages/react/src/components/IonLoading.tsx +++ b/packages/react/src/components/IonLoading.tsx @@ -1,9 +1,9 @@ -import { LoadingOptions, loadingController } from '@ionic/core/components'; +import { JSX } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-loading.js'; -import { createControllerComponent } from './createControllerComponent'; +import { createInlineOverlayComponent } from './createInlineOverlayComponent'; -export const IonLoading = /*@__PURE__*/ createControllerComponent< - LoadingOptions, +export const IonLoading = /*@__PURE__*/ createInlineOverlayComponent< + JSX.IonLoading, HTMLIonLoadingElement ->('ion-loading', loadingController, defineCustomElement); +>('ion-loading', defineCustomElement); \ No newline at end of file diff --git a/packages/react/test-app/tests/e2e/specs/overlay-components/IonLoading.cy.ts b/packages/react/test-app/tests/e2e/specs/overlay-components/IonLoading.cy.ts index 4bcbcb0bc6..76b19775d8 100644 --- a/packages/react/test-app/tests/e2e/specs/overlay-components/IonLoading.cy.ts +++ b/packages/react/test-app/tests/e2e/specs/overlay-components/IonLoading.cy.ts @@ -9,7 +9,7 @@ describe('IonLoading', () => { cy.get('ion-loading').contains('Loading'); //loading goes away after 1s - cy.get('ion-loading').should('not.exist'); + cy.get('ion-loading').should('not.be.visible'); }); it('display loading and call dismiss to close it', () => { @@ -17,7 +17,7 @@ describe('IonLoading', () => { cy.get('ion-button').contains('Show Loading, hide after 250 ms').click(); cy.get('ion-loading').contains('Loading'); - //verify loading is gone - cy.get('ion-loading').should('not.exist'); + //verify loading is hidden + cy.get('ion-loading').should('not.be.visible'); }); }); diff --git a/packages/vue/src/components/Overlays.ts b/packages/vue/src/components/Overlays.ts index c2646bfd72..ed5755900e 100644 --- a/packages/vue/src/components/Overlays.ts +++ b/packages/vue/src/components/Overlays.ts @@ -23,7 +23,7 @@ export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer('ion-alert', defineIonAlertCustomElement, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController); -export const IonLoading = /*@__PURE__*/ defineOverlayContainer('ion-loading', defineIonLoadingCustomElement, ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent'], loadingController); +export const IonLoading = /*@__PURE__*/ defineOverlayContainer('ion-loading', defineIonLoadingCustomElement, ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent', 'trigger'], loadingController); export const IonPicker = /*@__PURE__*/ defineOverlayContainer('ion-picker', defineIonPickerCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop'], pickerController);