feat(react): create initial portal implementation for overlay ctrls (#16830)

This commit is contained in:
Josh Thomas
2018-12-20 01:39:40 -06:00
committed by GitHub
parent 1227d57ac7
commit 99bdd1f016
5 changed files with 108 additions and 13 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,
);
}
}
}