mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
feat(react): add initial react code. (#16748)
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "0.0.2-3",
|
||||
"version": "0.0.1",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
"framework",
|
||||
"react",
|
||||
"mobile",
|
||||
"app",
|
||||
"hybrid",
|
||||
@ -32,11 +33,16 @@
|
||||
"dist/"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@ionic/core": "next",
|
||||
"@types/jest": "23.3.9",
|
||||
"@types/node": "10.12.9",
|
||||
"@types/react": "16.7.6",
|
||||
"@types/react-dom": "16.0.9",
|
||||
"react": "latest",
|
||||
"react-dom": "latest"
|
||||
"react-dom": "latest",
|
||||
"typescript": "3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stencil/core": "next"
|
||||
"ionicons": "^4.5.0",
|
||||
"@ionic/core": "4.0.0-beta.18"
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
|
||||
import { Delegate } from '../react-framework-delegate';
|
||||
import { getOrAppendElement } from '../utils/helpers';
|
||||
|
||||
export function createModal(opts: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
return createOverlayInternal('ion-modal-controller', opts);
|
||||
}
|
||||
|
||||
export function createPopover(opts: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
return createOverlayInternal('ion-popover-controller', opts);
|
||||
}
|
||||
|
||||
|
||||
function createOverlayInternal(controllerTagName: string, opts: any) {
|
||||
opts.delegate = Delegate;
|
||||
const element = getOrAppendElement(controllerTagName) as HTMLIonModalControllerElement;
|
||||
return (element as any).componentOnReady().then(() => {
|
||||
return element.create(opts);
|
||||
});
|
||||
}
|
20
react/src/components/AlertModal.tsx
Normal file
20
react/src/components/AlertModal.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import { Components } from '@ionic/core';
|
||||
|
||||
|
||||
const IonAlertModal: React.SFC<Components.IonAlertAttributes> = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
export default IonAlertModal;
|
||||
|
||||
/*
|
||||
import IonAlertModal, { Header, SubHeader, Message, Button} from 'IonAlertModal';
|
||||
|
||||
<IonAlertModal isOpen={state.showModal}>
|
||||
<Header>Favorite Added</Header>
|
||||
<SubHeader></SubHeader>
|
||||
<Message>Favorite info</Message>
|
||||
<Button onClick={(e: MouseEvent) => { this.setState({ showModal: false})}}>OK</Button>
|
||||
</IonAlertModal>
|
||||
*/
|
70
react/src/components/createComponent.ts
Normal file
70
react/src/components/createComponent.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import React, { RefObject } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const dashToPascalCase = (str: string) => str.toLowerCase().split('-').map(segment => segment.charAt(0).toUpperCase() + segment.slice(1)).join('');
|
||||
|
||||
|
||||
function syncEvent(node: Element, eventName: string, newEventHandler: (e: Event) => any) {
|
||||
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
|
||||
const eventStore = (node as any).__events || ((node as any).__events = {});
|
||||
const oldEventHandler = eventStore[eventNameLc];
|
||||
|
||||
// Remove old listener so they don't double up.
|
||||
if (oldEventHandler) {
|
||||
node.removeEventListener(eventNameLc, oldEventHandler);
|
||||
}
|
||||
|
||||
// Bind new listener.
|
||||
if (newEventHandler) {
|
||||
node.addEventListener(eventNameLc, eventStore[eventNameLc] = function handler(e: Event) {
|
||||
newEventHandler.call(this, e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface IonicReactBaseProps {
|
||||
ref?: RefObject<any>
|
||||
}
|
||||
|
||||
export function createReactComponent<T>(tagName: string) {
|
||||
const displayName = dashToPascalCase(tagName);
|
||||
|
||||
|
||||
return class ReactComponent extends React.Component<T & IonicReactBaseProps> {
|
||||
constructor(props: T & IonicReactBaseProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static get displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.componentWillReceiveProps(this.props);
|
||||
}
|
||||
componentWillReceiveProps(props: any) {
|
||||
const node = ReactDOM.findDOMNode(this) as Element | null
|
||||
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(props).forEach(name => {
|
||||
if (name === 'children' || name === 'style') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
|
||||
syncEvent(node, name.substring(2), props[name]);
|
||||
} else {
|
||||
(node as any)[name] = props[name];
|
||||
}
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const { children, className, ...cProps } = this.props as any;
|
||||
cProps.class = className || cProps.class;
|
||||
return React.createElement(tagName, cProps, children);
|
||||
}
|
||||
}
|
||||
}
|
55
react/src/components/index.ts
Normal file
55
react/src/components/index.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Components as IoniconsComponents } from 'ionicons';
|
||||
import { Components } from '@ionic/core';
|
||||
import { createReactComponent } from './createComponent';
|
||||
|
||||
export { default as AlertModal } from './AlertModal';
|
||||
|
||||
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');
|
2
react/src/declarations.d.ts
vendored
2
react/src/declarations.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
declare module 'react';
|
||||
declare module 'react-dom';
|
@ -1,3 +1,26 @@
|
||||
export { Delegate } from './react-framework-delegate';
|
||||
export * from './apis/apis';
|
||||
export * from './utils/wc-shim';
|
||||
import { addIcons } from 'ionicons';
|
||||
import { ICON_PATHS } from 'ionicons/icons';
|
||||
import { IonicConfig } from '@ionic/core';
|
||||
import { defineCustomElements } from '@ionic/core/loader';
|
||||
|
||||
export * from './components';
|
||||
|
||||
export interface IonicGlobal {
|
||||
config?: any;
|
||||
ael?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
|
||||
raf?: (ts: number) => void;
|
||||
rel?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
|
||||
}
|
||||
|
||||
export interface IonicWindow extends Window {
|
||||
Ionic: IonicGlobal;
|
||||
}
|
||||
|
||||
export function registerIonic(config: IonicConfig = {}) {
|
||||
const win: IonicWindow = window as any;
|
||||
const Ionic = (win.Ionic = win.Ionic || {});
|
||||
addIcons(ICON_PATHS);
|
||||
|
||||
Ionic.config = config;
|
||||
defineCustomElements(window);
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { FrameworkDelegate } from '@ionic/core';
|
||||
import { isElementModal, isElementNav } from './utils/helpers';
|
||||
|
||||
export function attachViewToDom(parentElement: HTMLElement, reactComponent: any, propsOrData: any, classesToAdd: string[]) {
|
||||
const wrappingDiv = shouldWrapInIonPage(parentElement) ? document.createElement('ion-page') : document.createElement('div');
|
||||
if (classesToAdd) {
|
||||
for (const clazz of classesToAdd) {
|
||||
wrappingDiv.classList.add(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
parentElement.appendChild(wrappingDiv);
|
||||
|
||||
// mount the React component
|
||||
const reactElement = React.createElement(reactComponent, propsOrData);
|
||||
ReactDOM.render(reactElement, wrappingDiv);
|
||||
|
||||
return Promise.resolve(wrappingDiv);
|
||||
}
|
||||
|
||||
export function removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement): Promise<any> {
|
||||
ReactDOM.unmountComponentAtNode(childElement);
|
||||
parentElement.removeChild(childElement);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const Delegate: FrameworkDelegate = {
|
||||
attachViewToDom: attachViewToDom,
|
||||
removeViewFromDom: removeViewFromDom,
|
||||
};
|
||||
|
||||
export { Delegate }
|
||||
|
||||
|
||||
export function shouldWrapInIonPage(element: HTMLElement) {
|
||||
return isElementModal(element) || isElementNav(element);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
|
||||
export function getOrAppendElement(tagName: string): Element {
|
||||
const element = document.querySelector(tagName);
|
||||
if (element) {
|
||||
return element;
|
||||
}
|
||||
const tmp = document.createElement(tagName);
|
||||
document.body.appendChild(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
export function isElementNav(element: HTMLElement) {
|
||||
return element.tagName.toUpperCase() === 'ION-NAV';
|
||||
}
|
||||
|
||||
export function isElementModal(element: HTMLElement) {
|
||||
return element.classList.contains('modal-wrapper');
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
export function wc(events = {}, obj = {}) {
|
||||
let storedEl: HTMLElement;
|
||||
|
||||
return function (el: HTMLElement) {
|
||||
|
||||
(Object as any).entries(events).forEach((keyValues: string[]) => {
|
||||
const name = keyValues[0];
|
||||
const value = keyValues[1];
|
||||
const action = (el) ? el.addEventListener : storedEl.removeEventListener;
|
||||
if (typeof value === 'function') {
|
||||
action(name, value);
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (el) {
|
||||
(Object as any).entries(obj).forEach((keyValues: string[]) => {
|
||||
const name = keyValues[0];
|
||||
const value = keyValues[1];
|
||||
(el as any)[name] = value;
|
||||
});
|
||||
}
|
||||
storedEl = el;
|
||||
};
|
||||
}
|
@ -15,10 +15,12 @@
|
||||
"outDir": "dist",
|
||||
"removeComments": false,
|
||||
"sourceMap": true,
|
||||
"jsx": "preserve",
|
||||
"target": "es2015"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"compileOnSave": false,
|
||||
"buildOnSave": false
|
||||
|
Reference in New Issue
Block a user