@ionic/react
Version:
React specific wrapper for @ionic/core
1,003 lines (982 loc) • 112 kB
JavaScript
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
import React, { useContext, useRef, useEffect, createElement, useState, useMemo, Fragment as Fragment$1, useCallback } from 'react';
import { isPlatform as isPlatform$1, getPlatforms as getPlatforms$1, componentOnReady, createAnimation, actionSheetController, alertController, toastController, modalController, popoverController, pickerController, loadingController, initialize } from '@ionic/core/components';
export { IonicSafeString, IonicSlides, createAnimation, createGesture, getIonPageElement, getTimeGivenProgression, iosTransitionAnimation, mdTransitionAnimation, openURL } from '@ionic/core/components';
import ReactDOM, { createPortal } from 'react-dom';
import { defineCustomElement as defineCustomElement$1 } from '@ionic/core/components/ion-accordion.js';
import { defineCustomElement as defineCustomElement$2 } from '@ionic/core/components/ion-accordion-group.js';
import { defineCustomElement as defineCustomElement$3 } from '@ionic/core/components/ion-avatar.js';
import { defineCustomElement as defineCustomElement$4 } from '@ionic/core/components/ion-backdrop.js';
import { defineCustomElement as defineCustomElement$5 } from '@ionic/core/components/ion-badge.js';
import { defineCustomElement as defineCustomElement$6 } from '@ionic/core/components/ion-breadcrumbs.js';
import { defineCustomElement as defineCustomElement$7 } from '@ionic/core/components/ion-buttons.js';
import { defineCustomElement as defineCustomElement$8 } from '@ionic/core/components/ion-card-content.js';
import { defineCustomElement as defineCustomElement$9 } from '@ionic/core/components/ion-card-header.js';
import { defineCustomElement as defineCustomElement$a } from '@ionic/core/components/ion-card-subtitle.js';
import { defineCustomElement as defineCustomElement$b } from '@ionic/core/components/ion-card-title.js';
import { defineCustomElement as defineCustomElement$c } from '@ionic/core/components/ion-checkbox.js';
import { defineCustomElement as defineCustomElement$d } from '@ionic/core/components/ion-chip.js';
import { defineCustomElement as defineCustomElement$e } from '@ionic/core/components/ion-col.js';
import { defineCustomElement as defineCustomElement$f } from '@ionic/core/components/ion-content.js';
import { defineCustomElement as defineCustomElement$g } from '@ionic/core/components/ion-datetime.js';
import { defineCustomElement as defineCustomElement$h } from '@ionic/core/components/ion-datetime-button.js';
import { defineCustomElement as defineCustomElement$i } from '@ionic/core/components/ion-fab.js';
import { defineCustomElement as defineCustomElement$j } from '@ionic/core/components/ion-fab-list.js';
import { defineCustomElement as defineCustomElement$k } from '@ionic/core/components/ion-footer.js';
import { defineCustomElement as defineCustomElement$l } from '@ionic/core/components/ion-grid.js';
import { defineCustomElement as defineCustomElement$m } from '@ionic/core/components/ion-header.js';
import { defineCustomElement as defineCustomElement$n } from '@ionic/core/components/ion-img.js';
import { defineCustomElement as defineCustomElement$o } from '@ionic/core/components/ion-infinite-scroll.js';
import { defineCustomElement as defineCustomElement$p } from '@ionic/core/components/ion-infinite-scroll-content.js';
import { defineCustomElement as defineCustomElement$q } from '@ionic/core/components/ion-input.js';
import { defineCustomElement as defineCustomElement$r } from '@ionic/core/components/ion-input-otp.js';
import { defineCustomElement as defineCustomElement$s } from '@ionic/core/components/ion-input-password-toggle.js';
import { defineCustomElement as defineCustomElement$t } from '@ionic/core/components/ion-item-divider.js';
import { defineCustomElement as defineCustomElement$u } from '@ionic/core/components/ion-item-group.js';
import { defineCustomElement as defineCustomElement$v } from '@ionic/core/components/ion-item-options.js';
import { defineCustomElement as defineCustomElement$w } from '@ionic/core/components/ion-item-sliding.js';
import { defineCustomElement as defineCustomElement$x } from '@ionic/core/components/ion-label.js';
import { defineCustomElement as defineCustomElement$y } from '@ionic/core/components/ion-list.js';
import { defineCustomElement as defineCustomElement$z } from '@ionic/core/components/ion-list-header.js';
import { defineCustomElement as defineCustomElement$A } from '@ionic/core/components/ion-menu.js';
import { defineCustomElement as defineCustomElement$B } from '@ionic/core/components/ion-menu-button.js';
import { defineCustomElement as defineCustomElement$C } from '@ionic/core/components/ion-menu-toggle.js';
import { defineCustomElement as defineCustomElement$1m } from '@ionic/core/components/ion-nav.js';
import { defineCustomElement as defineCustomElement$D } from '@ionic/core/components/ion-nav-link.js';
import { defineCustomElement as defineCustomElement$E } from '@ionic/core/components/ion-note.js';
import { defineCustomElement as defineCustomElement$F } from '@ionic/core/components/ion-picker.js';
import { defineCustomElement as defineCustomElement$G } from '@ionic/core/components/ion-picker-column.js';
import { defineCustomElement as defineCustomElement$H } from '@ionic/core/components/ion-picker-column-option.js';
import { defineCustomElement as defineCustomElement$I } from '@ionic/core/components/ion-progress-bar.js';
import { defineCustomElement as defineCustomElement$J } from '@ionic/core/components/ion-radio.js';
import { defineCustomElement as defineCustomElement$K } from '@ionic/core/components/ion-radio-group.js';
import { defineCustomElement as defineCustomElement$L } from '@ionic/core/components/ion-range.js';
import { defineCustomElement as defineCustomElement$M } from '@ionic/core/components/ion-refresher.js';
import { defineCustomElement as defineCustomElement$N } from '@ionic/core/components/ion-refresher-content.js';
import { defineCustomElement as defineCustomElement$O } from '@ionic/core/components/ion-reorder.js';
import { defineCustomElement as defineCustomElement$P } from '@ionic/core/components/ion-reorder-group.js';
import { defineCustomElement as defineCustomElement$Q } from '@ionic/core/components/ion-ripple-effect.js';
import { defineCustomElement as defineCustomElement$R } from '@ionic/core/components/ion-row.js';
import { defineCustomElement as defineCustomElement$S } from '@ionic/core/components/ion-searchbar.js';
import { defineCustomElement as defineCustomElement$T } from '@ionic/core/components/ion-segment.js';
import { defineCustomElement as defineCustomElement$U } from '@ionic/core/components/ion-segment-button.js';
import { defineCustomElement as defineCustomElement$V } from '@ionic/core/components/ion-segment-content.js';
import { defineCustomElement as defineCustomElement$W } from '@ionic/core/components/ion-segment-view.js';
import { defineCustomElement as defineCustomElement$X } from '@ionic/core/components/ion-select.js';
import { defineCustomElement as defineCustomElement$Y } from '@ionic/core/components/ion-select-modal.js';
import { defineCustomElement as defineCustomElement$Z } from '@ionic/core/components/ion-select-option.js';
import { defineCustomElement as defineCustomElement$_ } from '@ionic/core/components/ion-skeleton-text.js';
import { defineCustomElement as defineCustomElement$$ } from '@ionic/core/components/ion-spinner.js';
import { defineCustomElement as defineCustomElement$10 } from '@ionic/core/components/ion-split-pane.js';
import { defineCustomElement as defineCustomElement$11 } from '@ionic/core/components/ion-tab.js';
import { defineCustomElement as defineCustomElement$12 } from '@ionic/core/components/ion-text.js';
import { defineCustomElement as defineCustomElement$13 } from '@ionic/core/components/ion-textarea.js';
import { defineCustomElement as defineCustomElement$14 } from '@ionic/core/components/ion-thumbnail.js';
import { defineCustomElement as defineCustomElement$15 } from '@ionic/core/components/ion-title.js';
import { defineCustomElement as defineCustomElement$16 } from '@ionic/core/components/ion-toggle.js';
import { defineCustomElement as defineCustomElement$17 } from '@ionic/core/components/ion-toolbar.js';
import { IonBreadcrumb as IonBreadcrumb$1 } from '@ionic/core/components/ion-breadcrumb.js';
import { IonButton as IonButton$1 } from '@ionic/core/components/ion-button.js';
import { IonCard as IonCard$1 } from '@ionic/core/components/ion-card.js';
import { IonFabButton as IonFabButton$1 } from '@ionic/core/components/ion-fab-button.js';
import { IonItemOption as IonItemOption$1 } from '@ionic/core/components/ion-item-option.js';
import { IonItem as IonItem$1 } from '@ionic/core/components/ion-item.js';
import { IonRouterLink as IonRouterLink$1 } from '@ionic/core/components/ion-router-link.js';
import { defineCustomElement as defineCustomElement$18 } from '@ionic/core/components/ion-alert.js';
import { defineCustomElement as defineCustomElement$19 } from '@ionic/core/components/ion-loading.js';
import { defineCustomElement as defineCustomElement$1a } from '@ionic/core/components/ion-toast.js';
import { defineCustomElement as defineCustomElement$1b } from '@ionic/core/components/ion-picker-legacy.js';
import { defineCustomElement as defineCustomElement$1c } from '@ionic/core/components/ion-action-sheet.js';
import { defineCustomElement as defineCustomElement$1d } from '@ionic/core/components/ion-modal.js';
import { defineCustomElement as defineCustomElement$1e } from '@ionic/core/components/ion-popover.js';
import { defineCustomElement as defineCustomElement$1k } from '@ionic/core/components/ion-app.js';
import { defineCustomElement as defineCustomElement$1i } from '@ionic/core/components/ion-back-button.js';
import { defineCustomElement as defineCustomElement$1j } from '@ionic/core/components/ion-router-outlet.js';
import { defineCustomElement as defineCustomElement$1g } from '@ionic/core/components/ion-tab-bar.js';
import { defineCustomElement as defineCustomElement$1f } from '@ionic/core/components/ion-tab-button.js';
import { defineCustomElement as defineCustomElement$1h } from '@ionic/core/components/ion-tabs.js';
import { defineCustomElement as defineCustomElement$1l } from 'ionicons/components/ion-icon.js';
const IonLifeCycleContext = /*@__PURE__*/ React.createContext({
onIonViewWillEnter: () => {
return;
},
ionViewWillEnter: () => {
return;
},
onIonViewDidEnter: () => {
return;
},
ionViewDidEnter: () => {
return;
},
onIonViewWillLeave: () => {
return;
},
ionViewWillLeave: () => {
return;
},
onIonViewDidLeave: () => {
return;
},
ionViewDidLeave: () => {
return;
},
cleanupIonViewWillEnter: () => {
return;
},
cleanupIonViewDidEnter: () => {
return;
},
cleanupIonViewWillLeave: () => {
return;
},
cleanupIonViewDidLeave: () => {
return;
},
});
const DefaultIonLifeCycleContext = class {
constructor() {
this.ionViewWillEnterCallbacks = [];
this.ionViewDidEnterCallbacks = [];
this.ionViewWillLeaveCallbacks = [];
this.ionViewDidLeaveCallbacks = [];
this.ionViewWillEnterDestructorCallbacks = [];
this.ionViewDidEnterDestructorCallbacks = [];
this.ionViewWillLeaveDestructorCallbacks = [];
this.ionViewDidLeaveDestructorCallbacks = [];
}
onIonViewWillEnter(callback) {
if (callback.id) {
const index = this.ionViewWillEnterCallbacks.findIndex((x) => x.id === callback.id);
if (index > -1) {
this.ionViewWillEnterCallbacks[index] = callback;
}
else {
this.ionViewWillEnterCallbacks.push(callback);
}
}
else {
this.ionViewWillEnterCallbacks.push(callback);
}
}
teardownCallback(callback, callbacks) {
// Find any destructors that have been registered for the callback
const matches = callbacks.filter((x) => x.id === callback.id);
if (matches.length !== 0) {
// Execute the destructor for each matching item
matches.forEach((match) => {
if (match && typeof match.destructor === 'function') {
match.destructor();
}
});
// Remove all matching items from the array
callbacks = callbacks.filter((x) => x.id !== callback.id);
}
}
/**
* Tears down the user-provided ionViewWillEnter lifecycle callback.
* This is the same behavior as React's useEffect hook. The callback
* is invoked when the component is unmounted.
*/
cleanupIonViewWillEnter(callback) {
this.teardownCallback(callback, this.ionViewWillEnterDestructorCallbacks);
}
/**
* Tears down the user-provided ionViewDidEnter lifecycle callback.
* This is the same behavior as React's useEffect hook. The callback
* is invoked when the component is unmounted.
*/
cleanupIonViewDidEnter(callback) {
this.teardownCallback(callback, this.ionViewDidEnterDestructorCallbacks);
}
/**
* Tears down the user-provided ionViewWillLeave lifecycle callback.
* This is the same behavior as React's useEffect hook. The callback
* is invoked when the component is unmounted.
*/
cleanupIonViewWillLeave(callback) {
this.teardownCallback(callback, this.ionViewWillLeaveDestructorCallbacks);
}
/**
* Tears down the user-provided ionViewDidLeave lifecycle callback.
* This is the same behavior as React's useEffect hook. The callback
* is invoked when the component is unmounted.
*/
cleanupIonViewDidLeave(callback) {
this.teardownCallback(callback, this.ionViewDidLeaveDestructorCallbacks);
}
ionViewWillEnter() {
this.ionViewWillEnterCallbacks.forEach((cb) => {
const destructor = cb();
if (cb.id) {
this.ionViewWillEnterDestructorCallbacks.push({ id: cb.id, destructor });
}
});
}
onIonViewDidEnter(callback) {
if (callback.id) {
const index = this.ionViewDidEnterCallbacks.findIndex((x) => x.id === callback.id);
if (index > -1) {
this.ionViewDidEnterCallbacks[index] = callback;
}
else {
this.ionViewDidEnterCallbacks.push(callback);
}
}
else {
this.ionViewDidEnterCallbacks.push(callback);
}
}
ionViewDidEnter() {
this.ionViewDidEnterCallbacks.forEach((cb) => {
const destructor = cb();
if (cb.id) {
this.ionViewDidEnterDestructorCallbacks.push({ id: cb.id, destructor });
}
});
}
onIonViewWillLeave(callback) {
if (callback.id) {
const index = this.ionViewWillLeaveCallbacks.findIndex((x) => x.id === callback.id);
if (index > -1) {
this.ionViewWillLeaveCallbacks[index] = callback;
}
else {
this.ionViewWillLeaveCallbacks.push(callback);
}
}
else {
this.ionViewWillLeaveCallbacks.push(callback);
}
}
ionViewWillLeave() {
this.ionViewWillLeaveCallbacks.forEach((cb) => {
const destructor = cb();
if (cb.id) {
this.ionViewWillLeaveDestructorCallbacks.push({ id: cb.id, destructor });
}
});
}
onIonViewDidLeave(callback) {
if (callback.id) {
const index = this.ionViewDidLeaveCallbacks.findIndex((x) => x.id === callback.id);
if (index > -1) {
this.ionViewDidLeaveCallbacks[index] = callback;
}
else {
this.ionViewDidLeaveCallbacks.push(callback);
}
}
else {
this.ionViewDidLeaveCallbacks.push(callback);
}
}
ionViewDidLeave() {
this.ionViewDidLeaveCallbacks.forEach((cb) => {
const destructor = cb();
if (cb.id) {
this.ionViewDidLeaveDestructorCallbacks.push({ id: cb.id, destructor });
}
});
this.componentCanBeDestroyed();
}
onComponentCanBeDestroyed(callback) {
this.componentCanBeDestroyedCallback = callback;
}
componentCanBeDestroyed() {
if (this.componentCanBeDestroyedCallback) {
this.componentCanBeDestroyedCallback();
}
}
};
// TODO(FW-2959): types
const withIonLifeCycle = (WrappedComponent) => {
return class IonLifeCycle extends React.Component {
constructor(props) {
super(props);
this.componentRef = React.createRef();
}
componentDidMount() {
const element = this.componentRef.current;
this.context.onIonViewWillEnter(() => {
if (element && element.ionViewWillEnter) {
element.ionViewWillEnter();
}
});
this.context.onIonViewDidEnter(() => {
if (element && element.ionViewDidEnter) {
element.ionViewDidEnter();
}
});
this.context.onIonViewWillLeave(() => {
if (element && element.ionViewWillLeave) {
element.ionViewWillLeave();
}
});
this.context.onIonViewDidLeave(() => {
if (element && element.ionViewDidLeave) {
element.ionViewDidLeave();
}
});
}
render() {
return (jsx(IonLifeCycleContext.Consumer, { children: (context) => {
this.context = context;
return jsx(WrappedComponent, { ref: this.componentRef, ...this.props });
} }));
}
};
};
const useIonViewWillEnter = (callback, deps = []) => {
const context = useContext(IonLifeCycleContext);
const id = useRef();
id.current = id.current || Math.floor(Math.random() * 1000000);
useEffect(() => {
callback.id = id.current;
context.onIonViewWillEnter(callback);
return () => {
context.cleanupIonViewWillEnter(callback);
};
}, deps);
};
const useIonViewDidEnter = (callback, deps = []) => {
const context = useContext(IonLifeCycleContext);
const id = useRef();
id.current = id.current || Math.floor(Math.random() * 1000000);
useEffect(() => {
callback.id = id.current;
context.onIonViewDidEnter(callback);
return () => {
context.cleanupIonViewDidEnter(callback);
};
}, deps);
};
const useIonViewWillLeave = (callback, deps = []) => {
const context = useContext(IonLifeCycleContext);
const id = useRef();
id.current = id.current || Math.floor(Math.random() * 1000000);
useEffect(() => {
callback.id = id.current;
context.onIonViewWillLeave(callback);
return () => {
context.cleanupIonViewWillLeave(callback);
};
}, deps);
};
const useIonViewDidLeave = (callback, deps = []) => {
const context = useContext(IonLifeCycleContext);
const id = useRef();
id.current = id.current || Math.floor(Math.random() * 1000000);
useEffect(() => {
callback.id = id.current;
context.onIonViewDidLeave(callback);
return () => {
context.cleanupIonViewDidLeave(callback);
};
}, deps);
};
const NavContext = /*@__PURE__*/ React.createContext({
getIonRedirect: () => undefined,
getIonRoute: () => undefined,
getPageManager: () => undefined,
getStackManager: () => undefined,
goBack: (route) => {
if (typeof window !== 'undefined') {
if (typeof route === 'string') {
window.location.pathname = route;
}
else {
window.history.back();
}
}
},
navigate: (path) => {
if (typeof window !== 'undefined') {
window.location.pathname = path;
}
},
hasIonicRouter: () => false,
routeInfo: undefined,
setCurrentTab: () => undefined,
changeTab: (_tab, path) => {
if (typeof window !== 'undefined') {
window.location.pathname = path;
}
},
resetTab: (_tab, path) => {
if (typeof window !== 'undefined') {
window.location.pathname = path;
}
},
});
const dashToPascalCase = (str) => str
.toLowerCase()
.split('-')
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
.join('');
const camelToDashCase = (str) => str.replace(/([A-Z])/g, (m) => `-${m[0].toLowerCase()}`);
const attachProps = (node, newProps, oldProps = {}) => {
// some test frameworks don't render DOM elements, so we test here to make sure we are dealing with DOM first
if (node instanceof Element) {
// add any classes in className to the class list
const className = getClassName(node.classList, newProps, oldProps);
if (className !== '') {
node.className = className;
}
Object.keys(newProps).forEach((name) => {
if (name === 'children' ||
name === 'style' ||
name === 'ref' ||
name === 'class' ||
name === 'className' ||
name === 'forwardedRef') {
return;
}
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2);
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
if (!isCoveredByReact(eventNameLc)) {
syncEvent(node, eventNameLc, newProps[name]);
}
}
else {
node[name] = newProps[name];
const propType = typeof newProps[name];
if (propType === 'string') {
node.setAttribute(camelToDashCase(name), newProps[name]);
}
}
});
}
};
const getClassName = (classList, newProps, oldProps) => {
const newClassProp = newProps.className || newProps.class;
const oldClassProp = oldProps.className || oldProps.class;
// map the classes to Maps for performance
const currentClasses = arrayToMap(classList);
const incomingPropClasses = arrayToMap(newClassProp ? newClassProp.split(' ') : []);
const oldPropClasses = arrayToMap(oldClassProp ? oldClassProp.split(' ') : []);
const finalClassNames = [];
// loop through each of the current classes on the component
// to see if it should be a part of the classNames added
currentClasses.forEach((currentClass) => {
if (incomingPropClasses.has(currentClass)) {
// add it as its already included in classnames coming in from newProps
finalClassNames.push(currentClass);
incomingPropClasses.delete(currentClass);
}
else if (!oldPropClasses.has(currentClass)) {
// add it as it has NOT been removed by user
finalClassNames.push(currentClass);
}
});
incomingPropClasses.forEach((s) => finalClassNames.push(s));
return finalClassNames.join(' ');
};
/**
* Transforms a React event name to a browser event name.
*/
const transformReactEventName = (eventNameSuffix) => {
switch (eventNameSuffix) {
case 'doubleclick':
return 'dblclick';
}
return eventNameSuffix;
};
/**
* Checks if an event is supported in the current execution environment.
* @license Modernizr 3.0.0pre (Custom Build) | MIT
*/
const isCoveredByReact = (eventNameSuffix) => {
if (typeof document === 'undefined') {
return true;
}
else {
const eventName = 'on' + transformReactEventName(eventNameSuffix);
let isSupported = eventName in document;
if (!isSupported) {
const element = document.createElement('div');
element.setAttribute(eventName, 'return;');
isSupported = typeof element[eventName] === 'function';
}
return isSupported;
}
};
const syncEvent = (node, eventName, newEventHandler) => {
const eventStore = node.__events || (node.__events = {});
const oldEventHandler = eventStore[eventName];
// Remove old listener so they don't double up.
if (oldEventHandler) {
node.removeEventListener(eventName, oldEventHandler);
}
// Bind new listener.
node.addEventListener(eventName, (eventStore[eventName] = function handler(e) {
if (newEventHandler) {
newEventHandler.call(this, e);
}
}));
};
const arrayToMap = (arr) => {
const map = new Map();
arr.forEach((s) => map.set(s, s));
return map;
};
const setRef = (ref, value) => {
if (typeof ref === 'function') {
ref(value);
}
else if (ref != null) {
// Cast as a MutableRef so we can assign current
ref.current = value;
}
};
const mergeRefs = (...refs) => {
return (value) => {
refs.forEach((ref) => {
setRef(ref, value);
});
};
};
const createForwardRef$1 = (ReactComponent, displayName) => {
const forwardRef = (props, ref) => {
return jsx(ReactComponent, { ...props, forwardedRef: ref });
};
forwardRef.displayName = displayName;
return React.forwardRef(forwardRef);
};
const defineCustomElement = (tagName, customElement) => {
if (customElement !== undefined && typeof customElements !== 'undefined' && !customElements.get(tagName)) {
customElements.define(tagName, customElement);
}
};
const createReactComponent = (tagName, ReactComponentContext, manipulatePropsFunction, defineCustomElement) => {
if (defineCustomElement !== undefined) {
defineCustomElement();
}
const displayName = dashToPascalCase(tagName);
const ReactComponent = class extends React.Component {
constructor(props) {
super(props);
this.setComponentElRef = (element) => {
this.componentEl = element;
};
}
componentDidMount() {
this.componentDidUpdate(this.props);
}
componentDidUpdate(prevProps) {
attachProps(this.componentEl, this.props, prevProps);
}
render() {
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
let propsToPass = Object.keys(cProps).reduce((acc, name) => {
const value = cProps[name];
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2).toLowerCase();
if (typeof document !== 'undefined' && isCoveredByReact(eventName)) {
acc[name] = value;
}
}
else {
// we should only render strings, booleans, and numbers as attrs in html.
// objects, functions, arrays etc get synced via properties on mount.
const type = typeof value;
if (type === 'string' || type === 'boolean' || type === 'number') {
acc[camelToDashCase(name)] = value;
}
}
return acc;
}, {});
if (manipulatePropsFunction) {
propsToPass = manipulatePropsFunction(this.props, propsToPass);
}
const newProps = {
...propsToPass,
ref: mergeRefs(forwardedRef, this.setComponentElRef),
style,
};
/**
* We use createElement here instead of
* React.createElement to work around a
* bug in Vite (https://github.com/vitejs/vite/issues/6104).
* React.createElement causes all elements to be rendered
* as <tagname> instead of the actual Web Component.
*/
return createElement(tagName, newProps, children);
}
static get displayName() {
return displayName;
}
};
// If context was passed to createReactComponent then conditionally add it to the Component Class
if (ReactComponentContext) {
ReactComponent.contextType = ReactComponentContext;
}
return createForwardRef$1(ReactComponent, displayName);
};
/* eslint-disable */
/* tslint:disable */
/* auto-generated react proxies */
const IonAccordion = /*@__PURE__*/ createReactComponent('ion-accordion', undefined, undefined, defineCustomElement$1);
const IonAccordionGroup = /*@__PURE__*/ createReactComponent('ion-accordion-group', undefined, undefined, defineCustomElement$2);
const IonAvatar = /*@__PURE__*/ createReactComponent('ion-avatar', undefined, undefined, defineCustomElement$3);
const IonBackdrop = /*@__PURE__*/ createReactComponent('ion-backdrop', undefined, undefined, defineCustomElement$4);
const IonBadge = /*@__PURE__*/ createReactComponent('ion-badge', undefined, undefined, defineCustomElement$5);
const IonBreadcrumbs = /*@__PURE__*/ createReactComponent('ion-breadcrumbs', undefined, undefined, defineCustomElement$6);
const IonButtons = /*@__PURE__*/ createReactComponent('ion-buttons', undefined, undefined, defineCustomElement$7);
const IonCardContent = /*@__PURE__*/ createReactComponent('ion-card-content', undefined, undefined, defineCustomElement$8);
const IonCardHeader = /*@__PURE__*/ createReactComponent('ion-card-header', undefined, undefined, defineCustomElement$9);
const IonCardSubtitle = /*@__PURE__*/ createReactComponent('ion-card-subtitle', undefined, undefined, defineCustomElement$a);
const IonCardTitle = /*@__PURE__*/ createReactComponent('ion-card-title', undefined, undefined, defineCustomElement$b);
const IonCheckbox = /*@__PURE__*/ createReactComponent('ion-checkbox', undefined, undefined, defineCustomElement$c);
const IonChip = /*@__PURE__*/ createReactComponent('ion-chip', undefined, undefined, defineCustomElement$d);
const IonCol = /*@__PURE__*/ createReactComponent('ion-col', undefined, undefined, defineCustomElement$e);
const IonContent = /*@__PURE__*/ createReactComponent('ion-content', undefined, undefined, defineCustomElement$f);
const IonDatetime = /*@__PURE__*/ createReactComponent('ion-datetime', undefined, undefined, defineCustomElement$g);
const IonDatetimeButton = /*@__PURE__*/ createReactComponent('ion-datetime-button', undefined, undefined, defineCustomElement$h);
const IonFab = /*@__PURE__*/ createReactComponent('ion-fab', undefined, undefined, defineCustomElement$i);
const IonFabList = /*@__PURE__*/ createReactComponent('ion-fab-list', undefined, undefined, defineCustomElement$j);
const IonFooter = /*@__PURE__*/ createReactComponent('ion-footer', undefined, undefined, defineCustomElement$k);
const IonGrid = /*@__PURE__*/ createReactComponent('ion-grid', undefined, undefined, defineCustomElement$l);
const IonHeader = /*@__PURE__*/ createReactComponent('ion-header', undefined, undefined, defineCustomElement$m);
const IonImg = /*@__PURE__*/ createReactComponent('ion-img', undefined, undefined, defineCustomElement$n);
const IonInfiniteScroll = /*@__PURE__*/ createReactComponent('ion-infinite-scroll', undefined, undefined, defineCustomElement$o);
const IonInfiniteScrollContent = /*@__PURE__*/ createReactComponent('ion-infinite-scroll-content', undefined, undefined, defineCustomElement$p);
const IonInput = /*@__PURE__*/ createReactComponent('ion-input', undefined, undefined, defineCustomElement$q);
const IonInputOtp = /*@__PURE__*/ createReactComponent('ion-input-otp', undefined, undefined, defineCustomElement$r);
const IonInputPasswordToggle = /*@__PURE__*/ createReactComponent('ion-input-password-toggle', undefined, undefined, defineCustomElement$s);
const IonItemDivider = /*@__PURE__*/ createReactComponent('ion-item-divider', undefined, undefined, defineCustomElement$t);
const IonItemGroup = /*@__PURE__*/ createReactComponent('ion-item-group', undefined, undefined, defineCustomElement$u);
const IonItemOptions = /*@__PURE__*/ createReactComponent('ion-item-options', undefined, undefined, defineCustomElement$v);
const IonItemSliding = /*@__PURE__*/ createReactComponent('ion-item-sliding', undefined, undefined, defineCustomElement$w);
const IonLabel = /*@__PURE__*/ createReactComponent('ion-label', undefined, undefined, defineCustomElement$x);
const IonList = /*@__PURE__*/ createReactComponent('ion-list', undefined, undefined, defineCustomElement$y);
const IonListHeader = /*@__PURE__*/ createReactComponent('ion-list-header', undefined, undefined, defineCustomElement$z);
const IonMenu = /*@__PURE__*/ createReactComponent('ion-menu', undefined, undefined, defineCustomElement$A);
const IonMenuButton = /*@__PURE__*/ createReactComponent('ion-menu-button', undefined, undefined, defineCustomElement$B);
const IonMenuToggle = /*@__PURE__*/ createReactComponent('ion-menu-toggle', undefined, undefined, defineCustomElement$C);
const IonNavLink = /*@__PURE__*/ createReactComponent('ion-nav-link', undefined, undefined, defineCustomElement$D);
const IonNote = /*@__PURE__*/ createReactComponent('ion-note', undefined, undefined, defineCustomElement$E);
const IonPicker = /*@__PURE__*/ createReactComponent('ion-picker', undefined, undefined, defineCustomElement$F);
const IonPickerColumn = /*@__PURE__*/ createReactComponent('ion-picker-column', undefined, undefined, defineCustomElement$G);
const IonPickerColumnOption = /*@__PURE__*/ createReactComponent('ion-picker-column-option', undefined, undefined, defineCustomElement$H);
const IonProgressBar = /*@__PURE__*/ createReactComponent('ion-progress-bar', undefined, undefined, defineCustomElement$I);
const IonRadio = /*@__PURE__*/ createReactComponent('ion-radio', undefined, undefined, defineCustomElement$J);
const IonRadioGroup = /*@__PURE__*/ createReactComponent('ion-radio-group', undefined, undefined, defineCustomElement$K);
const IonRange = /*@__PURE__*/ createReactComponent('ion-range', undefined, undefined, defineCustomElement$L);
const IonRefresher = /*@__PURE__*/ createReactComponent('ion-refresher', undefined, undefined, defineCustomElement$M);
const IonRefresherContent = /*@__PURE__*/ createReactComponent('ion-refresher-content', undefined, undefined, defineCustomElement$N);
const IonReorder = /*@__PURE__*/ createReactComponent('ion-reorder', undefined, undefined, defineCustomElement$O);
const IonReorderGroup = /*@__PURE__*/ createReactComponent('ion-reorder-group', undefined, undefined, defineCustomElement$P);
const IonRippleEffect = /*@__PURE__*/ createReactComponent('ion-ripple-effect', undefined, undefined, defineCustomElement$Q);
const IonRow = /*@__PURE__*/ createReactComponent('ion-row', undefined, undefined, defineCustomElement$R);
const IonSearchbar = /*@__PURE__*/ createReactComponent('ion-searchbar', undefined, undefined, defineCustomElement$S);
const IonSegment = /*@__PURE__*/ createReactComponent('ion-segment', undefined, undefined, defineCustomElement$T);
const IonSegmentButton = /*@__PURE__*/ createReactComponent('ion-segment-button', undefined, undefined, defineCustomElement$U);
const IonSegmentContent = /*@__PURE__*/ createReactComponent('ion-segment-content', undefined, undefined, defineCustomElement$V);
const IonSegmentView = /*@__PURE__*/ createReactComponent('ion-segment-view', undefined, undefined, defineCustomElement$W);
const IonSelect = /*@__PURE__*/ createReactComponent('ion-select', undefined, undefined, defineCustomElement$X);
const IonSelectModal = /*@__PURE__*/ createReactComponent('ion-select-modal', undefined, undefined, defineCustomElement$Y);
const IonSelectOption = /*@__PURE__*/ createReactComponent('ion-select-option', undefined, undefined, defineCustomElement$Z);
const IonSkeletonText = /*@__PURE__*/ createReactComponent('ion-skeleton-text', undefined, undefined, defineCustomElement$_);
const IonSpinner = /*@__PURE__*/ createReactComponent('ion-spinner', undefined, undefined, defineCustomElement$$);
const IonSplitPane = /*@__PURE__*/ createReactComponent('ion-split-pane', undefined, undefined, defineCustomElement$10);
const IonTab = /*@__PURE__*/ createReactComponent('ion-tab', undefined, undefined, defineCustomElement$11);
const IonText = /*@__PURE__*/ createReactComponent('ion-text', undefined, undefined, defineCustomElement$12);
const IonTextarea = /*@__PURE__*/ createReactComponent('ion-textarea', undefined, undefined, defineCustomElement$13);
const IonThumbnail = /*@__PURE__*/ createReactComponent('ion-thumbnail', undefined, undefined, defineCustomElement$14);
const IonTitle = /*@__PURE__*/ createReactComponent('ion-title', undefined, undefined, defineCustomElement$15);
const IonToggle = /*@__PURE__*/ createReactComponent('ion-toggle', undefined, undefined, defineCustomElement$16);
const IonToolbar = /*@__PURE__*/ createReactComponent('ion-toolbar', undefined, undefined, defineCustomElement$17);
const createForwardRef = (ReactComponent, // TODO(FW-2959): type
displayName) => {
const forwardRef = (props, ref) => {
return jsx(ReactComponent, { ...props, forwardedRef: ref });
};
forwardRef.displayName = displayName;
return React.forwardRef(forwardRef);
};
const isPlatform = (platform) => {
return isPlatform$1(window, platform);
};
const getPlatforms = () => {
return getPlatforms$1(window);
};
const getConfig = () => {
if (typeof window !== 'undefined') {
const Ionic = window.Ionic;
if (Ionic && Ionic.config) {
return Ionic.config;
}
}
return null;
};
const createRoutingComponent = (tagName, customElement) => {
defineCustomElement(tagName, customElement);
const displayName = dashToPascalCase(tagName);
const ReactComponent = class extends React.Component {
constructor(props) {
super(props);
this.handleClick = (e) => {
const { routerLink, routerDirection, routerOptions, routerAnimation } = this.props;
if (routerLink !== undefined) {
e.preventDefault();
this.context.navigate(routerLink, routerDirection, undefined, routerAnimation, routerOptions);
}
};
// Create a local ref to to attach props to the wrapped element.
this.ref = React.createRef();
// React refs must be stable (not created inline).
this.stableMergedRefs = mergeRefs(this.ref, this.props.forwardedRef);
}
componentDidMount() {
this.componentDidUpdate(this.props);
}
componentDidUpdate(prevProps) {
const node = this.ref.current;
attachProps(node, this.props, prevProps);
}
render() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
const propsToPass = Object.keys(cProps).reduce((acc, name) => {
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2).toLowerCase();
if (isCoveredByReact(eventName)) {
acc[name] = cProps[name];
}
}
else if (['string', 'boolean', 'number'].includes(typeof cProps[name])) {
acc[camelToDashCase(name)] = cProps[name];
}
return acc;
}, {});
const newProps = {
...propsToPass,
ref: this.stableMergedRefs,
style,
};
if (this.props.routerLink && !this.props.href) {
newProps.href = this.props.routerLink;
}
if (newProps.onClick) {
const oldClick = newProps.onClick;
newProps.onClick = (e) => {
oldClick(e);
if (!e.defaultPrevented) {
this.handleClick(e);
}
};
}
else {
newProps.onClick = this.handleClick;
}
return createElement(tagName, newProps, children);
}
static get displayName() {
return displayName;
}
static get contextType() {
return NavContext;
}
};
return createForwardRef(ReactComponent, displayName);
};
const IonRouterLink = /*@__PURE__*/ createRoutingComponent('ion-router-link', IonRouterLink$1);
const IonButton = /*@__PURE__*/ createRoutingComponent('ion-button', IonButton$1);
const IonCard = /*@__PURE__*/ createRoutingComponent('ion-card', IonCard$1);
const IonFabButton = /*@__PURE__*/ createRoutingComponent('ion-fab-button', IonFabButton$1);
const IonItem = /*@__PURE__*/ createRoutingComponent('ion-item', IonItem$1);
const IonItemOption = /*@__PURE__*/ createRoutingComponent('ion-item-option', IonItemOption$1);
const IonBreadcrumb = /*@__PURE__*/ createRoutingComponent('ion-breadcrumb', IonBreadcrumb$1);
/**
* The @stencil/react-output-target will bind event listeners for any
* attached props that use the `on` prefix. This function will remove
* those event listeners when the component is unmounted.
*
* This prevents memory leaks and React state updates on unmounted components.
*/
const detachProps = (node, props) => {
if (node instanceof Element) {
Object.keys(props).forEach((name) => {
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2);
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
if (!isCoveredByReact(eventNameLc)) {
/**
* Detach custom event bindings (not built-in React events)
* that were added by the @stencil/react-output-target attachProps function.
*/
detachEvent(node, eventNameLc);
}
}
});
}
};
const detachEvent = (node, eventName) => {
const eventStore = node.__events || (node.__events = {});
/**
* If the event listener was added by attachProps, it will
* be stored in the __events object.
*/
const eventHandler = eventStore[eventName];
if (eventHandler) {
node.removeEventListener(eventName, eventHandler);
eventStore[eventName] = undefined;
}
};
const createInlineOverlayComponent = (tagName, defineCustomElement, hasDelegateHost) => {
if (defineCustomElement) {
defineCustomElement();
}
const displayName = dashToPascalCase(tagName);
const ReactComponent = class extends React.Component {
constructor(props) {
super(props);
this.handleIonMount = () => {
/**
* 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.setState({ isOpen: true });
};
this.handleWillPresent = (evt) => {
this.setState({ isOpen: true });
/**
* Manually call the onWillPresent
* handler if present as setState will
* cause the event handlers to be
* destroyed and re-created.
*/
this.props.onWillPresent && this.props.onWillPresent(evt);
};
this.handleDidDismiss = (evt) => {
const wrapper = this.wrapperRef.current;
const el = this.ref.current;
/**
* This component might be unmounted already, if the containing
* element was removed while the overlay was still open. (For
* example, if an item contains an inline overlay with a button
* that removes the item.)
*/
if (wrapper && el) {
el.append(wrapper);
this.setState({ isOpen: false });
}
this.props.onDidDismiss && this.props.onDidDismiss(evt);
};
// Create a local ref to to attach props to the wrapped element.
this.ref = React.createRef();
// React refs must be stable (not created inline).
this.stableMergedRefs = mergeRefs(this.ref, this.props.forwardedRef);
// Component is hidden by default
this.state = { isOpen: false };
// Create a local ref to the inner child element.
this.wrapperRef = React.createRef();
}
componentDidMount() {
this.componentDidUpdate(this.props);
this.ref.current?.addEventListener('ionMount', this.handleIonMount);
this.ref.current?.addEventListener('willPresent', this.handleWillPresent);
this.ref.current?.addEventListener('didDismiss', this.handleDidDismiss);
}
componentDidUpdate(prevProps) {
const node = this.ref.current;
/**
* onDidDismiss and onWillPresent have manual implementations that
* will invoke the original handler. We need to filter those out
* so they don't get attached twice and called twice.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { onDidDismiss, onWillPresent, ...cProps } = this.props;
attachProps(node, cProps, prevProps);
}
componentWillUnmount() {
const node = this.ref.current;
/**
* If the overlay is being unmounted, but is still
* open, this means the unmount was triggered outside
* of the overlay being dismissed.
*
* This can happen with:
* - The parent component being unmounted
* - The overlay being conditionally rendered
* - A route change (push/pop/replace)
*
* Unmounting the overlay at this stage should skip
* the dismiss lifecycle, including skipping the transition.
*
*/
if (node && this.state.isOpen) {
/**
* Detach the local event listener that performs the state updates,
* before dismissing the overlay, to prevent the callback handlers
* executing after the component has been unmounted. This is to
* avoid memory leaks.
*/
node.removeEventListener('didDismiss', this.handleDidDismiss);
node.remove();
detachProps(node, this.props);
}
}
render() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
const propsToPass = Object.keys(cProps).reduce((acc, name) => {
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2).toLowerCase();
if (isCoveredByReact(eventName)) {
acc[name] = cProps[name];
}
}
else if (['string', 'boolean', 'number'].includes(typeof cProps[name])) {
acc[camelToDashCase(name)] = cProps[name];
}
return acc;
}, {});
const newProps = {
...propsToPass,
ref: this.stableMergedRefs,
style,
};
/**
* Some overlays need `.ion-page` so content
* takes up the full size of the parent overlay.
*/
const getWrapperClasses = () => {
if (hasDelegateHost) {
return `${DELEGATE_HOST} ion-page`;
}
return DELEGATE_HOST;
};
return createElement('template', {}, createElement(tagName, newProps,
/**
* We only want the inner component
* to be mounted if the overlay is open,
* so conditionally render the component
* based on the isOpen state.
*/
this.state.isOpen || this.props.keepContentsMounted
? createElement('div', {
ref: this.wrapperRef,
className: getWrapperClasses(),
}, children)
: null));
}
static get displayName() {
return displayName;
}
};
return createForwardRef(ReactComponent, displayName);
};
const DELEGATE_HOST = 'ion-delegate-host';
const IonAlert = /*@__PURE__*/ createInlineOverlayComponent('ion-alert', defineCustomElement$18);
const IonLoading = /*@__PURE__*/ createInlineOverlayComponent('ion-loading', defineCustomElement$19);
const IonToast = /*@__PURE__*/ createInlineOverlayComponent('ion-toast', defineCustomElement$1a);
const IonPickerLegacy = /*@__PURE__*/ createInlineOverlayComponent('ion-picker-legacy', defineCustomElement$1b);
const IonActionSheet = /*@__PURE__*/ createInlineOverlayComponent('ion-action-sheet', defineCustomElement$1c);
const IonModal = /*@__PURE__*/ createInlineOverlayComponent('ion-modal', defineCustomElement$1d, true);
const IonPopover