diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index bfbf81575a..c8ac471231 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -59,27 +59,29 @@ export const prepareOverlay = (el: T) => { } }; -export const createOverlay = (tagName: string, opts: object | undefined, customElement?: any, childrenCustomElements?: ChildCustomElementDefinition[]): Promise => { - /* tslint:disable-next-line */ - if (typeof window.customElements !== 'undefined') { - if (typeof (window as any) !== 'undefined' && window.customElements) { - if (!window.customElements.get(tagName)) { - window.customElements.define(tagName, customElement); - } - /** - * If the parent element has nested usage of custom elements, - * we need to manually define those custom elements. - */ - if (childrenCustomElements) { - for (const customElementDefinition of childrenCustomElements) { - if (!window.customElements.get(customElementDefinition.tagName)) { - window.customElements.define(customElementDefinition.tagName, customElementDefinition.customElement); - } - } +const registerOverlayComponents = (tagName: string, customElement: any, childrenCustomElements?: ChildCustomElementDefinition[]): Promise => { + const { customElements } = window; + if (!customElements.get(tagName)) { + customElements.define(tagName, customElement); + } + /** + * If the parent element has nested usage of custom elements, + * we need to manually define those custom elements. + */ + if (childrenCustomElements) { + for (const customElementDefinition of childrenCustomElements) { + if (!customElements.get(customElementDefinition.tagName)) { + customElements.define(customElementDefinition.tagName, customElementDefinition.customElement); } } + } + return customElements.whenDefined(tagName); +} - return window.customElements.whenDefined(tagName).then(() => { +export const createOverlay = (tagName: string, opts: object | undefined, customElement?: any, childrenCustomElements?: ChildCustomElementDefinition[]): Promise => { + /* tslint:disable-next-line */ + if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') { + return registerOverlayComponents(tagName, customElement, childrenCustomElements).then(() => { const element = document.createElement(tagName) as HTMLIonOverlayElement; element.classList.add('overlay-hidden'); diff --git a/packages/react/src/components/IonActionSheet.tsx b/packages/react/src/components/IonActionSheet.tsx index 95f62f43ee..0446a8e42f 100644 --- a/packages/react/src/components/IonActionSheet.tsx +++ b/packages/react/src/components/IonActionSheet.tsx @@ -3,17 +3,17 @@ import { ActionSheetOptions as ActionSheetOptionsCore, actionSheetController as actionSheetControllerCore, } from '@ionic/core/components'; -import { IonActionSheet as IonActionSheetCmp } from '@ionic/core/components/ion-action-sheet.js'; +import { defineCustomElement } from '@ionic/core/components/ion-action-sheet.js'; import { createOverlayComponent } from './createOverlayComponent'; export interface ActionSheetButton extends Omit { icon?: - | { - ios: string; - md: string; - } - | string; + | { + ios: string; + md: string; + } + | string; } export interface ActionSheetOptions extends Omit { @@ -30,4 +30,4 @@ const actionSheetController = { export const IonActionSheet = /*@__PURE__*/ createOverlayComponent< ActionSheetOptions, HTMLIonActionSheetElement ->('ion-action-sheet', actionSheetController, IonActionSheetCmp); +>('ion-action-sheet', actionSheetController, defineCustomElement); diff --git a/packages/react/src/components/IonModal.tsx b/packages/react/src/components/IonModal.tsx index 027bdd0b77..cab83e4275 100644 --- a/packages/react/src/components/IonModal.tsx +++ b/packages/react/src/components/IonModal.tsx @@ -1,9 +1,9 @@ import { JSX } from '@ionic/core/components'; -import { IonModal as IonModalCmp } from '@ionic/core/components/ion-modal.js'; +import { defineCustomElement } from '@ionic/core/components/ion-modal.js'; import { createInlineOverlayComponent } from './createInlineOverlayComponent' export const IonModal = /*@__PURE__*/ createInlineOverlayComponent< JSX.IonModal, HTMLIonModalElement ->('ion-modal', IonModalCmp); +>('ion-modal', defineCustomElement); diff --git a/packages/react/src/components/IonPopover.tsx b/packages/react/src/components/IonPopover.tsx index c2e443eff9..77df4d3d56 100644 --- a/packages/react/src/components/IonPopover.tsx +++ b/packages/react/src/components/IonPopover.tsx @@ -1,9 +1,9 @@ import { JSX } from '@ionic/core/components'; -import { IonPopover as IonPopoverCmp } from '@ionic/core/components/ion-popover.js'; +import { defineCustomElement } from '@ionic/core/components/ion-popover.js'; import { createInlineOverlayComponent } from './createInlineOverlayComponent' export const IonPopover = /*@__PURE__*/ createInlineOverlayComponent< JSX.IonPopover, HTMLIonPopoverElement ->('ion-popover', IonPopoverCmp); +>('ion-popover', defineCustomElement); diff --git a/packages/react/src/components/createInlineOverlayComponent.tsx b/packages/react/src/components/createInlineOverlayComponent.tsx index 1a7f179761..3d4dab1fef 100644 --- a/packages/react/src/components/createInlineOverlayComponent.tsx +++ b/packages/react/src/components/createInlineOverlayComponent.tsx @@ -5,7 +5,6 @@ import { attachProps, camelToDashCase, dashToPascalCase, - defineCustomElement, isCoveredByReact, mergeRefs, } from './react-component-lib/utils'; @@ -26,10 +25,11 @@ interface IonicReactInternalProps extends React.HTMLAttributes( tagName: string, - customElement?: any + defineCustomElement?: () => void ) => { - defineCustomElement(tagName, customElement); - + if (defineCustomElement) { + defineCustomElement(); + } const displayName = dashToPascalCase(tagName); const ReactComponent = class extends React.Component, InlineOverlayState> { ref: React.RefObject; diff --git a/packages/react/src/components/createOverlayComponent.tsx b/packages/react/src/components/createOverlayComponent.tsx index afb3f5e55d..71a19e0abd 100644 --- a/packages/react/src/components/createOverlayComponent.tsx +++ b/packages/react/src/components/createOverlayComponent.tsx @@ -2,7 +2,7 @@ import { OverlayEventDetail } from '@ionic/core/components'; import React from 'react'; import ReactDOM from 'react-dom'; -import { attachProps, dashToPascalCase, defineCustomElement, setRef } from './react-component-lib/utils'; +import { attachProps, dashToPascalCase, setRef } from './react-component-lib/utils'; interface OverlayElement extends HTMLElement { present: () => Promise; @@ -24,9 +24,11 @@ export const createOverlayComponent = < >( tagName: string, controller: { create: (options: any) => Promise }, - customElement?: any + defineCustomElement?: () => void ) => { - defineCustomElement(tagName, customElement); + if (defineCustomElement !== undefined) { + defineCustomElement(); + } const displayName = dashToPascalCase(tagName); const didDismissEventName = `on${displayName}DidDismiss`; diff --git a/packages/vue/scripts/copy-overlays.js b/packages/vue/scripts/copy-overlays.js index 7450eb5d15..5c756f69f0 100644 --- a/packages/vue/scripts/copy-overlays.js +++ b/packages/vue/scripts/copy-overlays.js @@ -46,7 +46,9 @@ function generateOverlays() { const docsBlock = getDocsBlock(component.tag); const props = getPropsFromDocsBlock(docsBlock); - componentImports.push(`import { ${component.name} as ${component.name}Cmp } from '@ionic/core/components/${component.tag}.js'`); + const defineCustomElementFn = `define${component.name}CustomElement`; + + componentImports.push(`import { defineCustomElement as ${defineCustomElementFn} } from '@ionic/core/components/${component.tag}.js'`); if (component.controller) { controllerImports.push(component.controller); @@ -55,7 +57,7 @@ function generateOverlays() { const controllerParam = (component.controller) ? `, ${component.controller}` : ''; componentDefinitions.push(` -export const ${component.name} = /*@__PURE__*/ defineOverlayContainer('${component.tag}', ${component.name}Cmp, [${props.join(', ')}]${controllerParam}); +export const ${component.name} = /*@__PURE__*/ defineOverlayContainer('${component.tag}', ${defineCustomElementFn}, [${props.join(', ')}]${controllerParam}); `); }); diff --git a/packages/vue/src/components/Overlays.ts b/packages/vue/src/components/Overlays.ts index fb53336881..5fa5fdd98e 100644 --- a/packages/vue/src/components/Overlays.ts +++ b/packages/vue/src/components/Overlays.ts @@ -9,27 +9,27 @@ import { toastController, } from '@ionic/core/components'; -import { IonActionSheet as IonActionSheetCmp } from '@ionic/core/components/ion-action-sheet.js' -import { IonAlert as IonAlertCmp } from '@ionic/core/components/ion-alert.js' -import { IonLoading as IonLoadingCmp } from '@ionic/core/components/ion-loading.js' -import { IonPicker as IonPickerCmp } from '@ionic/core/components/ion-picker.js' -import { IonToast as IonToastCmp } from '@ionic/core/components/ion-toast.js' -import { IonModal as IonModalCmp } from '@ionic/core/components/ion-modal.js' -import { IonPopover as IonPopoverCmp } from '@ionic/core/components/ion-popover.js' +import { defineCustomElement as defineIonActionSheetCustomElement } from '@ionic/core/components/ion-action-sheet.js' +import { defineCustomElement as defineIonAlertCustomElement } from '@ionic/core/components/ion-alert.js' +import { defineCustomElement as defineIonLoadingCustomElement } from '@ionic/core/components/ion-loading.js' +import { defineCustomElement as defineIonPickerCustomElement } from '@ionic/core/components/ion-picker.js' +import { defineCustomElement as defineIonToastCustomElement } from '@ionic/core/components/ion-toast.js' +import { defineCustomElement as defineIonModalCustomElement } from '@ionic/core/components/ion-modal.js' +import { defineCustomElement as defineIonPopoverCustomElement } from '@ionic/core/components/ion-popover.js' import { defineOverlayContainer } from '../vue-component-lib/overlays'; -export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer('ion-action-sheet', IonActionSheetCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent'], actionSheetController); +export const IonActionSheet = /*@__PURE__*/ defineOverlayContainer('ion-action-sheet', defineIonActionSheetCustomElement, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent'], actionSheetController); -export const IonAlert = /*@__PURE__*/ defineOverlayContainer('ion-alert', IonAlertCmp, ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController); +export const IonAlert = /*@__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', IonLoadingCmp, ['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', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent'], loadingController); -export const IonPicker = /*@__PURE__*/ defineOverlayContainer('ion-picker', IonPickerCmp, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop'], pickerController); +export const IonPicker = /*@__PURE__*/ defineOverlayContainer('ion-picker', defineIonPickerCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop'], pickerController); -export const IonToast = /*@__PURE__*/ defineOverlayContainer('ion-toast', IonToastCmp, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController); +export const IonToast = /*@__PURE__*/ defineOverlayContainer('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController); -export const IonModal = /*@__PURE__*/ defineOverlayContainer('ion-modal', IonModalCmp, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'enterAnimation', 'handle', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'swipeToClose', 'trigger']); +export const IonModal = /*@__PURE__*/ defineOverlayContainer('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'enterAnimation', 'handle', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'swipeToClose', 'trigger']); -export const IonPopover = /*@__PURE__*/ defineOverlayContainer('ion-popover', IonPopoverCmp, ['alignment', 'animated', 'arrow', 'backdropDismiss', 'component', 'componentProps', 'dismissOnSelect', 'enterAnimation', 'event', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'reference', 'showBackdrop', 'side', 'size', 'translucent', 'trigger', 'triggerAction']); +export const IonPopover = /*@__PURE__*/ defineOverlayContainer('ion-popover', defineIonPopoverCustomElement, ['alignment', 'animated', 'arrow', 'backdropDismiss', 'component', 'componentProps', 'dismissOnSelect', 'enterAnimation', 'event', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'reference', 'showBackdrop', 'side', 'size', 'translucent', 'trigger', 'triggerAction']); diff --git a/packages/vue/src/vue-component-lib/overlays.ts b/packages/vue/src/vue-component-lib/overlays.ts index 3faf3a3e63..a59e72d7b5 100644 --- a/packages/vue/src/vue-component-lib/overlays.ts +++ b/packages/vue/src/vue-component-lib/overlays.ts @@ -1,5 +1,4 @@ import { defineComponent, h, ref, VNode, onMounted } from 'vue'; -import { defineCustomElement } from '../utils'; export interface OverlayProps { isOpen?: boolean; @@ -8,7 +7,7 @@ export interface OverlayProps { const EMPTY_PROP = Symbol(); const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP }; -export const defineOverlayContainer = (name: string, customElement: any, componentProps: string[] = [], controller?: any) => { +export const defineOverlayContainer = (name: string, defineCustomElement: () => void, componentProps: string[] = [], controller?: any) => { const createControllerComponent = () => { return defineComponent((props, { slots, emit }) => { @@ -19,7 +18,9 @@ export const defineOverlayContainer = (name: string, custo { componentEv: `${name}-did-dismiss`, frameworkEv: 'didDismiss' }, ]; - defineCustomElement(name, customElement); + if (defineCustomElement !== undefined) { + defineCustomElement(); + } const overlay = ref(); const onVnodeMounted = async () => { @@ -131,7 +132,9 @@ export const defineOverlayContainer = (name: string, custo }; const createInlineComponent = () => { return defineComponent((props, { slots }) => { - defineCustomElement(name, customElement); + if (defineCustomElement !== undefined) { + defineCustomElement(); + } const isOpen = ref(false); const elementRef = ref();