Files
ionic-framework/packages/react/src/components/createControllerComponent.tsx
2019-11-07 13:32:45 -07:00

77 lines
2.1 KiB
TypeScript

import { OverlayEventDetail } from '@ionic/core';
import React from 'react';
import { attachProps } from './utils';
interface OverlayBase extends HTMLElement {
present: () => Promise<void>;
dismiss: (data?: any, role?: string | undefined) => Promise<boolean>;
}
export interface ReactControllerProps {
isOpen: boolean;
onDidDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
}
export const createControllerComponent = <OptionsType extends object, OverlayType extends OverlayBase>(
displayName: string,
controller: { create: (options: OptionsType) => Promise<OverlayType> }
) => {
const dismissEventName = `on${displayName}DidDismiss`;
type Props = OptionsType & ReactControllerProps;
return class extends React.Component<Props> {
overlay?: OverlayType;
isUnmounted = false;
constructor(props: Props) {
super(props);
}
static get displayName() {
return displayName;
}
async componentDidMount() {
const { isOpen } = this.props;
if (isOpen as boolean) {
this.present();
}
}
componentWillUnmount() {
this.isUnmounted = true;
if (this.overlay) { this.overlay.dismiss(); }
}
async componentDidUpdate(prevProps: Props) {
if (prevProps.isOpen !== this.props.isOpen && this.props.isOpen === true) {
this.present(prevProps);
}
if (this.overlay && prevProps.isOpen !== this.props.isOpen && this.props.isOpen === false) {
await this.overlay.dismiss();
}
}
async present(prevProps?: Props) {
const { isOpen, onDidDismiss, ...cProps } = this.props;
this.overlay = await controller.create({
...cProps as any
});
attachProps(this.overlay, {
[dismissEventName]: onDidDismiss
}, 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) {
await this.overlay.present();
}
}
render(): null {
return null;
}
};
};