Master react (#18998)

* chore(): bump to beta 8

* fix(): IonFabButton href fix

* fix(react): support components with href attributes

* fix(): Prep work to break router out

* fix(): breaking react-router and react-core into own packages

* chore(): moving view stuff out of react-core

* chore(): dev build 8-1

* chore(): update to react beta 8

* chore(): fixes to deps

* fix(): removing IonAnchor in favor of IonRouterLink

* chore(): beta 9 release

* refactor(react): treeshake, minify, api

* wip

* fix(): react dev builds

* fix(): fixes to get app builds working again

* fix(): removing tgz file

* feat(): adding platform helper methods

* fix(): don't map attributes to props

* chore(): add test app

* feat(): copy css folder from core

* chore(): move rollup node resolve to devDependencies

* fix(): expose setupConfig()

* perf(): improve treeshaking

* fix(): removing crypto from generateUniqueId

* fix(): adding missing rollup dp

* fix(): test cleanup and fixes to make tests pass

* chore(): moving react to packages folder

* fix(): fixing react build due to move to packages

* feat(): adding missing IonInfiniteScrollContent component

* chore(): add automated testing using cypress

* fix(): adding option onDidDismiss to controller components

* 0.0.10 react

* wip

* fix(): removing deprecated React calls

* fix(): exporting setupConfig from core

* chore(): bump to 4.8.0-rc.0

* chore(): updating test-app deps and fixing test

* chore(): updates to react readme
This commit is contained in:
Manu MA
2019-08-13 22:24:44 +02:00
committed by Ely Lucas
parent 0b1e23f754
commit 930b271a4a
224 changed files with 16337 additions and 1734 deletions

View File

@ -0,0 +1,39 @@
import { JSX as LocalJSX } from '@ionic/core';
import React from 'react';
import { NavContext } from '../../contexts/NavContext';
import { IonBackButtonInner } from '../inner-proxies';
type Props = LocalJSX.IonBackButton & {
ref?: React.RefObject<HTMLIonBackButtonElement>;
};
export const IonBackButton = /*@__PURE__*/(() => class extends React.Component<Props> {
context!: React.ContextType<typeof NavContext>;
clickButton = (e: MouseEvent) => {
const defaultHref = this.props.defaultHref;
if (defaultHref !== undefined) {
if (this.context.hasIonicRouter()) {
e.stopPropagation();
this.context.goBack(defaultHref);
} else {
window.location.href = defaultHref;
}
}
}
render() {
return (
<IonBackButtonInner onClick={this.clickButton} {...this.props}></IonBackButtonInner>
);
}
static get displayName() {
return 'IonBackButton';
}
static get contextType() {
return NavContext;
}
})();

View File

@ -0,0 +1,111 @@
import { JSX as LocalJSX } from '@ionic/core';
import React, { useContext } from 'react';
import { NavContext } from '../../contexts/NavContext';
import { IonTabBarInner } from '../inner-proxies';
import { IonTabButton } from '../proxies';
type Props = LocalJSX.IonTabBar & {
ref?: React.RefObject<HTMLIonTabBarElement>;
navigate: (path: string) => void;
currentPath: string;
children?: React.ReactNode;
};
interface Tab {
originalHref: string;
currentHref: string;
}
interface State {
activeTab: string | undefined;
tabs: { [key: string]: Tab };
}
const IonTabBarUnwrapped = /*@__PURE__*/(() => class extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
const tabActiveUrls: { [key: string]: Tab } = {};
React.Children.forEach(this.props.children, (child: any) => {
if (child != null && typeof child === 'object' && child.props && child.type === IonTabButton) {
tabActiveUrls[child.props.tab] = {
originalHref: child.props.href,
currentHref: child.props.href
};
}
});
this.state = {
activeTab: undefined,
tabs: tabActiveUrls
};
}
static getDerivedStateFromProps(props: Props, state: State) {
const activeTab = Object.keys(state.tabs)
.find(key => {
const href = state.tabs[key].originalHref;
return props.currentPath.startsWith(href);
});
if (activeTab === undefined || (activeTab === state.activeTab && state.tabs[activeTab].currentHref === props.currentPath)) {
return null;
}
return {
activeTab,
tabs: {
...state.tabs,
[activeTab]: {
originalHref: state.tabs[activeTab].originalHref,
currentHref: props.currentPath
}
}
};
}
private onTabButtonClick = (e: CustomEvent<{ href: string, selected: boolean, tab: string }>) => {
const targetUrl = (this.state.activeTab === e.detail.tab) ?
this.state.tabs[e.detail.tab].originalHref :
this.state.tabs[e.detail.tab].currentHref;
this.props.navigate(targetUrl);
}
private renderChild = (activeTab: string | null | undefined) => (child: (React.ReactElement<LocalJSX.IonTabButton & { onIonTabButtonClick: (e: CustomEvent) => void }>) | null | undefined) => {
if (child != null && child.props && child.type === IonTabButton) {
const href = (child.props.tab === activeTab) ? this.props.currentPath : (this.state.tabs[child.props.tab!].currentHref);
return React.cloneElement(child, {
href,
onIonTabButtonClick: this.onTabButtonClick
});
}
return null;
}
render() {
return (
<IonTabBarInner {...this.props} selectedTab={this.state.activeTab}>
{React.Children.map(this.props.children as any, this.renderChild(this.state.activeTab))}
</IonTabBarInner>
);
}
})();
export const IonTabBar: React.FC<LocalJSX.IonTabBar & { currentPath?: string, navigate?: (path: string) => void; }> = props => {
const context = useContext(NavContext);
return (
<IonTabBarUnwrapped
{...props as any}
navigate={props.navigate || ((path: string) => {
context.navigate(path);
})}
currentPath={props.currentPath || context.currentPath}
>
{props.children}
</IonTabBarUnwrapped>
);
};

View File

@ -0,0 +1,89 @@
import React from 'react';
import { NavContext } from '../../contexts/NavContext';
import { IonRouterOutlet } from '../proxies';
import { IonTabBar } from './IonTabBar';
interface Props {
children: React.ReactNode;
}
const hostStyles: React.CSSProperties = {
display: 'flex',
position: 'absolute',
top: '0',
left: '0',
right: '0',
bottom: '0',
flexDirection: 'column',
width: '100%',
height: '100%',
contain: 'layout size style'
};
const tabsInner: React.CSSProperties = {
position: 'relative',
flex: 1,
contain: 'layout size style'
};
export const IonTabs = /*@__PURE__*/(() => class extends React.Component<Props> {
context!: React.ContextType<typeof NavContext>;
routerOutletRef: React.Ref<HTMLIonRouterOutletElement> = React.createRef();
constructor(props: Props) {
super(props);
}
render() {
let outlet: React.ReactElement<{}> | undefined;
let tabBar: React.ReactElement<{ slot: 'bottom' | 'top' }> | undefined;
React.Children.forEach(this.props.children, (child: any) => {
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
return;
}
if (child.type === IonRouterOutlet) {
outlet = child;
}
if (child.type === IonTabBar) {
tabBar = child;
}
});
if (!outlet) {
throw new Error('IonTabs must contain an IonRouterOutlet');
}
if (!tabBar) {
// TODO, this is not required
throw new Error('IonTabs needs a IonTabBar');
}
const NavManager = this.context.getViewManager();
return (
<div style={hostStyles}>
{tabBar.props.slot === 'top' ? tabBar : null}
<div style={tabsInner} className="tabs-inner">
{this.context.hasIonicRouter() ? (
<NavManager>
{outlet}
</NavManager>
) : (
<>{outlet}</>
)}
</div>
{tabBar.props.slot === 'bottom' ? tabBar : null}
</div>
);
}
static get displayName() {
return 'IonTabs';
}
static get contextType() {
return NavContext;
}
})();