Skip to content

Commit

Permalink
feat(react): create initial portal implementation for overlay ctrls (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jthoms1 committed Dec 20, 2018
1 parent 1227d57 commit 99bdd1f
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 13 deletions.
42 changes: 37 additions & 5 deletions react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,36 @@ Below is a list of components and their current status. Please know that these

| Component | Development Status | Tests |
| ------------------ |:------------------:|:-------------:|
| `ion-action-sheet` | under development | :black_square_button: |
| `ion-action-sheet` | :white_check_mark: | :black_square_button: |
| `ion-alert` | :white_check_mark: | :black_square_button: |
| `ion-anchor` | :black_square_button: | :black_square_button: |
| `ion-animation` | :black_square_button: | :black_square_button: |
| `ion-app` | :white_check_mark: | :black_square_button: |
| `ion-avatar` | :white_check_mark: | :black_square_button: |
| `ion-back-button` | :black_square_button: | :black_square_button: |
| `ion-backdrop` | :black_square_button: | :black_square_button: |
| `ion-badge` | :black_square_button: | :black_square_button: |
| `ion-button` | :white_check_mark: | :black_square_button: |
| `ion-buttons` | :white_check_mark: | :black_square_button: |
| `ion-card` | :white_check_mark: | :black_square_button: |
| `ion-card-content` | :white_check_mark: | :black_square_button: |
| `ion-card-header` | :white_check_mark: | :black_square_button: |
| `ion-card-subtitle` | :black_square_button: | :black_square_button: |
| `ion-card-title` | :black_square_button: | :black_square_button: |
| `ion-checkbox` | :black_square_button: | :black_square_button: |
| `ion-chip` | :black_square_button: | :black_square_button: |
| `ion-col` | :white_check_mark: | :black_square_button: |
| `ion-content` | :white_check_mark: | :black_square_button: |
| `ion-datetime` | :white_check_mark: | :black_square_button: |
| `ion-datetime` | :black_square_button: | :black_square_button: |
| `ion-fab` | :white_check_mark: | :black_square_button: |
| `ion-fab-button` | :white_check_mark: | :black_square_button: |
| `ion-fab-list` | :white_check_mark: | :black_square_button: |
| `ion-footer` | :black_square_button: | :black_square_button: |
| `ion-grid` | :white_check_mark: | :black_square_button: |
| `ion-header` | :white_check_mark: | :black_square_button: |
| `ion-icon` | :white_check_mark: | :black_square_button: |
| `ion-img` | :black_square_button: | :black_square_button: |
| `ion-infinite-scroll` | :black_square_button: | :black_square_button: |
| `ion-input` | :white_check_mark: | :black_square_button: |
| `ion-item` | :white_check_mark: | :black_square_button: |
| `ion-item-divider` | :white_check_mark: | :black_square_button: |
Expand All @@ -47,26 +59,46 @@ Below is a list of components and their current status. Please know that these
| `ion-menu` | :white_check_mark: | :black_square_button: |
| `ion-menu-button` | :white_check_mark: | :black_square_button: |
| `ion-menu-toggle` | :white_check_mark: | :black_square_button: |
| `ion-modal` | under development | :black_square_button: |
| `ion-nav` | :white_check_mark: | :black_square_button: |
| `ion-popover` | under development | :black_square_button: |
| `ion-modal` | :white_check_mark: | :black_square_button: |
| `ion-nav` | :black_square_button: | :black_square_button: |
| `ion-nav-pop` | :black_square_button: | :black_square_button: |
| `ion-nav-push` | :black_square_button: | :black_square_button: |
| `ion-nav-set-root` | :black_square_button: | :black_square_button: |
| `ion-note` | :black_square_button: | :black_square_button: |
| `ion-picker` | :black_square_button: | :black_square_button: |
| `ion-picker-column` | :black_square_button: | :black_square_button: |
| `ion-popover` | :white_check_mark: | :black_square_button: |
| `ion-progress-bar` | :black_square_button: | :black_square_button: |
| `ion-radio` | :black_square_button: | :black_square_button: |
| `ion-radio-group` | :black_square_button: | :black_square_button: |
| `ion-range` | :black_square_button: | :black_square_button: |
| `ion-refresher` | :white_check_mark: | :black_square_button: |
| `ion-refresher-content` | :white_check_mark: | :black_square_button: |
| `ion-reorder` | :black_square_button: | :black_square_button: |
| `ion-reorder-group` | :black_square_button: | :black_square_button: |
| `ion-ripple-effect` | :black_square_button: | :black_square_button: |
| `ion-router-outlet` | :black_square_button: | :black_square_button: |
| `ion-row` | :white_check_mark: | :black_square_button: |
| `ion-searchbar` | :white_check_mark: | :black_square_button: |
| `ion-segment` | :white_check_mark: | :black_square_button: |
| `ion-segment-button` | :white_check_mark: | :black_square_button: |
| `ion-select` | :white_check_mark: | :black_square_button: |
| `ion-select-option` | :white_check_mark: | :black_square_button: |
| `ion-select-popover` | :black_square_button: | :black_square_button: |
| `ion-skeleton-text` | :black_square_button: | :black_square_button: |
| `ion-slide` | :white_check_mark: | :black_square_button: |
| `ion-slides` | :white_check_mark: | :black_square_button: |
| `ion-spinner` | :black_square_button: | :black_square_button: |
| `ion-split-pane` | :white_check_mark: | :black_square_button: |
| `ion-tab` | :white_check_mark: | :black_square_button: |
| `ion-tab-bar` | :white_check_mark: | :black_square_button: |
| `ion-tab-button` | :white_check_mark: | :black_square_button: |
| `ion-tabs` | :white_check_mark: | :black_square_button: |
| `ion-text` | :black_square_button: | :black_square_button: |
| `ion-textarea` | :white_check_mark: | :black_square_button: |
| `ion-thumbnail` | :black_square_button: | :black_square_button: |
| `ion-title` | :white_check_mark: | :black_square_button: |
| `ion-toast` | :white_check_mark: | :black_square_button: |
| `ion-toggle` | :white_check_mark: | :black_square_button: |
| `ion-toolbar` | :white_check_mark: | :black_square_button: |
| `ion-virtual-scroll` | :black_square_button: | :black_square_button: |
4 changes: 2 additions & 2 deletions react/src/components/IonActionSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Components } from '@ionic/core';
import { createControllerComponent } from './createControllerComponent';
import { createOverlayComponent } from './createOverlayComponent';
import { Omit } from './types';

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

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

export type ModalOptions = Omit<Components.IonModalAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'>;
export type ModalOptions = Omit<Components.IonModalAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'> & {
children: React.ReactNode;
};

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

export type PopoverOptions = Omit<Components.IonPopoverAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'>;
export type PopoverOptions = Omit<Components.IonPopoverAttributes, 'delegate' | 'overlayIndex' | 'component' | 'componentProps'> & {
children: React.ReactNode;
};

const IonPopover = createControllerComponent<PopoverOptions, HTMLIonPopoverElement, HTMLIonPopoverControllerElement>('ion-popover', 'ion-popover-controller')
const IonPopover = createOverlayComponent<PopoverOptions, HTMLIonPopoverElement, HTMLIonPopoverControllerElement>('ion-popover', 'ion-popover-controller')
export default IonPopover;
59 changes: 59 additions & 0 deletions react/src/components/createOverlayComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { attachEventProps } from './utils'
import { ensureElementInBody, dashToPascalCase } from './utils';

export function createOverlayComponent<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;
el: HTMLDivElement;

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

this.el = document.createElement('div');
}

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;
cProps.component = this.el;
cProps.componentProps = {};

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() {
return ReactDOM.createPortal(
this.props.children,
this.el,
);
}
}
}

0 comments on commit 99bdd1f

Please sign in to comment.