Skip to content

Commit

Permalink
feat(react): Initial implementations of controller required elements. (
Browse files Browse the repository at this point in the history
  • Loading branch information
jthoms1 authored Dec 19, 2018
1 parent 45b2e5c commit e30c5f1
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 141 deletions.
20 changes: 0 additions & 20 deletions react/src/components/AlertModal.tsx

This file was deleted.

8 changes: 8 additions & 0 deletions react/src/components/IonActionSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type ActionSheetOptions = Omit<Components.IonActionSheetAttributes, 'overlayIndex'>;

const IonActionSheet = createControllerComponent<ActionSheetOptions, HTMLIonActionSheetElement, HTMLIonActionSheetControllerElement>('ion-action-sheet', 'ion-action-sheet-controller')
export default IonActionSheet;
8 changes: 8 additions & 0 deletions react/src/components/IonAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type AlertOptions = Omit<Components.IonAlertAttributes, 'overlayIndex'>;

const IonAlert = createControllerComponent<AlertOptions, HTMLIonAlertElement, HTMLIonAlertControllerElement>('ion-alert', 'ion-alert-controller')
export default IonAlert;
8 changes: 8 additions & 0 deletions react/src/components/IonLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type LoadingOptions = Omit<Components.IonLoadingAttributes, 'overlayIndex'>;

const IonActionSheet = createControllerComponent<LoadingOptions, HTMLIonLoadingElement, HTMLIonLoadingControllerElement>('ion-loading', 'ion-loading-controller')
export default IonActionSheet;
8 changes: 8 additions & 0 deletions react/src/components/IonModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type ModalOptions = Omit<Components.IonModalAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'>;

const IonModal = createControllerComponent<ModalOptions, HTMLIonModalElement, HTMLIonModalControllerElement>('ion-modal', 'ion-modal-controller')
export default IonModal;
8 changes: 8 additions & 0 deletions react/src/components/IonPopover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type PopoverOptions = Omit<Components.IonPopoverAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'>;

const IonPopover = createControllerComponent<PopoverOptions, HTMLIonPopoverElement, HTMLIonPopoverControllerElement>('ion-popover', 'ion-popover-controller')
export default IonPopover;
8 changes: 8 additions & 0 deletions react/src/components/IonToast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { Omit } from './types';

export type ToastOptions = Omit<Components.IonToastAttributes, 'overlayIndex'>;

const IonToast = createControllerComponent<ToastOptions, HTMLIonToastElement, HTMLIonToastControllerElement>('ion-toast', 'ion-toast-controller')
export default IonToast;
70 changes: 0 additions & 70 deletions react/src/components/createComponent.ts

This file was deleted.

58 changes: 58 additions & 0 deletions react/src/components/createComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { dashToPascalCase, attachEventProps } from './utils';

export function createReactComponent<T, E>(tagName: string) {
const displayName = dashToPascalCase(tagName);

type IonicReactInternalProps = {
forwardedRef?: React.RefObject<E>;
children?: React.ReactNode;
}

type IonicReactExternalProps = {
ref?: React.RefObject<E>;
children?: React.ReactNode;
}

class ReactComponent extends React.Component<T & IonicReactInternalProps> {
componentRef: React.RefObject<E>;

constructor(props: T & IonicReactInternalProps) {
super(props);
this.componentRef = React.createRef();
}

static get displayName() {
return displayName;
}

componentDidMount() {
this.componentWillReceiveProps(this.props);
}

componentWillReceiveProps(props: any) {
const node = ReactDOM.findDOMNode(this);

if (!(node instanceof HTMLElement)) {
return;
}

attachEventProps(node, props);
}

render() {
const { children, forwardedRef, ...cProps } = this.props as any;
cProps.ref = forwardedRef;

return React.createElement(tagName, cProps, children);
}
}

function forwardRef(props: T & IonicReactInternalProps, ref: React.RefObject<E>) {
return <ReactComponent {...props} forwardedRef={ref} />;
}
forwardRef.displayName = displayName;

return React.forwardRef<E, T & IonicReactExternalProps>(forwardRef);
}
50 changes: 50 additions & 0 deletions react/src/components/createControllerComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { attachEventProps } from './utils'
import { ensureElementInBody, dashToPascalCase } from './utils';

export function createControllerComponent<T, E extends HTMLElement, C extends HTMLElement>(tagName: string, controllerTagName: string) {
const displayName = dashToPascalCase(tagName);

type IonicReactInternalProps = {
forwardedRef?: React.RefObject<E>;
children?: React.ReactNode;
show: boolean
}

return class ReactControllerComponent extends React.Component<T & IonicReactInternalProps> {
element: E;
controllerElement: C;

constructor(props: T & IonicReactInternalProps) {
super(props);
}

static get displayName() {
return displayName;
}

async componentDidMount() {
this.controllerElement = ensureElementInBody<C>(controllerTagName);
await (this.controllerElement as any).componentOnReady();
}

async componentDidUpdate(prevProps: T & IonicReactInternalProps) {
if (prevProps.show !== this.props.show && this.props.show === true) {
const { children, show, ...cProps} = this.props as any;

this.element = await (this.controllerElement as any).create(cProps);
await (this.element as any).present();

attachEventProps(this.element, cProps);
}
if (prevProps.show !== this.props.show && this.props.show === false) {
return await (this.element as any).dismiss();
}
}

render(): null {
return null;
}
}
}

105 changes: 55 additions & 50 deletions react/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,59 @@ import { Components as IoniconsComponents } from 'ionicons';
import { Components } from '@ionic/core';
import { createReactComponent } from './createComponent';

export { default as AlertModal } from './AlertModal';
export { default as IonActionSheet } from './IonActionSheet';
export { default as IonAlert } from './IonAlert';
export { default as IonLoading } from './IonLoading';
export { default as IonModal } from './IonModal';
export { default as IonPopover } from './IonPopover';
export { default as IonToast } from './IonToast';

export const IonIcon = createReactComponent<IoniconsComponents.IonIconAttributes>('ion-icon');
export const IonApp = createReactComponent<Components.IonAppAttributes>('ion-app');
export const IonPage = createReactComponent<{}>('ion-page');
export const IonMenu = createReactComponent<Components.IonMenuAttributes>('ion-menu');
export const IonHeader = createReactComponent<Components.IonHeaderAttributes>('ion-header');
export const IonTitle = createReactComponent<Components.IonTitleAttributes>('ion-title');
export const IonNav = createReactComponent<Components.IonNavAttributes>('ion-nav');
export const IonToolbar = createReactComponent<Components.IonToolbarAttributes>('ion-toolbar');
export const IonButtons = createReactComponent<Components.IonButtonsAttributes>('ion-buttons');
export const IonSelect = createReactComponent<Components.IonSelectAttributes>('ion-select');
export const IonSelectOption = createReactComponent<Components.IonSelectOptionAttributes>('ion-select-option');
export const IonButton = createReactComponent<Components.IonButtonAttributes>('ion-button');
export const IonContent = createReactComponent<Components.IonContentAttributes>('ion-content');
export const IonList = createReactComponent<Components.IonListAttributes>('ion-list');
export const IonListHeader = createReactComponent<Components.IonListHeaderAttributes>('ion-list-header');
export const IonItem = createReactComponent<Components.IonItemAttributes>('ion-item');
export const IonLabel = createReactComponent<Components.IonLabelAttributes>('ion-label');
export const IonDatetime = createReactComponent<Components.IonDatetimeAttributes>('ion-datetime');
export const IonMenuButton = createReactComponent<Components.IonMenuButtonAttributes>('ion-menu-button');
export const IonItemGroup = createReactComponent<Components.IonItemGroupAttributes>('ion-item-group');
export const IonItemDivider = createReactComponent<Components.IonItemDividerAttributes>('ion-item-divider');
export const IonItemSliding = createReactComponent<Components.IonItemSlidingAttributes>('ion-item-sliding');
export const IonItemOption = createReactComponent<Components.IonItemOptionAttributes>('ion-item-option');
export const IonItemOptions = createReactComponent<Components.IonItemOptionsAttributes>('ion-item-options');
export const IonInput = createReactComponent<Components.IonInputAttributes>('ion-input');
export const IonGrid = createReactComponent<Components.IonGridAttributes>('ion-grid');
export const IonRow = createReactComponent<Components.IonRowAttributes>('ion-row');
export const IonCol = createReactComponent<Components.IonColAttributes>('ion-col');
export const IonSegment= createReactComponent<Components.IonSegmentAttributes>('ion-segment');
export const IonSegmentButton= createReactComponent<Components.IonSegmentButtonAttributes>('ion-segment-button');
export const IonSearchbar= createReactComponent<Components.IonSearchbarAttributes>('ion-searchbar');
export const IonRefresher= createReactComponent<Components.IonRefresherAttributes>('ion-refresher');
export const IonRefresherContent= createReactComponent<Components.IonRefresherContentAttributes>('ion-refresher-content');
export const IonFab= createReactComponent<Components.IonFabAttributes>('ion-fab');
export const IonFabList = createReactComponent<Components.IonFabListAttributes>('ion-fab-list');
export const IonFabButton= createReactComponent<Components.IonFabButtonAttributes>('ion-fab-button');
export const IonAvatar = createReactComponent<Components.IonAvatarAttributes>('ion-avatar');
export const IonCard = createReactComponent<Components.IonCardAttributes>('ion-card');
export const IonCardHeader = createReactComponent<Components.IonCardHeaderAttributes>('ion-card-header');
export const IonCardContent = createReactComponent<Components.IonCardContentAttributes>('ion-card-content');
export const IonTextarea = createReactComponent<Components.IonTextareaAttributes>('ion-textarea');
export const IonTabs = createReactComponent<Components.IonTabsAttributes>('ion-tabs');
export const IonTab = createReactComponent<Components.IonTabAttributes>('ion-tab');
export const IonTabBar = createReactComponent<Components.IonTabBarAttributes>('ion-tab-bar');
export const IonTabButton = createReactComponent<Components.IonTabButtonAttributes>('ion-tab-button');
export const IonSlides = createReactComponent<Components.IonSlidesAttributes>('ion-slides');
export const IonSlide = createReactComponent<Components.IonSlideAttributes>('ion-slide');
export const IonSplitPane = createReactComponent<Components.IonSplitPaneAttributes>('ion-split-pane');
export const IonMenuToggle = createReactComponent<Components.IonMenuToggleAttributes>('ion-menu-toggle');
export const IonIcon = createReactComponent<IoniconsComponents.IonIconAttributes, HTMLIonIconElement>('ion-icon');
export const IonApp = createReactComponent<Components.IonAppAttributes, HTMLIonAppElement>('ion-app');
export const IonMenu = createReactComponent<Components.IonMenuAttributes, HTMLIonMenuElement>('ion-menu');
export const IonHeader = createReactComponent<Components.IonHeaderAttributes, HTMLIonHeaderElement>('ion-header');
export const IonTitle = createReactComponent<Components.IonTitleAttributes, HTMLIonTitleElement>('ion-title');
export const IonNav = createReactComponent<Components.IonNavAttributes, HTMLIonNavElement>('ion-nav');
export const IonToolbar = createReactComponent<Components.IonToolbarAttributes, HTMLIonToolbarElement>('ion-toolbar');
export const IonButtons = createReactComponent<Components.IonButtonsAttributes, HTMLIonButtonsElement>('ion-buttons');
export const IonSelect = createReactComponent<Components.IonSelectAttributes, HTMLIonSelectElement>('ion-select');
export const IonSelectOption = createReactComponent<Components.IonSelectOptionAttributes, HTMLIonSelectOptionElement>('ion-select-option');
export const IonButton = createReactComponent<Components.IonButtonAttributes, HTMLIonButtonElement>('ion-button');
export const IonContent = createReactComponent<Components.IonContentAttributes, HTMLIonContentElement>('ion-content');
export const IonList = createReactComponent<Components.IonListAttributes, HTMLIonListElement>('ion-list');
export const IonListHeader = createReactComponent<Components.IonListHeaderAttributes, HTMLIonListHeaderElement>('ion-list-header');
export const IonItem = createReactComponent<Components.IonItemAttributes, HTMLIonItemElement>('ion-item');
export const IonLabel = createReactComponent<Components.IonLabelAttributes, HTMLIonLabelElement>('ion-label');
export const IonDatetime = createReactComponent<Components.IonDatetimeAttributes, HTMLIonDatetimeElement>('ion-datetime');
export const IonMenuButton = createReactComponent<Components.IonMenuButtonAttributes, HTMLIonMenuButtonElement>('ion-menu-button');
export const IonItemGroup = createReactComponent<Components.IonItemGroupAttributes, HTMLIonItemGroupElement>('ion-item-group');
export const IonItemDivider = createReactComponent<Components.IonItemDividerAttributes, HTMLIonItemDividerElement>('ion-item-divider');
export const IonItemSliding = createReactComponent<Components.IonItemSlidingAttributes, HTMLIonItemSlidingElement>('ion-item-sliding');
export const IonItemOption = createReactComponent<Components.IonItemOptionAttributes, HTMLIonItemOptionElement>('ion-item-option');
export const IonItemOptions = createReactComponent<Components.IonItemOptionsAttributes, HTMLIonItemOptionsElement>('ion-item-options');
export const IonInput = createReactComponent<Components.IonInputAttributes, HTMLIonInputElement>('ion-input');
export const IonGrid = createReactComponent<Components.IonGridAttributes, HTMLIonGridElement>('ion-grid');
export const IonRow = createReactComponent<Components.IonRowAttributes, HTMLIonRowElement>('ion-row');
export const IonCol = createReactComponent<Components.IonColAttributes, HTMLIonColElement>('ion-col');
export const IonSegment= createReactComponent<Components.IonSegmentAttributes, HTMLIonSegmentElement>('ion-segment');
export const IonSegmentButton= createReactComponent<Components.IonSegmentButtonAttributes, HTMLIonSegmentButtonElement>('ion-segment-button');
export const IonSearchbar= createReactComponent<Components.IonSearchbarAttributes, HTMLIonSearchbarElement>('ion-searchbar');
export const IonRefresher= createReactComponent<Components.IonRefresherAttributes, HTMLIonRefresherElement>('ion-refresher');
export const IonRefresherContent= createReactComponent<Components.IonRefresherContentAttributes, HTMLIonRefresherContentElement>('ion-refresher-content');
export const IonFab= createReactComponent<Components.IonFabAttributes, HTMLIonFabElement>('ion-fab');
export const IonFabList = createReactComponent<Components.IonFabListAttributes, HTMLIonFabListElement>('ion-fab-list');
export const IonFabButton= createReactComponent<Components.IonFabButtonAttributes, HTMLIonFabButtonElement>('ion-fab-button');
export const IonAvatar = createReactComponent<Components.IonAvatarAttributes, HTMLIonAvatarElement>('ion-avatar');
export const IonCard = createReactComponent<Components.IonCardAttributes, HTMLIonCardElement>('ion-card');
export const IonCardHeader = createReactComponent<Components.IonCardHeaderAttributes, HTMLIonCardHeaderElement>('ion-card-header');
export const IonCardContent = createReactComponent<Components.IonCardContentAttributes, HTMLIonCardContentElement>('ion-card-content');
export const IonTextarea = createReactComponent<Components.IonTextareaAttributes, HTMLIonTextareaElement>('ion-textarea');
export const IonTabs = createReactComponent<Components.IonTabsAttributes, HTMLIonTabsElement>('ion-tabs');
export const IonTab = createReactComponent<Components.IonTabAttributes, HTMLIonTabElement>('ion-tab');
export const IonTabBar = createReactComponent<Components.IonTabBarAttributes, HTMLIonTabBarElement>('ion-tab-bar');
export const IonTabButton = createReactComponent<Components.IonTabButtonAttributes, HTMLIonTabButtonElement>('ion-tab-button');
export const IonSlides = createReactComponent<Components.IonSlidesAttributes, HTMLIonSlidesElement>('ion-slides');
export const IonSlide = createReactComponent<Components.IonSlideAttributes, HTMLIonSlideElement>('ion-slide');
export const IonSplitPane = createReactComponent<Components.IonSplitPaneAttributes, HTMLIonSplitPaneElement>('ion-split-pane');
export const IonMenuToggle = createReactComponent<Components.IonMenuToggleAttributes, HTMLIonMenuToggleElement>('ion-menu-toggle');
export const IonToggle = createReactComponent<Components.IonToggleAttributes, HTMLIonToggleElement>('ion-toggle');
2 changes: 2 additions & 0 deletions react/src/components/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
Loading

0 comments on commit e30c5f1

Please sign in to comment.