chore(react): adding prettier and formating files

This commit is contained in:
Ely Lucas
2020-12-07 09:31:33 -07:00
committed by GitHub
parent 01afdc42e5
commit 91aaaab71a
163 changed files with 3205 additions and 2535 deletions

View File

@@ -1,8 +1,23 @@
import { Animation, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, createAnimation } from '@ionic/core';
import {
Animation,
AnimationCallbackOptions,
AnimationDirection,
AnimationFill,
AnimationKeyFrames,
AnimationLifecycle,
createAnimation,
} from '@ionic/core';
import React from 'react';
interface PartialPropertyValue { property: string; value: any; }
interface PropertyValue { property: string; fromValue: any; toValue: any; }
interface PartialPropertyValue {
property: string;
value: any;
}
interface PropertyValue {
property: string;
fromValue: any;
toValue: any;
}
export interface CreateAnimationProps {
delay?: number;
@@ -27,7 +42,7 @@ export interface CreateAnimationProps {
beforeAddClass?: string | string[];
beforeRemoveClass?: string | string[];
onFinish?: { callback: AnimationLifecycle; opts?: AnimationCallbackOptions; };
onFinish?: { callback: AnimationLifecycle; opts?: AnimationCallbackOptions };
keyframes?: AnimationKeyFrames;
from?: PartialPropertyValue[] | PartialPropertyValue;
@@ -39,9 +54,9 @@ export interface CreateAnimationProps {
stop?: boolean;
destroy?: boolean;
progressStart?: { forceLinearEasing: boolean, step?: number };
progressStart?: { forceLinearEasing: boolean; step?: number };
progressStep?: { step: number };
progressEnd?: { playTo: 0 | 1 | undefined, step: number, dur?: number };
progressEnd?: { playTo: 0 | 1 | undefined; step: number; dur?: number };
}
export class CreateAnimation extends React.PureComponent<CreateAnimationProps> {
@@ -84,14 +99,29 @@ export class CreateAnimation extends React.PureComponent<CreateAnimationProps> {
const { children } = this.props;
return (
<>
{React.Children.map(children, ((child, id) => React.cloneElement(child as any, { ref: (el: any) => this.nodes.set(id, el) })))}
{React.Children.map(children, (child, id) =>
React.cloneElement(child as any, { ref: (el: any) => this.nodes.set(id, el) })
)}
</>
);
}
}
const checkConfig = (animation: Animation, currentProps: any = {}, prevProps: any = {}) => {
const reservedProps = ['children', 'progressStart', 'progressStep', 'progressEnd', 'pause', 'stop', 'destroy', 'play', 'from', 'to', 'fromTo', 'onFinish'];
const reservedProps = [
'children',
'progressStart',
'progressStep',
'progressEnd',
'pause',
'stop',
'destroy',
'play',
'from',
'to',
'fromTo',
'onFinish',
];
for (const key in currentProps) {
if (
currentProps.hasOwnProperty(key) &&
@@ -104,33 +134,37 @@ const checkConfig = (animation: Animation, currentProps: any = {}, prevProps: an
const fromValues = currentProps.from;
if (fromValues && fromValues !== prevProps.from) {
const values = (Array.isArray(fromValues)) ? fromValues : [fromValues];
values.forEach(val => animation.from(val.property, val.value));
const values = Array.isArray(fromValues) ? fromValues : [fromValues];
values.forEach((val) => animation.from(val.property, val.value));
}
const toValues = currentProps.to;
if (toValues && toValues !== prevProps.to) {
const values = (Array.isArray(toValues)) ? toValues : [toValues];
values.forEach(val => animation.to(val.property, val.value));
const values = Array.isArray(toValues) ? toValues : [toValues];
values.forEach((val) => animation.to(val.property, val.value));
}
const fromToValues = currentProps.fromTo;
if (fromToValues && fromToValues !== prevProps.fromTo) {
const values = (Array.isArray(fromToValues)) ? fromToValues : [fromToValues];
values.forEach(val => animation.fromTo(val.property, val.fromValue, val.toValue));
const values = Array.isArray(fromToValues) ? fromToValues : [fromToValues];
values.forEach((val) => animation.fromTo(val.property, val.fromValue, val.toValue));
}
const onFinishValues = currentProps.onFinish;
if (onFinishValues && onFinishValues !== prevProps.onFinish) {
const values = (Array.isArray(onFinishValues)) ? onFinishValues : [onFinishValues];
values.forEach(val => animation.onFinish(val.callback, val.opts));
const values = Array.isArray(onFinishValues) ? onFinishValues : [onFinishValues];
values.forEach((val) => animation.onFinish(val.callback, val.opts));
}
};
const checkProgress = (animation: Animation, currentProps: any = {}, prevProps: any = {}) => {
const { progressStart, progressStep, progressEnd } = currentProps;
if (progressStart && (prevProps.progressStart?.forceLinearEasing !== progressStart?.forceLinearEasing || prevProps.progressStart?.step !== progressStart?.step)) {
if (
progressStart &&
(prevProps.progressStart?.forceLinearEasing !== progressStart?.forceLinearEasing ||
prevProps.progressStart?.step !== progressStart?.step)
) {
animation.progressStart(progressStart.forceLinearEasing, progressStart.step);
}
@@ -138,7 +172,12 @@ const checkProgress = (animation: Animation, currentProps: any = {}, prevProps:
animation.progressStep(progressStep.step);
}
if (progressEnd && (prevProps.progressEnd?.playTo !== progressEnd?.playTo || prevProps.progressEnd?.step !== progressEnd?.step || prevProps?.dur !== progressEnd?.dur)) {
if (
progressEnd &&
(prevProps.progressEnd?.playTo !== progressEnd?.playTo ||
prevProps.progressEnd?.step !== progressEnd?.step ||
prevProps?.dur !== progressEnd?.dur)
) {
animation.progressEnd(progressEnd.playTo, progressEnd.step, progressEnd.dur);
}
};

View File

@@ -1,12 +1,18 @@
import { ActionSheetButton as ActionSheetButtonCore, ActionSheetOptions as ActionSheetOptionsCore, actionSheetController as actionSheetControllerCore } from '@ionic/core';
import {
ActionSheetButton as ActionSheetButtonCore,
ActionSheetOptions as ActionSheetOptionsCore,
actionSheetController as actionSheetControllerCore,
} from '@ionic/core';
import { createOverlayComponent } from './createOverlayComponent';
export interface ActionSheetButton extends Omit<ActionSheetButtonCore, 'icon'> {
icon?: {
ios: string;
md: string;
} | string;
icon?:
| {
ios: string;
md: string;
}
| string;
}
export interface ActionSheetOptions extends Omit<ActionSheetOptionsCore, 'buttons'> {
@@ -15,8 +21,12 @@ export interface ActionSheetOptions extends Omit<ActionSheetOptionsCore, 'button
const actionSheetController = {
create: (options: ActionSheetOptions) => actionSheetControllerCore.create(options as any),
dismiss: (data?: any, role?: string | undefined, id?: string | undefined) => actionSheetControllerCore.dismiss(data, role, id),
getTop: () => actionSheetControllerCore.getTop()
dismiss: (data?: any, role?: string | undefined, id?: string | undefined) =>
actionSheetControllerCore.dismiss(data, role, id),
getTop: () => actionSheetControllerCore.getTop(),
};
export const IonActionSheet = /*@__PURE__*/createOverlayComponent<ActionSheetOptions, HTMLIonActionSheetElement>('IonActionSheet', actionSheetController);
export const IonActionSheet = /*@__PURE__*/ createOverlayComponent<
ActionSheetOptions,
HTMLIonActionSheetElement
>('IonActionSheet', actionSheetController);

View File

@@ -2,4 +2,7 @@ import { AlertOptions, alertController } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
export const IonAlert = /*@__PURE__*/createControllerComponent<AlertOptions, HTMLIonAlertElement>('IonAlert', alertController);
export const IonAlert = /*@__PURE__*/ createControllerComponent<AlertOptions, HTMLIonAlertElement>(
'IonAlert',
alertController
);

View File

@@ -26,11 +26,13 @@ type InternalProps = IonIconProps & {
};
class IonIconContainer extends React.PureComponent<InternalProps> {
constructor(props: InternalProps) {
super(props);
if (this.props.name) {
deprecationWarning('icon-name', 'In Ionic React, you import icons from "ionicons/icons" and set the icon you imported to the "icon" property. Setting the "name" property has no effect.');
deprecationWarning(
'icon-name',
'In Ionic React, you import icons from "ionicons/icons" and set the icon you imported to the "icon" property. Setting the "name" property has no effect.'
);
}
}
@@ -61,4 +63,7 @@ class IonIconContainer extends React.PureComponent<InternalProps> {
}
}
export const IonIcon = createForwardRef<IonIconProps & IonicReactProps, HTMLIonIconElement>(IonIconContainer, 'IonIcon');
export const IonIcon = createForwardRef<IonIconProps & IonicReactProps, HTMLIonIconElement>(
IonIconContainer,
'IonIcon'
);

View File

@@ -2,4 +2,7 @@ import { LoadingOptions, loadingController } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
export const IonLoading = /*@__PURE__*/createControllerComponent<LoadingOptions, HTMLIonLoadingElement>('IonLoading', loadingController);
export const IonLoading = /*@__PURE__*/ createControllerComponent<
LoadingOptions,
HTMLIonLoadingElement
>('IonLoading', loadingController);

View File

@@ -6,4 +6,7 @@ export type ReactModalOptions = Omit<ModalOptions, 'component' | 'componentProps
children: React.ReactNode;
};
export const IonModal = /*@__PURE__*/createOverlayComponent<ReactModalOptions, HTMLIonModalElement>('IonModal', modalController);
export const IonModal = /*@__PURE__*/ createOverlayComponent<
ReactModalOptions,
HTMLIonModalElement
>('IonModal', modalController);

View File

@@ -6,8 +6,7 @@ import PageManager from '../routing/PageManager';
import { IonicReactProps } from './IonicReactProps';
import { createForwardRef } from './utils';
interface IonPageProps extends IonicReactProps {
}
interface IonPageProps extends IonicReactProps {}
interface IonPageInternalProps extends IonPageProps {
forwardedRef?: React.RefObject<HTMLDivElement>;
@@ -23,21 +22,23 @@ class IonPageInternal extends React.Component<IonPageInternalProps> {
render() {
const { className, children, forwardedRef, ...props } = this.props;
return (
this.context.hasIonicRouter() ? (
<PageManager
className={className ? `${className}` : ''}
routeInfo={this.context.routeInfo}
forwardedRef={forwardedRef}
{...props}
>
{children}
</PageManager>
) : (
<div className={className ? `ion-page ${className}` : 'ion-page'} ref={forwardedRef} {...props}>
{children}
</div>
)
return this.context.hasIonicRouter() ? (
<PageManager
className={className ? `${className}` : ''}
routeInfo={this.context.routeInfo}
forwardedRef={forwardedRef}
{...props}
>
{children}
</PageManager>
) : (
<div
className={className ? `ion-page ${className}` : 'ion-page'}
ref={forwardedRef}
{...props}
>
{children}
</div>
);
}

View File

@@ -2,4 +2,7 @@ import { PickerOptions, pickerController } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
export const IonPicker = /*@__PURE__*/createControllerComponent<PickerOptions, HTMLIonPickerElement>('IonPicker', pickerController);
export const IonPicker = /*@__PURE__*/ createControllerComponent<
PickerOptions,
HTMLIonPickerElement
>('IonPicker', pickerController);

View File

@@ -6,4 +6,7 @@ export type ReactPopoverOptions = Omit<PopoverOptions, 'component' | 'componentP
children: React.ReactNode;
};
export const IonPopover = /*@__PURE__*/createOverlayComponent<ReactPopoverOptions, HTMLIonPopoverElement>('IonPopover', popoverController);
export const IonPopover = /*@__PURE__*/ createOverlayComponent<
ReactPopoverOptions,
HTMLIonPopoverElement
>('IonPopover', popoverController);

View File

@@ -9,30 +9,25 @@ export interface IonRedirectProps {
routerOptions?: unknown;
}
interface IonRedirectState {
}
interface IonRedirectState {}
export class IonRedirect extends React.PureComponent<IonRedirectProps, IonRedirectState> {
context!: React.ContextType<typeof NavContext>;
render() {
const IonRedirectInner = this.context.getIonRedirect();
if (!this.context.hasIonicRouter() || !IonRedirect) {
console.error('You either do not have an Ionic Router package, or your router does not support using <IonRedirect>');
console.error(
'You either do not have an Ionic Router package, or your router does not support using <IonRedirect>'
);
return null;
}
return (
<IonRedirectInner {...this.props} />
);
return <IonRedirectInner {...this.props} />;
}
static get contextType() {
return NavContext;
}
}

View File

@@ -10,30 +10,25 @@ export interface IonRouteProps {
disableIonPageManagement?: boolean;
}
interface IonRouteState {
}
interface IonRouteState {}
export class IonRoute extends React.PureComponent<IonRouteProps, IonRouteState> {
context!: React.ContextType<typeof NavContext>;
render() {
const IonRouteInner = this.context.getIonRoute();
if (!this.context.hasIonicRouter() || !IonRoute) {
console.error('You either do not have an Ionic Router package, or your router does not support using <IonRoute>');
console.error(
'You either do not have an Ionic Router package, or your router does not support using <IonRoute>'
);
return null;
}
return (
<IonRouteInner {...this.props} />
);
return <IonRouteInner {...this.props} />;
}
static get contextType() {
return NavContext;
}
}

View File

@@ -6,7 +6,13 @@ import { RouteInfo } from '../models/RouteInfo';
export interface IonRouterContextState {
routeInfo: RouteInfo;
push: (pathname: string, routerDirection?: RouterDirection, routeAction?: RouteAction, routerOptions?: RouterOptions, animationBuilder?: AnimationBuilder) => void;
push: (
pathname: string,
routerDirection?: RouterDirection,
routeAction?: RouteAction,
routerOptions?: RouterOptions,
animationBuilder?: AnimationBuilder
) => void;
back: (animationBuilder?: AnimationBuilder) => void;
canGoBack: () => boolean;
nativeBack: () => void;
@@ -14,10 +20,18 @@ export interface IonRouterContextState {
export const IonRouterContext = React.createContext<IonRouterContextState>({
routeInfo: undefined as any,
push: () => { throw new Error('An Ionic Router is required for IonRouterContext'); },
back: () => { throw new Error('An Ionic Router is required for IonRouterContext'); },
canGoBack: () => { throw new Error('An Ionic Router is required for IonRouterContext'); },
nativeBack: () => { throw new Error('An Ionic Router is required for IonRouterContext'); }
push: () => {
throw new Error('An Ionic Router is required for IonRouterContext');
},
back: () => {
throw new Error('An Ionic Router is required for IonRouterContext');
},
canGoBack: () => {
throw new Error('An Ionic Router is required for IonRouterContext');
},
nativeBack: () => {
throw new Error('An Ionic Router is required for IonRouterContext');
},
});
/**
@@ -29,8 +43,8 @@ export function useIonRouter(): UseIonRouterResult {
back: context.back,
push: context.push,
goBack: context.back,
canGoBack: context.canGoBack
}
canGoBack: context.canGoBack,
};
}
type UseIonRouterResult = {
@@ -47,7 +61,13 @@ type UseIonRouterResult = {
* @param routerOptions - Optional - Any additional parameters to pass to the router
* @param animationBuilder - Optional - A custom transition animation to use
*/
push(pathname: string, routerDirection?: RouterDirection, routeAction?: RouteAction, routerOptions?: RouterOptions, animationBuilder?: AnimationBuilder): void;
push(
pathname: string,
routerDirection?: RouterDirection,
routeAction?: RouteAction,
routerOptions?: RouterOptions,
animationBuilder?: AnimationBuilder
): void;
/**
* Navigates backwards in history, using the IonRouter to determine history
* @param animationBuilder - Optional - A custom transition animation to use
@@ -57,4 +77,4 @@ type UseIonRouterResult = {
* Determines if there are any additional routes in the the Router's history. However, routing is not prevented if the browser's history has more entries. Returns true if more entries exist, false if not.
*/
canGoBack(): boolean;
}
};

View File

@@ -1,4 +1,3 @@
import { JSX as LocalJSX } from '@ionic/core';
import React from 'react';
@@ -19,8 +18,7 @@ interface InternalProps extends Props {
forwardedRef?: React.RefObject<HTMLIonRouterOutletElement>;
}
interface InternalState {
}
interface InternalState {}
class IonRouterOutletContainer extends React.Component<InternalProps, InternalState> {
context!: React.ContextType<typeof NavContext>;
@@ -30,32 +28,29 @@ class IonRouterOutletContainer extends React.Component<InternalProps, InternalSt
}
render() {
const StackManager = this.context.getStackManager();
const { children, forwardedRef, ...props } = this.props;
return (
this.context.hasIonicRouter() ? (
props.ionPage ? (
<OutletPageManager
StackManager={StackManager}
routeInfo={this.context.routeInfo}
{...props}
>
{children}
</OutletPageManager>
) : (
<StackManager routeInfo={this.context.routeInfo}>
<IonRouterOutletInner {...props} forwardedRef={forwardedRef}>
{children}
</IonRouterOutletInner>
</StackManager>
)
return this.context.hasIonicRouter() ? (
props.ionPage ? (
<OutletPageManager
StackManager={StackManager}
routeInfo={this.context.routeInfo}
{...props}
>
{children}
</OutletPageManager>
) : (
<IonRouterOutletInner ref={forwardedRef} {...this.props}>
{this.props.children}
<StackManager routeInfo={this.context.routeInfo}>
<IonRouterOutletInner {...props} forwardedRef={forwardedRef}>
{children}
</IonRouterOutletInner>
)
</StackManager>
)
) : (
<IonRouterOutletInner ref={forwardedRef} {...this.props}>
{this.props.children}
</IonRouterOutletInner>
);
}
@@ -64,4 +59,7 @@ class IonRouterOutletContainer extends React.Component<InternalProps, InternalSt
}
}
export const IonRouterOutlet = createForwardRef<Props & IonicReactProps, HTMLIonRouterOutletElement>(IonRouterOutletContainer, 'IonRouterOutlet');
export const IonRouterOutlet = createForwardRef<
Props & IonicReactProps,
HTMLIonRouterOutletElement
>(IonRouterOutletContainer, 'IonRouterOutlet');

View File

@@ -1,12 +1,18 @@
import { ToastButton as ToastButtonCore, ToastOptions as ToastOptionsCore, toastController as toastControllerCore } from '@ionic/core';
import {
ToastButton as ToastButtonCore,
ToastOptions as ToastOptionsCore,
toastController as toastControllerCore,
} from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
export interface ToastButton extends Omit<ToastButtonCore, 'icon'> {
icon?: {
ios: string;
md: string;
} | string;
icon?:
| {
ios: string;
md: string;
}
| string;
}
export interface ToastOptions extends Omit<ToastOptionsCore, 'buttons'> {
@@ -15,8 +21,12 @@ export interface ToastOptions extends Omit<ToastOptionsCore, 'buttons'> {
const toastController = {
create: (options: ToastOptions) => toastControllerCore.create(options as any),
dismiss: (data?: any, role?: string | undefined, id?: string | undefined) => toastControllerCore.dismiss(data, role, id),
getTop: () => toastControllerCore.getTop()
dismiss: (data?: any, role?: string | undefined, id?: string | undefined) =>
toastControllerCore.dismiss(data, role, id),
getTop: () => toastControllerCore.getTop(),
};
export const IonToast = /*@__PURE__*/createControllerComponent<ToastOptions, HTMLIonToastElement>('IonToast', toastController);
export const IonToast = /*@__PURE__*/ createControllerComponent<ToastOptions, HTMLIonToastElement>(
'IonToast',
toastController
);

View File

@@ -1,6 +1,5 @@
export interface IonicReactProps {
class?: string;
className?: string;
style?: {[key: string]: any };
style?: { [key: string]: any };
}

View File

@@ -4,23 +4,22 @@ import { IonButton } from '../index';
import { defineCustomElements } from '@ionic/core/loader';
describe('IonButton', () => {
beforeAll(async (done) => {
await defineCustomElements(window);
done();
})
});
afterEach(cleanup);
it('should render a button', () => {
const { getByText, } = render(<IonButton>my button</IonButton>);
const { getByText } = render(<IonButton>my button</IonButton>);
const button = getByText('my button');
expect(button).toBeDefined();
});
it('when the button is clicked, it should call the click handler', () => {
const clickSpy = jest.fn();
const { getByText, } = render(<IonButton onClick={clickSpy}>my button</IonButton>);
const { getByText } = render(<IonButton onClick={clickSpy}>my button</IonButton>);
const button = getByText('my button');
fireEvent.click(button);
expect(clickSpy).toHaveBeenCalled();

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { IonTabs, IonTabButton, IonLabel, IonIcon, IonTabBar} from '../index';
import { IonTabs, IonTabButton, IonLabel, IonIcon, IonTabBar } from '../index';
import { render, cleanup } from '@testing-library/react';
import { IonRouterOutlet } from '../IonRouterOutlet';
afterEach(cleanup)
afterEach(cleanup);
describe('IonTabs', () => {
test('should render happy path', () => {
@@ -37,7 +37,12 @@ describe('IonTabs', () => {
expect(container.children[0].children[1].tagName).toEqual('ION-TAB-BAR');
expect(container.children[0].children[1].children.length).toEqual(4);
expect(Array.from(container.children[0].children[1].children).map(c => c.tagName)).toEqual(['ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON']);
expect(Array.from(container.children[0].children[1].children).map((c) => c.tagName)).toEqual([
'ION-TAB-BUTTON',
'ION-TAB-BUTTON',
'ION-TAB-BUTTON',
'ION-TAB-BUTTON',
]);
});
test('should allow for conditional children', () => {
@@ -45,12 +50,12 @@ describe('IonTabs', () => {
<IonTabs>
<IonRouterOutlet></IonRouterOutlet>
<IonTabBar slot="bottom">
{false &&
<IonTabButton tab="schedule">
<IonLabel>Schedule</IonLabel>
<IonIcon name="schedule"></IonIcon>
</IonTabButton>
}
{false && (
<IonTabButton tab="schedule">
<IonLabel>Schedule</IonLabel>
<IonIcon name="schedule"></IonIcon>
</IonTabButton>
)}
<IonTabButton tab="speakers">
<IonLabel>Speakers</IonLabel>
<IonIcon name="speakers"></IonIcon>
@@ -73,6 +78,10 @@ describe('IonTabs', () => {
expect(container.children[0].children[1].tagName).toEqual('ION-TAB-BAR');
expect(container.children[0].children[1].children.length).toEqual(3);
expect(Array.from(container.children[0].children[1].children).map(c => c.tagName)).toEqual(['ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON']);
expect(Array.from(container.children[0].children[1].children).map((c) => c.tagName)).toEqual([
'ION-TAB-BUTTON',
'ION-TAB-BUTTON',
'ION-TAB-BUTTON',
]);
});
});

View File

@@ -11,11 +11,7 @@ describe('createComponent - events', () => {
const FakeOnClick = jest.fn((e) => e);
const IonButton = createReactComponent<JSX.IonButton, HTMLIonButtonElement>('ion-button');
const { getByText } = render(
<IonButton onClick={FakeOnClick}>
ButtonNameA
</IonButton>
);
const { getByText } = render(<IonButton onClick={FakeOnClick}>ButtonNameA</IonButton>);
fireEvent.click(getByText('ButtonNameA'));
expect(FakeOnClick).toBeCalledTimes(1);
});
@@ -24,11 +20,7 @@ describe('createComponent - events', () => {
const FakeIonFocus = jest.fn((e) => e);
const IonInput = createReactComponent<JSX.IonInput, HTMLIonInputElement>('ion-input');
const { getByText } = render(
<IonInput onIonFocus={FakeIonFocus}>
ButtonNameA
</IonInput>
);
const { getByText } = render(<IonInput onIonFocus={FakeIonFocus}>ButtonNameA</IonInput>);
const ionInputItem = getByText('ButtonNameA');
expect(Object.keys((ionInputItem as any).__events)).toEqual(['ionFocus']);
});
@@ -39,11 +31,7 @@ describe('createComponent - ref', () => {
const ionButtonRef: React.RefObject<any> = React.createRef();
const IonButton = createReactComponent<JSX.IonButton, HTMLIonButtonElement>('ion-button');
const { getByText } = render(
<IonButton ref={ionButtonRef}>
ButtonNameA
</IonButton>
)
const { getByText } = render(<IonButton ref={ionButtonRef}>ButtonNameA</IonButton>);
const ionButtonItem = getByText('ButtonNameA');
expect(ionButtonRef.current).toEqual(ionButtonItem);
});
@@ -65,8 +53,8 @@ describe('createComponent - strict mode', () => {
});
describe('when working with css classes', () => {
const myClass = 'my-class'
const myClass2 = 'my-class2'
const myClass = 'my-class';
const myClass2 = 'my-class2';
const customClass = 'custom-class';
describe('when a class is added to className', () => {
@@ -74,11 +62,7 @@ describe('when working with css classes', () => {
let button: HTMLElement;
beforeEach(() => {
renderResult = render(
<IonButton className={myClass}>
Hello!
</IonButton>
);
renderResult = render(<IonButton className={myClass}>Hello!</IonButton>);
button = renderResult.getByText(/Hello/);
});
@@ -89,11 +73,7 @@ describe('when working with css classes', () => {
it('when a class is added to class list outside of React, then that class should still be in class list when rendered again', () => {
button.classList.add(customClass);
expect(button.classList.contains(customClass)).toBeTruthy();
renderResult.rerender(
<IonButton className={myClass}>
Hello!
</IonButton>
);
renderResult.rerender(<IonButton className={myClass}>Hello!</IonButton>);
expect(button.classList.contains(customClass)).toBeTruthy();
});
});
@@ -103,11 +83,7 @@ describe('when working with css classes', () => {
let button: HTMLElement;
beforeEach(() => {
renderResult = render(
<IonButton className={myClass + ' ' + myClass2}>
Hello!
</IonButton>
);
renderResult = render(<IonButton className={myClass + ' ' + myClass2}>Hello!</IonButton>);
button = renderResult.getByText(/Hello/);
});
@@ -120,11 +96,7 @@ describe('when working with css classes', () => {
expect(button.classList.contains(myClass)).toBeTruthy();
expect(button.classList.contains(myClass2)).toBeTruthy();
renderResult.rerender(
<IonButton className={myClass}>
Hello!
</IonButton>
);
renderResult.rerender(<IonButton className={myClass}>Hello!</IonButton>);
expect(button.classList.contains(myClass)).toBeTruthy();
expect(button.classList.contains(myClass2)).toBeFalsy();
@@ -136,15 +108,11 @@ describe('when working with css classes', () => {
expect(button.classList.contains(myClass2)).toBeTruthy();
expect(button.classList.contains(customClass)).toBeTruthy();
renderResult.rerender(
<IonButton className={myClass}>
Hello!
</IonButton>
);
renderResult.rerender(<IonButton className={myClass}>Hello!</IonButton>);
expect(button.classList.contains(myClass)).toBeTruthy();
expect(button.classList.contains(myClass)).toBeTruthy();
expect(button.classList.contains(myClass2)).toBeFalsy();
});
})
});
});

View File

@@ -13,9 +13,9 @@ describe('isCoveredByReact', () => {
describe('syncEvent', () => {
it('should add event on sync and readd on additional syncs', () => {
var div = document.createElement("div");
const addEventListener = jest.spyOn(div, "addEventListener");
const removeEventListener = jest.spyOn(div, "removeEventListener");
var div = document.createElement('div');
const addEventListener = jest.spyOn(div, 'addEventListener');
const removeEventListener = jest.spyOn(div, 'removeEventListener');
const ionClickCallback = jest.fn();
utils.syncEvent(div, 'ionClick', ionClickCallback);
@@ -26,29 +26,28 @@ describe('syncEvent', () => {
expect(removeEventListener).toHaveBeenCalledWith('ionClick', expect.any(Function));
expect(addEventListener).toHaveBeenCalledWith('ionClick', expect.any(Function));
const event = new CustomEvent('ionClick', { detail: 'test'});
const event = new CustomEvent('ionClick', { detail: 'test' });
div.dispatchEvent(event);
expect(ionClickCallback).toHaveBeenCalled();
})
});
});
describe('attachProps', () => {
it('should pass props to a dom node', () => {
const onIonClickCallback = () => {};
var div = document.createElement("div");
var div = document.createElement('div');
utils.attachProps(div, {
'children': [],
'style': 'color: red',
'ref': () => {},
'onClick': () => {},
'onIonClick': onIonClickCallback,
'testprop': ['red']
children: [],
style: 'color: red',
ref: () => {},
onClick: () => {},
onIonClick: onIonClickCallback,
testprop: ['red'],
});
expect((div as any).testprop).toEqual(['red']);
expect(div).toHaveStyle(`display: block;`);
expect(Object.keys((div as any).__events)).toEqual(['ionClick']);
});
});

View File

@@ -5,7 +5,13 @@ import { NavContext } from '../contexts/NavContext';
import { RouterOptions } from '../models';
import { RouterDirection } from '../models/RouterDirection';
import { attachProps, camelToDashCase, createForwardRef, dashToPascalCase, isCoveredByReact } from './utils';
import {
attachProps,
camelToDashCase,
createForwardRef,
dashToPascalCase,
isCoveredByReact,
} from './utils';
interface IonicReactInternalProps<ElementType> extends React.HTMLAttributes<ElementType> {
forwardedRef?: React.Ref<ElementType>;
@@ -48,9 +54,15 @@ export const createReactComponent = <PropType, ElementType>(
const { routerLink, routerDirection, routerOptions, routerAnimation } = this.props;
if (routerLink !== undefined) {
e.preventDefault();
this.context.navigate(routerLink, routerDirection, undefined, routerAnimation, routerOptions);
this.context.navigate(
routerLink,
routerDirection,
undefined,
routerAnimation,
routerOptions
);
}
}
};
render() {
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
@@ -70,7 +82,7 @@ export const createReactComponent = <PropType, ElementType>(
const newProps: IonicReactInternalProps<PropType> = {
...propsToPass,
ref: forwardedRef || this.ref,
style
style,
};
if (routerLinkComponent) {
@@ -90,11 +102,7 @@ export const createReactComponent = <PropType, ElementType>(
}
}
return React.createElement(
tagName,
newProps,
children
);
return React.createElement(tagName, newProps, children);
}
static get displayName() {

View File

@@ -16,18 +16,22 @@ export interface ReactControllerProps {
onWillPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
}
export const createControllerComponent = <OptionsType extends object, OverlayType extends OverlayBase>(
export const createControllerComponent = <
OptionsType extends object,
OverlayType extends OverlayBase
>(
displayName: string,
controller: { create: (options: OptionsType) => Promise<OverlayType>; }
controller: { create: (options: OptionsType) => Promise<OverlayType> }
) => {
const didDismissEventName = `on${displayName}DidDismiss`;
const didPresentEventName = `on${displayName}DidPresent`;
const willDismissEventName = `on${displayName}WillDismiss`;
const willPresentEventName = `on${displayName}WillPresent`;
type Props = OptionsType & ReactControllerProps & {
forwardedRef?: React.RefObject<OverlayType>;
};
type Props = OptionsType &
ReactControllerProps & {
forwardedRef?: React.RefObject<OverlayType>;
};
class Overlay extends React.Component<Props> {
overlay?: OverlayType;
@@ -51,7 +55,9 @@ export const createControllerComponent = <OptionsType extends object, OverlayTyp
componentWillUnmount() {
this.isUnmounted = true;
if (this.overlay) { this.overlay.dismiss(); }
if (this.overlay) {
this.overlay.dismiss();
}
}
async componentDidUpdate(prevProps: Props) {
@@ -73,16 +79,30 @@ export const createControllerComponent = <OptionsType extends object, OverlayTyp
}
async present(prevProps?: Props) {
const { isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props;
const {
isOpen,
onDidDismiss,
onDidPresent,
onWillDismiss,
onWillPresent,
...cProps
} = this.props;
this.overlay = await controller.create({
...cProps as any
...(cProps as any),
});
attachProps(this.overlay, {
[didDismissEventName]: this.handleDismiss,
[didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e),
[willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e),
[willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e)
}, prevProps);
attachProps(
this.overlay,
{
[didDismissEventName]: this.handleDismiss,
[didPresentEventName]: (e: CustomEvent) =>
this.props.onDidPresent && this.props.onDidPresent(e),
[willDismissEventName]: (e: CustomEvent) =>
this.props.onWillDismiss && this.props.onWillDismiss(e),
[willPresentEventName]: (e: CustomEvent) =>
this.props.onWillPresent && this.props.onWillPresent(e),
},
prevProps
);
// Check isOpen again since the value could have changed during the async call to controller.create
// It's also possible for the component to have become unmounted.
if (this.props.isOpen === true && this.isUnmounted === false) {

View File

@@ -18,18 +18,22 @@ export interface ReactOverlayProps {
onWillPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
}
export const createOverlayComponent = <OverlayComponent extends object, OverlayType extends OverlayElement>(
export const createOverlayComponent = <
OverlayComponent extends object,
OverlayType extends OverlayElement
>(
displayName: string,
controller: { create: (options: any) => Promise<OverlayType>; }
controller: { create: (options: any) => Promise<OverlayType> }
) => {
const didDismissEventName = `on${displayName}DidDismiss`;
const didPresentEventName = `on${displayName}DidPresent`;
const willDismissEventName = `on${displayName}WillDismiss`;
const willPresentEventName = `on${displayName}WillPresent`;
type Props = OverlayComponent & ReactOverlayProps & {
forwardedRef?: React.RefObject<OverlayType>;
};
type Props = OverlayComponent &
ReactOverlayProps & {
forwardedRef?: React.RefObject<OverlayType>;
};
class Overlay extends React.Component<Props> {
overlay?: OverlayType;
@@ -54,7 +58,9 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
}
componentWillUnmount() {
if (this.overlay) { this.overlay.dismiss(); }
if (this.overlay) {
this.overlay.dismiss();
}
}
handleDismiss(event: CustomEvent<OverlayEventDetail<any>>) {
@@ -80,20 +86,31 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
}
async present(prevProps?: Props) {
const { children, isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props;
const {
children,
isOpen,
onDidDismiss,
onDidPresent,
onWillDismiss,
onWillPresent,
...cProps
} = this.props;
const elementProps = {
...cProps,
ref: this.props.forwardedRef,
[didDismissEventName]: this.handleDismiss,
[didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e),
[willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e),
[willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e)
[didPresentEventName]: (e: CustomEvent) =>
this.props.onDidPresent && this.props.onDidPresent(e),
[willDismissEventName]: (e: CustomEvent) =>
this.props.onWillDismiss && this.props.onWillDismiss(e),
[willPresentEventName]: (e: CustomEvent) =>
this.props.onWillPresent && this.props.onWillPresent(e),
};
this.overlay = await controller.create({
...elementProps,
component: this.el,
componentProps: {}
componentProps: {},
});
if (this.props.forwardedRef) {
@@ -106,10 +123,7 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
}
render() {
return ReactDOM.createPortal(
this.props.isOpen ? this.props.children : null,
this.el
);
return ReactDOM.createPortal(this.props.isOpen ? this.props.children : null, this.el);
}
}

View File

@@ -1,8 +1,41 @@
import { defineCustomElements } from '@ionic/core/loader';
import { addIcons } from 'ionicons';
import { arrowBackSharp, caretBackSharp, chevronBack, chevronForward, close, closeCircle, closeSharp, menuOutline, menuSharp, reorderThreeOutline, reorderTwoSharp, searchOutline, searchSharp } from 'ionicons/icons';
export { Animation, AnimationBuilder, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, createAnimation, createGesture, AlertButton, AlertInput, Gesture, GestureConfig, GestureDetail, iosTransitionAnimation, IonicSafeString, mdTransitionAnimation, NavComponentWithProps, setupConfig } from '@ionic/core';
import {
arrowBackSharp,
caretBackSharp,
chevronBack,
chevronForward,
close,
closeCircle,
closeSharp,
menuOutline,
menuSharp,
reorderThreeOutline,
reorderTwoSharp,
searchOutline,
searchSharp,
} from 'ionicons/icons';
export {
Animation,
AnimationBuilder,
AnimationCallbackOptions,
AnimationDirection,
AnimationFill,
AnimationKeyFrames,
AnimationLifecycle,
createAnimation,
createGesture,
AlertButton,
AlertInput,
Gesture,
GestureConfig,
GestureDetail,
iosTransitionAnimation,
IonicSafeString,
mdTransitionAnimation,
NavComponentWithProps,
setupConfig,
} from '@ionic/core';
export * from './proxies';
// createControllerComponent
@@ -42,7 +75,7 @@ addIcons({
'caret-back-sharp': caretBackSharp,
'chevron-back': chevronBack,
'chevron-forward': chevronForward,
'close': close,
close,
'close-circle': closeCircle,
'close-sharp': closeSharp,
'menu-outline': menuOutline,

View File

@@ -3,13 +3,28 @@ import { JSX as IoniconsJSX } from 'ionicons';
import { /*@__PURE__*/ createReactComponent } from './createComponent';
export const IonTabButtonInner = /*@__PURE__*/createReactComponent<JSX.IonTabButton & { onIonTabButtonClick?: (e: CustomEvent) => void; }, HTMLIonTabButtonElement>('ion-tab-button');
export const IonTabBarInner = /*@__PURE__*/createReactComponent<JSX.IonTabBar, HTMLIonTabBarElement>('ion-tab-bar');
export const IonBackButtonInner = /*@__PURE__*/createReactComponent<Omit<JSX.IonBackButton, 'icon'>, HTMLIonBackButtonElement>('ion-back-button');
export const IonRouterOutletInner = /*@__PURE__*/createReactComponent<JSX.IonRouterOutlet & {
setRef?: (val: HTMLIonRouterOutletElement) => void;
forwardedRef?: React.RefObject<HTMLIonRouterOutletElement>;
}, HTMLIonRouterOutletElement>('ion-router-outlet');
export const IonTabButtonInner = /*@__PURE__*/ createReactComponent<
JSX.IonTabButton & { onIonTabButtonClick?: (e: CustomEvent) => void },
HTMLIonTabButtonElement
>('ion-tab-button');
export const IonTabBarInner = /*@__PURE__*/ createReactComponent<
JSX.IonTabBar,
HTMLIonTabBarElement
>('ion-tab-bar');
export const IonBackButtonInner = /*@__PURE__*/ createReactComponent<
Omit<JSX.IonBackButton, 'icon'>,
HTMLIonBackButtonElement
>('ion-back-button');
export const IonRouterOutletInner = /*@__PURE__*/ createReactComponent<
JSX.IonRouterOutlet & {
setRef?: (val: HTMLIonRouterOutletElement) => void;
forwardedRef?: React.RefObject<HTMLIonRouterOutletElement>;
},
HTMLIonRouterOutletElement
>('ion-router-outlet');
// ionicons
export const IonIconInner = /*@__PURE__*/createReactComponent<IoniconsJSX.IonIcon, HTMLIonIconElement>('ion-icon');
export const IonIconInner = /*@__PURE__*/ createReactComponent<
IoniconsJSX.IonIcon,
HTMLIonIconElement
>('ion-icon');

View File

@@ -5,38 +5,40 @@ import { NavContext } from '../../contexts/NavContext';
import { IonicReactProps } from '../IonicReactProps';
import { IonBackButtonInner } from '../inner-proxies';
type Props = Omit<LocalJSX.IonBackButton, 'icon'> & IonicReactProps & {
icon?: {
ios: string;
md: string;
} | string;
ref?: React.RefObject<HTMLIonBackButtonElement>;
};
type Props = Omit<LocalJSX.IonBackButton, 'icon'> &
IonicReactProps & {
icon?:
| {
ios: string;
md: string;
}
| string;
ref?: React.RefObject<HTMLIonBackButtonElement>;
};
export const IonBackButton = /*@__PURE__*/(() => class extends React.Component<Props> {
context!: React.ContextType<typeof NavContext>;
export const IonBackButton = /*@__PURE__*/ (() =>
class extends React.Component<Props> {
context!: React.ContextType<typeof NavContext>;
clickButton = (e: React.MouseEvent) => {
const { defaultHref, routerAnimation } = this.props;
if (this.context.hasIonicRouter()) {
e.stopPropagation();
this.context.goBack(defaultHref, routerAnimation);
} else if (defaultHref !== undefined) {
window.location.href = defaultHref;
clickButton = (e: React.MouseEvent) => {
const { defaultHref, routerAnimation } = this.props;
if (this.context.hasIonicRouter()) {
e.stopPropagation();
this.context.goBack(defaultHref, routerAnimation);
} else if (defaultHref !== undefined) {
window.location.href = defaultHref;
}
};
render() {
return <IonBackButtonInner onClick={this.clickButton} {...this.props}></IonBackButtonInner>;
}
}
render() {
return (
<IonBackButtonInner onClick={this.clickButton} {...this.props}></IonBackButtonInner>
);
}
static get displayName() {
return 'IonBackButton';
}
static get displayName() {
return 'IonBackButton';
}
static get contextType() {
return NavContext;
}
})();
static get contextType() {
return NavContext;
}
})();

View File

@@ -9,12 +9,13 @@ import { createForwardRef } from '../utils';
import { IonTabButton } from './IonTabButton';
type IonTabBarProps = LocalJSX.IonTabBar & IonicReactProps & {
onIonTabsDidChange?: (event: CustomEvent<{ tab: string; }>) => void;
onIonTabsWillChange?: (event: CustomEvent<{ tab: string; }>) => void;
slot?: 'bottom' | 'top';
style?: { [key: string]: string; };
};
type IonTabBarProps = LocalJSX.IonTabBar &
IonicReactProps & {
onIonTabsDidChange?: (event: CustomEvent<{ tab: string }>) => void;
onIonTabsWillChange?: (event: CustomEvent<{ tab: string }>) => void;
slot?: 'bottom' | 'top';
style?: { [key: string]: string };
};
interface InternalProps extends IonTabBarProps {
forwardedRef?: React.RefObject<HTMLIonIconElement>;
@@ -31,7 +32,7 @@ interface TabUrls {
interface IonTabBarState {
activeTab?: string;
tabs: { [key: string]: TabUrls; };
tabs: { [key: string]: TabUrls };
}
class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarState> {
@@ -39,20 +40,31 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
constructor(props: InternalProps) {
super(props);
const tabs: { [key: string]: TabUrls; } = {};
const tabs: { [key: string]: TabUrls } = {};
React.Children.forEach((props as any).children, (child: any) => {
if (child != null && typeof child === 'object' && child.props && child.type === IonTabButton) {
if (
child != null &&
typeof child === 'object' &&
child.props &&
child.type === IonTabButton
) {
tabs[child.props.tab] = {
originalHref: child.props.href,
currentHref: child.props.href,
originalRouteOptions: child.props.href === props.routeInfo?.pathname ? props.routeInfo?.routeOptions : undefined,
currentRouteOptions: child.props.href === props.routeInfo?.pathname ? props.routeInfo?.routeOptions : undefined,
originalRouteOptions:
child.props.href === props.routeInfo?.pathname
? props.routeInfo?.routeOptions
: undefined,
currentRouteOptions:
child.props.href === props.routeInfo?.pathname
? props.routeInfo?.routeOptions
: undefined,
};
}
});
this.state = {
tabs
tabs,
};
this.onTabButtonClick = this.onTabButtonClick.bind(this);
@@ -64,15 +76,14 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
componentDidMount() {
const tabs = this.state.tabs;
const tabKeys = Object.keys(tabs);
const activeTab = tabKeys
.find(key => {
const href = tabs[key].originalHref;
return this.props.routeInfo!.pathname.startsWith(href);
});
const activeTab = tabKeys.find((key) => {
const href = tabs[key].originalHref;
return this.props.routeInfo!.pathname.startsWith(href);
});
if (activeTab) {
this.setState({
activeTab
activeTab,
});
}
}
@@ -83,19 +94,21 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
}
}
setActiveTabOnContext = (_tab: string) => { };
setActiveTabOnContext = (_tab: string) => {};
selectTab(tab: string) {
const tabUrl = this.state.tabs[tab];
if (tabUrl) {
this.onTabButtonClick(new CustomEvent('ionTabButtonClick', {
detail: {
href: tabUrl.currentHref,
tab,
selected: tab === this.state.activeTab,
routeOptions: undefined
}
}));
this.onTabButtonClick(
new CustomEvent('ionTabButtonClick', {
detail: {
href: tabUrl.currentHref,
tab,
selected: tab === this.state.activeTab,
routeOptions: undefined,
},
})
);
return true;
}
return false;
@@ -104,22 +117,26 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
static getDerivedStateFromProps(props: InternalProps, state: IonTabBarState) {
const tabs = { ...state.tabs };
const tabKeys = Object.keys(state.tabs);
const activeTab = tabKeys
.find(key => {
const href = state.tabs[key].originalHref;
return props.routeInfo!.pathname.startsWith(href);
});
const activeTab = tabKeys.find((key) => {
const href = state.tabs[key].originalHref;
return props.routeInfo!.pathname.startsWith(href);
});
// Check to see if the tab button href has changed, and if so, update it in the tabs state
React.Children.forEach((props as any).children, (child: any) => {
if (child != null && typeof child === 'object' && child.props && child.type === IonTabButton) {
if (
child != null &&
typeof child === 'object' &&
child.props &&
child.type === IonTabButton
) {
const tab = tabs[child.props.tab];
if (!tab || (tab.originalHref !== child.props.href)) {
if (!tab || tab.originalHref !== child.props.href) {
tabs[child.props.tab] = {
originalHref: child.props.href,
currentHref: child.props.href,
originalRouteOptions: child.props.routeOptions,
currentRouteOptions: child.props.routeOptions
currentRouteOptions: child.props.routeOptions,
};
}
}
@@ -129,20 +146,24 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
if (activeTab && prevActiveTab) {
const prevHref = state.tabs[prevActiveTab].currentHref;
const prevRouteOptions = state.tabs[prevActiveTab].currentRouteOptions;
if (activeTab !== prevActiveTab || (prevHref !== props.routeInfo?.pathname || prevRouteOptions !== props.routeInfo?.routeOptions)) {
if (
activeTab !== prevActiveTab ||
prevHref !== props.routeInfo?.pathname ||
prevRouteOptions !== props.routeInfo?.routeOptions
) {
tabs[activeTab] = {
originalHref: tabs[activeTab].originalHref,
currentHref: props.routeInfo!.pathname + (props.routeInfo!.search || ''),
originalRouteOptions: tabs[activeTab].originalRouteOptions,
currentRouteOptions: props.routeInfo?.routeOptions
currentRouteOptions: props.routeInfo?.routeOptions,
};
if (props.routeInfo.routeAction === 'pop' && (activeTab !== prevActiveTab)) {
if (props.routeInfo.routeAction === 'pop' && activeTab !== prevActiveTab) {
// If navigating back and the tabs change, set the prev tab back to its original href
tabs[prevActiveTab] = {
originalHref: tabs[prevActiveTab].originalHref,
currentHref: tabs[prevActiveTab].originalHref,
originalRouteOptions: tabs[prevActiveTab].originalRouteOptions,
currentRouteOptions: tabs[prevActiveTab].currentRouteOptions
currentRouteOptions: tabs[prevActiveTab].currentRouteOptions,
};
}
}
@@ -152,11 +173,13 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
return {
activeTab,
tabs
tabs,
};
}
private onTabButtonClick(e: CustomEvent<{ href: string, selected: boolean, tab: string; routeOptions: unknown; }>) {
private onTabButtonClick(
e: CustomEvent<{ href: string; selected: boolean; tab: string; routeOptions: unknown }>
) {
const tappedTab = this.state.tabs[e.detail.tab];
const originalHref = tappedTab.originalHref;
const currentHref = e.detail.href;
@@ -169,10 +192,14 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
}
} else {
if (this.props.onIonTabsWillChange) {
this.props.onIonTabsWillChange(new CustomEvent('ionTabWillChange', { detail: { tab: e.detail.tab } }));
this.props.onIonTabsWillChange(
new CustomEvent('ionTabWillChange', { detail: { tab: e.detail.tab } })
);
}
if (this.props.onIonTabsDidChange) {
this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } }));
this.props.onIonTabsDidChange(
new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } })
);
}
this.setActiveTabOnContext(e.detail.tab);
this.context.changeTab(e.detail.tab, currentHref, e.detail.routeOptions);
@@ -180,16 +207,28 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
}
private renderTabButton(activeTab: string | null | undefined) {
return (child: (React.ReactElement<LocalJSX.IonTabButton & { onClick: (e: any) => void; routeOptions?: unknown; }>) | null | undefined) => {
return (
child:
| React.ReactElement<
LocalJSX.IonTabButton & { onClick: (e: any) => void; routeOptions?: unknown }
>
| null
| undefined
) => {
if (child != null && child.props && child.type === IonTabButton) {
const href = (child.props.tab === activeTab) ? this.props.routeInfo?.pathname : (this.state.tabs[child.props.tab!].currentHref);
const routeOptions = (child.props.tab === activeTab) ? this.props.routeInfo?.routeOptions : (this.state.tabs[child.props.tab!].currentRouteOptions);
const href =
child.props.tab === activeTab
? this.props.routeInfo?.pathname
: this.state.tabs[child.props.tab!].currentHref;
const routeOptions =
child.props.tab === activeTab
? this.props.routeInfo?.routeOptions
: this.state.tabs[child.props.tab!].currentRouteOptions;
return React.cloneElement(child, {
href,
routeOptions,
onClick: this.onTabButtonClick
onClick: this.onTabButtonClick,
});
}
return null;
@@ -210,18 +249,23 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
}
}
const IonTabBarContainer: React.FC<InternalProps> = React.memo<InternalProps>(({ forwardedRef, ...props }) => {
const context = useContext(NavContext);
return (
<IonTabBarUnwrapped
ref={forwardedRef}
{...props as any}
routeInfo={props.routeInfo || context.routeInfo || { pathname: window.location.pathname }}
onSetCurrentTab={context.setCurrentTab}
>
{props.children}
</IonTabBarUnwrapped>
);
});
const IonTabBarContainer: React.FC<InternalProps> = React.memo<InternalProps>(
({ forwardedRef, ...props }) => {
const context = useContext(NavContext);
return (
<IonTabBarUnwrapped
ref={forwardedRef}
{...(props as any)}
routeInfo={props.routeInfo || context.routeInfo || { pathname: window.location.pathname }}
onSetCurrentTab={context.setCurrentTab}
>
{props.children}
</IonTabBarUnwrapped>
);
}
);
export const IonTabBar = createForwardRef<IonTabBarProps, HTMLIonTabBarElement>(IonTabBarContainer, 'IonTabBar');
export const IonTabBar = createForwardRef<IonTabBarProps, HTMLIonTabBarElement>(
IonTabBarContainer,
'IonTabBar'
);

View File

@@ -5,14 +5,14 @@ import { RouterOptions } from '../../models';
import { IonicReactProps } from '../IonicReactProps';
import { IonTabButtonInner } from '../inner-proxies';
type Props = LocalJSX.IonTabButton & IonicReactProps & {
routerOptions?: RouterOptions;
ref?: React.RefObject<HTMLIonTabButtonElement>;
onClick?: (e: any) => void;
};
type Props = LocalJSX.IonTabButton &
IonicReactProps & {
routerOptions?: RouterOptions;
ref?: React.RefObject<HTMLIonTabButtonElement>;
onClick?: (e: any) => void;
};
export class IonTabButton extends React.Component<Props> {
constructor(props: Props) {
super(props);
this.handleIonTabButtonClick = this.handleIonTabButtonClick.bind(this);
@@ -20,16 +20,25 @@ export class IonTabButton extends React.Component<Props> {
handleIonTabButtonClick() {
if (this.props.onClick) {
this.props.onClick(new CustomEvent('ionTabButtonClick', {
detail: { tab: this.props.tab, href: this.props.href, routeOptions: this.props.routerOptions }
}));
this.props.onClick(
new CustomEvent('ionTabButtonClick', {
detail: {
tab: this.props.tab,
href: this.props.href,
routeOptions: this.props.routerOptions,
},
})
);
}
}
render() {
const { onClick, ...rest } = this.props;
return (
<IonTabButtonInner onIonTabButtonClick={this.handleIonTabButtonClick} {...rest}></IonTabButtonInner>
<IonTabButtonInner
onIonTabButtonClick={this.handleIonTabButtonClick}
{...rest}
></IonTabButtonInner>
);
}

View File

@@ -46,13 +46,13 @@ const hostStyles: React.CSSProperties = {
flexDirection: 'column',
width: '100%',
height: '100%',
contain: 'layout size style'
contain: 'layout size style',
};
const tabsInner: React.CSSProperties = {
position: 'relative',
flex: 1,
contain: 'layout size style'
contain: 'layout size style',
};
export class IonTabs extends React.Component<Props> {
@@ -63,7 +63,7 @@ export class IonTabs extends React.Component<Props> {
ionTabContextState: IonTabsContextState = {
activeTab: undefined,
selectTab: () => false
selectTab: () => false,
};
constructor(props: Props) {
@@ -86,8 +86,10 @@ export class IonTabs extends React.Component<Props> {
let outlet: React.ReactElement<{}> | undefined;
let tabBar: React.ReactElement | undefined;
const children = typeof this.props.children === 'function' ?
(this.props.children as ChildFunction)(this.ionTabContextState) : this.props.children;
const children =
typeof this.props.children === 'function'
? (this.props.children as ChildFunction)(this.ionTabContextState)
: this.props.children;
React.Children.forEach(children, (child: any) => {
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
@@ -103,14 +105,14 @@ export class IonTabs extends React.Component<Props> {
tabBar = React.cloneElement(child, {
onIonTabsDidChange,
onIonTabsWillChange,
ref: this.tabBarRef
ref: this.tabBarRef,
});
} else if (child.type === Fragment && child.props.children[1].type === IonTabBar) {
const { onIonTabsDidChange, onIonTabsWillChange } = this.props;
tabBar = React.cloneElement(child.props.children[1], {
onIonTabsDidChange,
onIonTabsWillChange,
ref: this.tabBarRef
ref: this.tabBarRef,
});
}
});
@@ -125,11 +127,13 @@ export class IonTabs extends React.Component<Props> {
const { className, ...props } = this.props;
return (
<IonTabsContext.Provider
value={this.ionTabContextState}
>
<IonTabsContext.Provider value={this.ionTabContextState}>
{this.context.hasIonicRouter() ? (
<PageManager className={className ? `${className}` : ''} routeInfo={this.context.routeInfo} {...props}>
<PageManager
className={className ? `${className}` : ''}
routeInfo={this.context.routeInfo}
{...props}
>
<ion-tabs className="ion-tabs" style={hostStyles}>
{tabBar.props.slot === 'top' ? tabBar : null}
<div style={tabsInner} className="tabs-inner">
@@ -139,15 +143,15 @@ export class IonTabs extends React.Component<Props> {
</ion-tabs>
</PageManager>
) : (
<div className={className ? `${className}` : 'ion-tabs'} {...props} style={hostStyles}>
{tabBar.props.slot === 'top' ? tabBar : null}
<div style={tabsInner} className="tabs-inner">
{outlet}
</div>
{tabBar.props.slot === 'bottom' ? tabBar : null}
<div className={className ? `${className}` : 'ion-tabs'} {...props} style={hostStyles}>
{tabBar.props.slot === 'top' ? tabBar : null}
<div style={tabsInner} className="tabs-inner">
{outlet}
</div>
)}
</IonTabsContext.Provider >
{tabBar.props.slot === 'bottom' ? tabBar : null}
</div>
)}
</IonTabsContext.Provider>
);
}

View File

@@ -7,5 +7,5 @@ export interface IonTabsContextState {
export const IonTabsContext = React.createContext<IonTabsContextState>({
activeTab: undefined,
selectTab: () => false
selectTab: () => false,
});

View File

@@ -4,74 +4,240 @@ import { createReactComponent } from './createComponent';
import { HrefProps } from './hrefprops';
// ionic/core
export const IonApp = /*@__PURE__*/createReactComponent<JSX.IonApp, HTMLIonAppElement>('ion-app');
export const IonTab = /*@__PURE__*/createReactComponent<JSX.IonTab, HTMLIonTabElement>('ion-tab');
export const IonRouterLink = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonRouterLink>, HTMLIonRouterLinkElement>('ion-router-link', true);
export const IonAvatar = /*@__PURE__*/createReactComponent<JSX.IonAvatar, HTMLIonAvatarElement>('ion-avatar');
export const IonBackdrop = /*@__PURE__*/createReactComponent<JSX.IonBackdrop, HTMLIonBackdropElement>('ion-backdrop');
export const IonBadge = /*@__PURE__*/createReactComponent<JSX.IonBadge, HTMLIonBadgeElement>('ion-badge');
export const IonButton = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonButton>, HTMLIonButtonElement>('ion-button', true);
export const IonButtons = /*@__PURE__*/createReactComponent<JSX.IonButtons, HTMLIonButtonsElement>('ion-buttons');
export const IonCard = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonCard>, HTMLIonCardElement>('ion-card', true);
export const IonCardContent = /*@__PURE__*/createReactComponent<JSX.IonCardContent, HTMLIonCardContentElement>('ion-card-content');
export const IonCardHeader = /*@__PURE__*/createReactComponent<JSX.IonCardHeader, HTMLIonCardHeaderElement>('ion-card-header');
export const IonCardSubtitle = /*@__PURE__*/createReactComponent<JSX.IonCardSubtitle, HTMLIonCardSubtitleElement>('ion-card-subtitle');
export const IonCardTitle = /*@__PURE__*/createReactComponent<JSX.IonCardTitle, HTMLIonCardTitleElement>('ion-card-title');
export const IonCheckbox = /*@__PURE__*/createReactComponent<JSX.IonCheckbox, HTMLIonCheckboxElement>('ion-checkbox');
export const IonCol = /*@__PURE__*/createReactComponent<JSX.IonCol, HTMLIonColElement>('ion-col');
export const IonContent = /*@__PURE__*/createReactComponent<JSX.IonContent, HTMLIonContentElement>('ion-content');
export const IonChip = /*@__PURE__*/createReactComponent<JSX.IonChip, HTMLIonChipElement>('ion-chip');
export const IonDatetime = /*@__PURE__*/createReactComponent<JSX.IonDatetime, HTMLIonDatetimeElement>('ion-datetime');
export const IonFab = /*@__PURE__*/createReactComponent<JSX.IonFab, HTMLIonFabElement>('ion-fab');
export const IonFabButton = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonFabButton>, HTMLIonFabButtonElement>('ion-fab-button', true);
export const IonFabList = /*@__PURE__*/createReactComponent<JSX.IonFabList, HTMLIonFabListElement>('ion-fab-list');
export const IonFooter = /*@__PURE__*/createReactComponent<JSX.IonFooter, HTMLIonFooterElement>('ion-footer');
export const IonGrid = /*@__PURE__*/createReactComponent<JSX.IonGrid, HTMLIonGridElement>('ion-grid');
export const IonHeader = /*@__PURE__*/createReactComponent<JSX.IonHeader, HTMLIonHeaderElement>('ion-header');
export const IonImg = /*@__PURE__*/createReactComponent<JSX.IonImg, HTMLIonImgElement>('ion-img');
export const IonInfiniteScroll = /*@__PURE__*/createReactComponent<JSX.IonInfiniteScroll, HTMLIonInfiniteScrollElement>('ion-infinite-scroll');
export const IonInfiniteScrollContent = /*@__PURE__*/createReactComponent<JSX.IonInfiniteScrollContent, HTMLIonInfiniteScrollContentElement>('ion-infinite-scroll-content');
export const IonInput = /*@__PURE__*/createReactComponent<JSX.IonInput, HTMLIonInputElement>('ion-input');
export const IonItem = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonItem>, HTMLIonItemElement>('ion-item', true);
export const IonItemDivider = /*@__PURE__*/createReactComponent<JSX.IonItemDivider, HTMLIonItemDividerElement>('ion-item-divider');
export const IonItemGroup = /*@__PURE__*/createReactComponent<JSX.IonItemGroup, HTMLIonItemGroupElement>('ion-item-group');
export const IonItemOption = /*@__PURE__*/createReactComponent<HrefProps<JSX.IonItemOption>, HTMLIonItemOptionElement>('ion-item-option', true);
export const IonItemOptions = /*@__PURE__*/createReactComponent<JSX.IonItemOptions, HTMLIonItemOptionsElement>('ion-item-options');
export const IonItemSliding = /*@__PURE__*/createReactComponent<JSX.IonItemSliding, HTMLIonItemSlidingElement>('ion-item-sliding');
export const IonLabel = /*@__PURE__*/createReactComponent<JSX.IonLabel, HTMLIonLabelElement>('ion-label');
export const IonList = /*@__PURE__*/createReactComponent<JSX.IonList, HTMLIonListElement>('ion-list');
export const IonListHeader = /*@__PURE__*/createReactComponent<JSX.IonListHeader, HTMLIonListHeaderElement>('ion-list-header');
export const IonMenu = /*@__PURE__*/createReactComponent<JSX.IonMenu, HTMLIonMenuElement>('ion-menu');
export const IonMenuButton = /*@__PURE__*/createReactComponent<JSX.IonMenuButton, HTMLIonMenuButtonElement>('ion-menu-button');
export const IonMenuToggle = /*@__PURE__*/createReactComponent<JSX.IonMenuToggle, HTMLIonMenuToggleElement>('ion-menu-toggle');
export const IonNote = /*@__PURE__*/createReactComponent<JSX.IonNote, HTMLIonNoteElement>('ion-note');
export const IonPickerColumn = /*@__PURE__*/createReactComponent<JSX.IonPickerColumn, HTMLIonPickerColumnElement>('ion-picker-column');
export const IonNav = /*@__PURE__*/createReactComponent<JSX.IonNav, HTMLIonNavElement>('ion-nav');
export const IonProgressBar = /*@__PURE__*/createReactComponent<JSX.IonProgressBar, HTMLIonProgressBarElement>('ion-progress-bar');
export const IonRadio = /*@__PURE__*/createReactComponent<JSX.IonRadio, HTMLIonRadioElement>('ion-radio');
export const IonRadioGroup = /*@__PURE__*/createReactComponent<JSX.IonRadioGroup, HTMLIonRadioGroupElement>('ion-radio-group');
export const IonRange = /*@__PURE__*/createReactComponent<JSX.IonRange, HTMLIonRangeElement>('ion-range');
export const IonRefresher = /*@__PURE__*/createReactComponent<JSX.IonRefresher, HTMLIonRefresherElement>('ion-refresher');
export const IonRefresherContent = /*@__PURE__*/createReactComponent<JSX.IonRefresherContent, HTMLIonRefresherContentElement>('ion-refresher-content');
export const IonReorder = /*@__PURE__*/createReactComponent<JSX.IonReorder, HTMLIonReorderElement>('ion-reorder');
export const IonReorderGroup = /*@__PURE__*/createReactComponent<JSX.IonReorderGroup, HTMLIonReorderGroupElement>('ion-reorder-group');
export const IonRippleEffect = /*@__PURE__*/createReactComponent<JSX.IonRippleEffect, HTMLIonRippleEffectElement>('ion-ripple-effect');
export const IonRow = /*@__PURE__*/createReactComponent<JSX.IonRow, HTMLIonRowElement>('ion-row');
export const IonSearchbar = /*@__PURE__*/createReactComponent<JSX.IonSearchbar, HTMLIonSearchbarElement>('ion-searchbar');
export const IonSegment = /*@__PURE__*/createReactComponent<JSX.IonSegment, HTMLIonSegmentElement>('ion-segment');
export const IonSegmentButton = /*@__PURE__*/createReactComponent<JSX.IonSegmentButton, HTMLIonSegmentButtonElement>('ion-segment-button');
export const IonSelect = /*@__PURE__*/createReactComponent<JSX.IonSelect, HTMLIonSelectElement>('ion-select');
export const IonSelectOption = /*@__PURE__*/createReactComponent<JSX.IonSelectOption, HTMLIonSelectOptionElement>('ion-select-option');
export const IonSelectPopover = /*@__PURE__*/createReactComponent<JSX.IonSelectPopover, HTMLIonSelectPopoverElement>('ion-select-popover');
export const IonSkeletonText = /*@__PURE__*/createReactComponent<JSX.IonSkeletonText, HTMLIonSkeletonTextElement>('ion-skeleton-text');
export const IonSlide = /*@__PURE__*/createReactComponent<JSX.IonSlide, HTMLIonSlideElement>('ion-slide');
export const IonSlides = /*@__PURE__*/createReactComponent<JSX.IonSlides, HTMLIonSlidesElement>('ion-slides');
export const IonSpinner = /*@__PURE__*/createReactComponent<JSX.IonSpinner, HTMLIonSpinnerElement>('ion-spinner');
export const IonSplitPane = /*@__PURE__*/createReactComponent<JSX.IonSplitPane, HTMLIonSplitPaneElement>('ion-split-pane');
export const IonText = /*@__PURE__*/createReactComponent<JSX.IonText, HTMLIonTextElement>('ion-text');
export const IonTextarea = /*@__PURE__*/createReactComponent<JSX.IonTextarea, HTMLIonTextareaElement>('ion-textarea');
export const IonThumbnail = /*@__PURE__*/createReactComponent<JSX.IonThumbnail, HTMLIonThumbnailElement>('ion-thumbnail');
export const IonTitle = /*@__PURE__*/createReactComponent<JSX.IonTitle, HTMLIonTitleElement>('ion-title');
export const IonToggle = /*@__PURE__*/createReactComponent<JSX.IonToggle, HTMLIonToggleElement>('ion-toggle');
export const IonToolbar = /*@__PURE__*/createReactComponent<JSX.IonToolbar, HTMLIonToolbarElement>('ion-toolbar');
export const IonVirtualScroll = /*@__PURE__*/createReactComponent<JSX.IonVirtualScroll, HTMLIonVirtualScrollElement>('ion-virtual-scroll');
export const IonApp = /*@__PURE__*/ createReactComponent<JSX.IonApp, HTMLIonAppElement>('ion-app');
export const IonTab = /*@__PURE__*/ createReactComponent<JSX.IonTab, HTMLIonTabElement>('ion-tab');
export const IonRouterLink = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonRouterLink>,
HTMLIonRouterLinkElement
>('ion-router-link', true);
export const IonAvatar = /*@__PURE__*/ createReactComponent<JSX.IonAvatar, HTMLIonAvatarElement>(
'ion-avatar'
);
export const IonBackdrop = /*@__PURE__*/ createReactComponent<
JSX.IonBackdrop,
HTMLIonBackdropElement
>('ion-backdrop');
export const IonBadge = /*@__PURE__*/ createReactComponent<JSX.IonBadge, HTMLIonBadgeElement>(
'ion-badge'
);
export const IonButton = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonButton>,
HTMLIonButtonElement
>('ion-button', true);
export const IonButtons = /*@__PURE__*/ createReactComponent<JSX.IonButtons, HTMLIonButtonsElement>(
'ion-buttons'
);
export const IonCard = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonCard>,
HTMLIonCardElement
>('ion-card', true);
export const IonCardContent = /*@__PURE__*/ createReactComponent<
JSX.IonCardContent,
HTMLIonCardContentElement
>('ion-card-content');
export const IonCardHeader = /*@__PURE__*/ createReactComponent<
JSX.IonCardHeader,
HTMLIonCardHeaderElement
>('ion-card-header');
export const IonCardSubtitle = /*@__PURE__*/ createReactComponent<
JSX.IonCardSubtitle,
HTMLIonCardSubtitleElement
>('ion-card-subtitle');
export const IonCardTitle = /*@__PURE__*/ createReactComponent<
JSX.IonCardTitle,
HTMLIonCardTitleElement
>('ion-card-title');
export const IonCheckbox = /*@__PURE__*/ createReactComponent<
JSX.IonCheckbox,
HTMLIonCheckboxElement
>('ion-checkbox');
export const IonCol = /*@__PURE__*/ createReactComponent<JSX.IonCol, HTMLIonColElement>('ion-col');
export const IonContent = /*@__PURE__*/ createReactComponent<JSX.IonContent, HTMLIonContentElement>(
'ion-content'
);
export const IonChip = /*@__PURE__*/ createReactComponent<JSX.IonChip, HTMLIonChipElement>(
'ion-chip'
);
export const IonDatetime = /*@__PURE__*/ createReactComponent<
JSX.IonDatetime,
HTMLIonDatetimeElement
>('ion-datetime');
export const IonFab = /*@__PURE__*/ createReactComponent<JSX.IonFab, HTMLIonFabElement>('ion-fab');
export const IonFabButton = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonFabButton>,
HTMLIonFabButtonElement
>('ion-fab-button', true);
export const IonFabList = /*@__PURE__*/ createReactComponent<JSX.IonFabList, HTMLIonFabListElement>(
'ion-fab-list'
);
export const IonFooter = /*@__PURE__*/ createReactComponent<JSX.IonFooter, HTMLIonFooterElement>(
'ion-footer'
);
export const IonGrid = /*@__PURE__*/ createReactComponent<JSX.IonGrid, HTMLIonGridElement>(
'ion-grid'
);
export const IonHeader = /*@__PURE__*/ createReactComponent<JSX.IonHeader, HTMLIonHeaderElement>(
'ion-header'
);
export const IonImg = /*@__PURE__*/ createReactComponent<JSX.IonImg, HTMLIonImgElement>('ion-img');
export const IonInfiniteScroll = /*@__PURE__*/ createReactComponent<
JSX.IonInfiniteScroll,
HTMLIonInfiniteScrollElement
>('ion-infinite-scroll');
export const IonInfiniteScrollContent = /*@__PURE__*/ createReactComponent<
JSX.IonInfiniteScrollContent,
HTMLIonInfiniteScrollContentElement
>('ion-infinite-scroll-content');
export const IonInput = /*@__PURE__*/ createReactComponent<JSX.IonInput, HTMLIonInputElement>(
'ion-input'
);
export const IonItem = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonItem>,
HTMLIonItemElement
>('ion-item', true);
export const IonItemDivider = /*@__PURE__*/ createReactComponent<
JSX.IonItemDivider,
HTMLIonItemDividerElement
>('ion-item-divider');
export const IonItemGroup = /*@__PURE__*/ createReactComponent<
JSX.IonItemGroup,
HTMLIonItemGroupElement
>('ion-item-group');
export const IonItemOption = /*@__PURE__*/ createReactComponent<
HrefProps<JSX.IonItemOption>,
HTMLIonItemOptionElement
>('ion-item-option', true);
export const IonItemOptions = /*@__PURE__*/ createReactComponent<
JSX.IonItemOptions,
HTMLIonItemOptionsElement
>('ion-item-options');
export const IonItemSliding = /*@__PURE__*/ createReactComponent<
JSX.IonItemSliding,
HTMLIonItemSlidingElement
>('ion-item-sliding');
export const IonLabel = /*@__PURE__*/ createReactComponent<JSX.IonLabel, HTMLIonLabelElement>(
'ion-label'
);
export const IonList = /*@__PURE__*/ createReactComponent<JSX.IonList, HTMLIonListElement>(
'ion-list'
);
export const IonListHeader = /*@__PURE__*/ createReactComponent<
JSX.IonListHeader,
HTMLIonListHeaderElement
>('ion-list-header');
export const IonMenu = /*@__PURE__*/ createReactComponent<JSX.IonMenu, HTMLIonMenuElement>(
'ion-menu'
);
export const IonMenuButton = /*@__PURE__*/ createReactComponent<
JSX.IonMenuButton,
HTMLIonMenuButtonElement
>('ion-menu-button');
export const IonMenuToggle = /*@__PURE__*/ createReactComponent<
JSX.IonMenuToggle,
HTMLIonMenuToggleElement
>('ion-menu-toggle');
export const IonNote = /*@__PURE__*/ createReactComponent<JSX.IonNote, HTMLIonNoteElement>(
'ion-note'
);
export const IonPickerColumn = /*@__PURE__*/ createReactComponent<
JSX.IonPickerColumn,
HTMLIonPickerColumnElement
>('ion-picker-column');
export const IonNav = /*@__PURE__*/ createReactComponent<JSX.IonNav, HTMLIonNavElement>('ion-nav');
export const IonProgressBar = /*@__PURE__*/ createReactComponent<
JSX.IonProgressBar,
HTMLIonProgressBarElement
>('ion-progress-bar');
export const IonRadio = /*@__PURE__*/ createReactComponent<JSX.IonRadio, HTMLIonRadioElement>(
'ion-radio'
);
export const IonRadioGroup = /*@__PURE__*/ createReactComponent<
JSX.IonRadioGroup,
HTMLIonRadioGroupElement
>('ion-radio-group');
export const IonRange = /*@__PURE__*/ createReactComponent<JSX.IonRange, HTMLIonRangeElement>(
'ion-range'
);
export const IonRefresher = /*@__PURE__*/ createReactComponent<
JSX.IonRefresher,
HTMLIonRefresherElement
>('ion-refresher');
export const IonRefresherContent = /*@__PURE__*/ createReactComponent<
JSX.IonRefresherContent,
HTMLIonRefresherContentElement
>('ion-refresher-content');
export const IonReorder = /*@__PURE__*/ createReactComponent<JSX.IonReorder, HTMLIonReorderElement>(
'ion-reorder'
);
export const IonReorderGroup = /*@__PURE__*/ createReactComponent<
JSX.IonReorderGroup,
HTMLIonReorderGroupElement
>('ion-reorder-group');
export const IonRippleEffect = /*@__PURE__*/ createReactComponent<
JSX.IonRippleEffect,
HTMLIonRippleEffectElement
>('ion-ripple-effect');
export const IonRow = /*@__PURE__*/ createReactComponent<JSX.IonRow, HTMLIonRowElement>('ion-row');
export const IonSearchbar = /*@__PURE__*/ createReactComponent<
JSX.IonSearchbar,
HTMLIonSearchbarElement
>('ion-searchbar');
export const IonSegment = /*@__PURE__*/ createReactComponent<JSX.IonSegment, HTMLIonSegmentElement>(
'ion-segment'
);
export const IonSegmentButton = /*@__PURE__*/ createReactComponent<
JSX.IonSegmentButton,
HTMLIonSegmentButtonElement
>('ion-segment-button');
export const IonSelect = /*@__PURE__*/ createReactComponent<JSX.IonSelect, HTMLIonSelectElement>(
'ion-select'
);
export const IonSelectOption = /*@__PURE__*/ createReactComponent<
JSX.IonSelectOption,
HTMLIonSelectOptionElement
>('ion-select-option');
export const IonSelectPopover = /*@__PURE__*/ createReactComponent<
JSX.IonSelectPopover,
HTMLIonSelectPopoverElement
>('ion-select-popover');
export const IonSkeletonText = /*@__PURE__*/ createReactComponent<
JSX.IonSkeletonText,
HTMLIonSkeletonTextElement
>('ion-skeleton-text');
export const IonSlide = /*@__PURE__*/ createReactComponent<JSX.IonSlide, HTMLIonSlideElement>(
'ion-slide'
);
export const IonSlides = /*@__PURE__*/ createReactComponent<JSX.IonSlides, HTMLIonSlidesElement>(
'ion-slides'
);
export const IonSpinner = /*@__PURE__*/ createReactComponent<JSX.IonSpinner, HTMLIonSpinnerElement>(
'ion-spinner'
);
export const IonSplitPane = /*@__PURE__*/ createReactComponent<
JSX.IonSplitPane,
HTMLIonSplitPaneElement
>('ion-split-pane');
export const IonText = /*@__PURE__*/ createReactComponent<JSX.IonText, HTMLIonTextElement>(
'ion-text'
);
export const IonTextarea = /*@__PURE__*/ createReactComponent<
JSX.IonTextarea,
HTMLIonTextareaElement
>('ion-textarea');
export const IonThumbnail = /*@__PURE__*/ createReactComponent<
JSX.IonThumbnail,
HTMLIonThumbnailElement
>('ion-thumbnail');
export const IonTitle = /*@__PURE__*/ createReactComponent<JSX.IonTitle, HTMLIonTitleElement>(
'ion-title'
);
export const IonToggle = /*@__PURE__*/ createReactComponent<JSX.IonToggle, HTMLIonToggleElement>(
'ion-toggle'
);
export const IonToolbar = /*@__PURE__*/ createReactComponent<JSX.IonToolbar, HTMLIonToolbarElement>(
'ion-toolbar'
);
export const IonVirtualScroll = /*@__PURE__*/ createReactComponent<
JSX.IonVirtualScroll,
HTMLIonVirtualScrollElement
>('ion-virtual-scroll');

View File

@@ -9,8 +9,15 @@ export const attachProps = (node: HTMLElement, newProps: any, oldProps: any = {}
node.className = className;
}
Object.keys(newProps).forEach(name => {
if (name === 'children' || name === 'style' || name === 'ref' || name === 'class' || name === 'className' || name === 'forwardedRef') {
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()) {
@@ -42,7 +49,7 @@ export const getClassName = (classList: DOMTokenList, newProps: any, oldProps: a
const finalClassNames: string[] = [];
// 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 => {
currentClasses.forEach((currentClass) => {
if (incomingPropClasses.has(currentClass)) {
// add it as its already included in classnames coming in from newProps
finalClassNames.push(currentClass);
@@ -52,7 +59,7 @@ export const getClassName = (classList: DOMTokenList, newProps: any, oldProps: a
finalClassNames.push(currentClass);
}
});
incomingPropClasses.forEach(s => finalClassNames.push(s));
incomingPropClasses.forEach((s) => finalClassNames.push(s));
return finalClassNames.join(' ');
};
@@ -77,7 +84,11 @@ export const isCoveredByReact = (eventNameSuffix: string) => {
}
};
export const syncEvent = (node: Element & { __events?: { [key: string]: ((e: Event) => any) | undefined; }; }, eventName: string, newEventHandler?: (e: Event) => any) => {
export const syncEvent = (
node: Element & { __events?: { [key: string]: ((e: Event) => any) | undefined } },
eventName: string,
newEventHandler?: (e: Event) => any
) => {
const eventStore = node.__events || (node.__events = {});
const oldEventHandler = eventStore[eventName];
@@ -87,9 +98,14 @@ export const syncEvent = (node: Element & { __events?: { [key: string]: ((e: Eve
}
// Bind new listener.
node.addEventListener(eventName, eventStore[eventName] = function handler(e: Event) {
if (newEventHandler) { newEventHandler.call(this, e); }
});
node.addEventListener(
eventName,
(eventStore[eventName] = function handler(e: Event) {
if (newEventHandler) {
newEventHandler.call(this, e);
}
})
);
};
const arrayToMap = (arr: string[] | DOMTokenList) => {

View File

@@ -1,2 +1,8 @@
export const dashToPascalCase = (str: string) => str.toLowerCase().split('-').map(segment => segment.charAt(0).toUpperCase() + segment.slice(1)).join('');
export const camelToDashCase = (str: string) => str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`);
export const dashToPascalCase = (str: string) =>
str
.toLowerCase()
.split('-')
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
.join('');
export const camelToDashCase = (str: string) =>
str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`);

View File

@@ -1,12 +1,25 @@
import { Config as CoreConfig, Platforms, getPlatforms as getPlatformsCore, isPlatform as isPlatformCore } from '@ionic/core';
import {
Config as CoreConfig,
Platforms,
getPlatforms as getPlatformsCore,
isPlatform as isPlatformCore,
} from '@ionic/core';
import React from 'react';
import { IonicReactProps } from '../IonicReactProps';
export type IonicReactExternalProps<PropType, ElementType> = PropType & Omit<React.HTMLAttributes<ElementType>, 'style'> & IonicReactProps;
export type IonicReactExternalProps<PropType, ElementType> = PropType &
Omit<React.HTMLAttributes<ElementType>, 'style'> &
IonicReactProps;
export const createForwardRef = <PropType, ElementType>(ReactComponent: any, displayName: string) => {
const forwardRef = (props: IonicReactExternalProps<PropType, ElementType>, ref: React.Ref<ElementType>) => {
export const createForwardRef = <PropType, ElementType>(
ReactComponent: any,
displayName: string
) => {
const forwardRef = (
props: IonicReactExternalProps<PropType, ElementType>,
ref: React.Ref<ElementType>
) => {
return <ReactComponent {...props} forwardedRef={ref} />;
};
forwardRef.displayName = displayName;

View File

@@ -1,36 +1,43 @@
import { SerializeDocumentOptions, renderToString } from '@ionic/core/hydrate';
export async function ionRenderToString(html: string, userAgent: string, options: SerializeDocumentOptions = {}) {
export async function ionRenderToString(
html: string,
userAgent: string,
options: SerializeDocumentOptions = {}
) {
const renderToStringOptions = Object.assign(
{},
{
clientHydrateAnnotations: false,
excludeComponents: [
// overlays
'ion-action-sheet',
'ion-alert',
'ion-loading',
'ion-modal',
'ion-picker',
'ion-popover',
'ion-toast',
const renderToStringOptions = Object.assign({}, {
clientHydrateAnnotations: false,
excludeComponents: [
// overlays
'ion-action-sheet',
'ion-alert',
'ion-loading',
'ion-modal',
'ion-picker',
'ion-popover',
'ion-toast',
// navigation
'ion-router',
'ion-route',
'ion-route-redirect',
'ion-router-link',
'ion-router-outlet',
// navigation
'ion-router',
'ion-route',
'ion-route-redirect',
'ion-router-link',
'ion-router-outlet',
// tabs
'ion-tabs',
'ion-tab',
// tabs
'ion-tabs',
'ion-tab',
// auxiliary
'ion-picker-column',
'ion-virtual-scroll'
],
userAgent
}, options);
// auxiliary
'ion-picker-column',
'ion-virtual-scroll',
],
userAgent,
},
options
);
const ionHtml = await renderToString(html, renderToStringOptions);
return ionHtml.html;