merge release-4.11.2

Sync 4.11.2
This commit is contained in:
Liam DeBeasi
2019-10-21 17:54:25 -04:00
committed by GitHub
10 changed files with 111 additions and 66 deletions

View File

@@ -1,3 +1,20 @@
## [4.11.2](https://github.com/ionic-team/ionic/compare/v4.11.1...v4.11.2) (2019-10-21)
### Bug Fixes
* **animations:** ensure all elements are cleaned up when calling .destroy() ([#19654](https://github.com/ionic-team/ionic/issues/19654)) ([d97e167](https://github.com/ionic-team/ionic/commit/d97e167))
* **header:** collapsible header works in tabs ([#19658](https://github.com/ionic-team/ionic/issues/19658)) ([4853909](https://github.com/ionic-team/ionic/commit/4853909)), closes [#19640](https://github.com/ionic-team/ionic/issues/19640)
* **ios:** hide leaving view after nav transition to avoid flicker ([#19691](https://github.com/ionic-team/ionic/issues/19691)) ([70e0562](https://github.com/ionic-team/ionic/commit/70e0562)), closes [#19674](https://github.com/ionic-team/ionic/issues/19674)
* **menu:** clamp out of bounds swipe value ([#19684](https://github.com/ionic-team/ionic/issues/19684)) ([1535e95](https://github.com/ionic-team/ionic/commit/1535e95)), closes [#18927](https://github.com/ionic-team/ionic/issues/18927)
* **react:** add IonPicker as controller component, fixes [#19620](https://github.com/ionic-team/ionic/issues/19620) ([#19643](https://github.com/ionic-team/ionic/issues/19643)) ([ed98d9e](https://github.com/ionic-team/ionic/commit/ed98d9e))
* **react:** adding change events to IonTabs, fixes [#19665](https://github.com/ionic-team/ionic/issues/19665) ([#19711](https://github.com/ionic-team/ionic/issues/19711)) ([b7baf24](https://github.com/ionic-team/ionic/commit/b7baf24))
* **react:** adding HashRouter to available ion routers, fixes [#19621](https://github.com/ionic-team/ionic/issues/19621) ([#19683](https://github.com/ionic-team/ionic/issues/19683)) ([fcdbb3c](https://github.com/ionic-team/ionic/commit/fcdbb3c))
* **react:** pages no longer hidden when navigating between tabs, fixes [#19646](https://github.com/ionic-team/ionic/issues/19646) ([#19647](https://github.com/ionic-team/ionic/issues/19647)) ([8776556](https://github.com/ionic-team/ionic/commit/8776556))
* **react:** ensure views are removed from DOM after navigating back, fixes [#19701](https://github.com/ionic-team/ionic/issues/19701) ([#19712](https://github.com/ionic-team/ionic/issues/19712)) ([ee21d3a](https://github.com/ionic-team/ionic/commit/ee21d3a))
# [5.0.0-beta.0](https://github.com/ionic-team/ionic/compare/v4.11.1...v5.0.0-beta.0) (2019-10-15)

View File

@@ -0,0 +1,15 @@
import React from 'react';
import { HashRouter, HashRouterProps } from 'react-router-dom';
import { RouteManagerWithRouter } from './Router';
export class IonReactHashRouter extends React.Component<HashRouterProps> {
render() {
const { children, ...props } = this.props;
return (
<HashRouter {...props}>
<RouteManagerWithRouter>{children}</RouteManagerWithRouter>
</HashRouter>
);
}
}

View File

@@ -0,0 +1,15 @@
import React from 'react';
import { BrowserRouter, BrowserRouterProps } from 'react-router-dom';
import { RouteManagerWithRouter } from './Router';
export class IonReactRouter extends React.Component<BrowserRouterProps> {
render() {
const { children, ...props } = this.props;
return (
<BrowserRouter {...props}>
<RouteManagerWithRouter>{children}</RouteManagerWithRouter>
</BrowserRouter>
);
}
}

View File

@@ -15,6 +15,7 @@ interface NavManagerProps extends RouteComponentProps {
findViewInfoByLocation: (location: HistoryLocation) => { view?: ViewItem, viewStack?: ViewStack };
findViewInfoById: (id: string) => { view?: ViewItem, viewStack?: ViewStack };
getActiveIonPage: () => { view?: ViewItem, viewStack?: ViewStack };
onNavigate: (type: 'push' | 'replace', path: string, state?: any) => void;
}
export class NavManager extends React.Component<NavManagerProps, NavContextState> {
@@ -27,8 +28,6 @@ export class NavManager extends React.Component<NavManagerProps, NavContextState
this.state = {
goBack: this.goBack.bind(this),
hasIonicRouter: () => true,
getHistory: this.getHistory.bind(this),
getLocation: this.getLocation.bind(this),
navigate: this.navigate.bind(this),
getStackManager: this.getStackManager.bind(this),
getPageManager: this.getPageManager.bind(this),
@@ -66,36 +65,28 @@ export class NavManager extends React.Component<NavManagerProps, NavContextState
if (enteringView) {
const lastLocation = this.locationHistory.findLastLocation(enteringView.routeData.match.url);
if (lastLocation) {
this.props.history.replace(lastLocation.pathname + lastLocation.search, { direction: 'back' });
this.props.onNavigate('replace', lastLocation.pathname + lastLocation.search, 'back');
} else {
this.props.history.replace(enteringView.routeData.match.url, { direction: 'back' });
this.props.onNavigate('replace', enteringView.routeData.match.url, 'back');
}
} else {
if (defaultHref) {
this.props.history.replace(defaultHref, { direction: 'back' });
this.props.onNavigate('replace', defaultHref, 'back');
}
}
} else {
if (defaultHref) {
this.props.history.replace(defaultHref, { direction: 'back' });
this.props.onNavigate('replace', defaultHref, 'back');
}
}
}
getHistory() {
return this.props.history as any;
}
getLocation() {
return this.props.location as any;
}
navigate(path: string, direction?: RouterDirection | 'none') {
this.props.history.push(path, { direction });
this.props.onNavigate('push', path, direction);
}
tabNavigate(url: string) {
this.props.history.replace(url, { direction: 'back' });
tabNavigate(path: string) {
this.props.onNavigate('replace', path, 'back');
}
getPageManager() {

View File

@@ -2,7 +2,7 @@ import { NavDirection } from '@ionic/core';
import { RouterDirection } from '@ionic/react';
import { Action as HistoryAction, Location as HistoryLocation, UnregisterCallback } from 'history';
import React from 'react';
import { BrowserRouter, BrowserRouterProps, RouteComponentProps, matchPath, withRouter } from 'react-router-dom';
import { RouteComponentProps, matchPath, withRouter } from 'react-router-dom';
import { generateId } from '../utils';
@@ -20,10 +20,12 @@ interface RouteManagerState extends RouteManagerContextState {
class RouteManager extends React.Component<RouteComponentProps, RouteManagerState> {
listenUnregisterCallback: UnregisterCallback | undefined;
activeIonPageId?: string;
currentDirection?: RouterDirection;
constructor(props: RouteComponentProps) {
super(props);
this.listenUnregisterCallback = this.props.history.listen(this.historyChange.bind(this));
this.handleNavigate = this.handleNavigate.bind(this);
this.state = {
viewStacks: new ViewStacks(),
hideView: this.hideView.bind(this),
@@ -41,6 +43,12 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}
}
componentWillUnmount() {
if (this.listenUnregisterCallback) {
this.listenUnregisterCallback();
}
}
hideView(viewId: string) {
const viewStacks = Object.assign(new ViewStacks(), this.state.viewStacks);
const { view } = viewStacks.findViewInfoById(viewId);
@@ -57,6 +65,8 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}
historyChange(location: HistoryLocation, action: HistoryAction) {
location.state = location.state || { direction: this.currentDirection };
this.currentDirection = undefined;
this.setState({
location,
action
@@ -65,7 +75,7 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
setActiveView(location: HistoryLocation, action: HistoryAction) {
const viewStacks = Object.assign(new ViewStacks(), this.state.viewStacks);
let direction: RouterDirection = location.state && location.state.direction || 'forward';
let direction: RouterDirection = (location.state && location.state.direction) || 'forward';
let leavingView: ViewItem | undefined;
const viewStackKeys = viewStacks.getKeys();
@@ -93,17 +103,16 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
enteringView.prevId = enteringView.prevId || leavingView.id;
} else {
direction = direction || 'back';
leavingView.mount = false;
}
} else if (action === 'REPLACE') {
leavingView.mount = false;
}
}
this.removeOrphanedViews(enteringView, enteringViewStack);
} else {
enteringView.show = true;
enteringView.mount = true;
enteringView.routeData.match = match!;
}
});
if (leavingView) {
@@ -120,7 +129,6 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
if (enteringView && viewStack) {
const enteringEl = enteringView.ionPageElement ? enteringView.ionPageElement : undefined;
const leavingEl = leavingView && leavingView.ionPageElement ? leavingView.ionPageElement : undefined;
if (enteringEl) {
// Don't animate from an empty view
const navDirection = leavingEl && leavingEl.innerHTML === '' ? undefined : direction === 'none' ? undefined : direction;
@@ -137,10 +145,20 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
});
}
componentWillUnmount() {
if (this.listenUnregisterCallback) {
this.listenUnregisterCallback();
}
removeOrphanedViews(view: ViewItem, viewStack: ViewStack) {
const viewsToRemove = viewStack.views.filter(v => v.prevId === view.id);
viewsToRemove.forEach(v => {
this.removeOrphanedViews(v, viewStack);
// If view is not currently visible, go ahead and remove it from DOM
if (v.ionPageElement!.classList.contains('ion-page-hidden')) {
v.show = false;
v.ionPageElement = undefined;
v.isIonRoute = false;
v.prevId = undefined;
v.key = generateId();
}
v.mount = false;
});
}
async setupIonRouter(id: string, children: any, routerOutlet: HTMLIonRouterOutletElement) {
@@ -266,11 +284,21 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}
}
handleNavigate(type: 'push' | 'replace', path: string, direction?: RouterDirection) {
this.currentDirection = direction;
if (type === 'push') {
this.props.history.push(path);
} else {
this.props.history.replace(path);
}
}
render() {
return (
<RouteManagerContext.Provider value={this.state}>
<NavManager
{...this.props}
onNavigate={this.handleNavigate}
findViewInfoById={(id: string) => this.state.viewStacks.findViewInfoById(id)}
findViewInfoByLocation={(location: HistoryLocation) => this.state.viewStacks.findViewInfoByLocation(location)}
getActiveIonPage={() => this.state.viewStacks.findViewInfoById(this.activeIonPageId)}
@@ -282,16 +310,5 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}
}
const RouteManagerWithRouter = withRouter(RouteManager);
export const RouteManagerWithRouter = withRouter(RouteManager);
RouteManagerWithRouter.displayName = 'RouteManager';
export class IonReactRouter extends React.Component<BrowserRouterProps> {
render() {
const { children, ...props } = this.props;
return (
<BrowserRouter {...props}>
<RouteManagerWithRouter>{children}</RouteManagerWithRouter>
</BrowserRouter>
);
}
}

View File

@@ -85,16 +85,4 @@ export class ViewStacks {
return { view, viewStack };
}
setHiddenViews() {
const keys = this.getKeys();
keys.forEach(key => {
const viewStack = this.viewStacks[key];
viewStack!.views.forEach(view => {
if (!view.routeData.match && !view.isIonRoute) {
view.show = false;
view.mount = false;
}
});
});
}
}

View File

@@ -1,2 +1,2 @@
export { IonReactRouter } from './Router';
export { IonReactRouter } from './IonReactRouter';
export { IonReactHashRouter } from './IonReactHashRouter';

View File

@@ -6,6 +6,8 @@ import { IonTabBarInner } from '../inner-proxies';
import { IonTabButton } from '../proxies';
type Props = LocalJSX.IonTabBar & {
onIonTabsDidChange?: (event: CustomEvent<{ tab: string }>) => void;
onIonTabsWillChange?: (event: CustomEvent<{ tab: string }>) => void;
currentPath?: string;
slot?: 'bottom' | 'top';
};
@@ -75,6 +77,12 @@ const IonTabBarUnwrapped = /*@__PURE__*/(() => class extends React.Component<Pro
this.context.navigate(originalHref, 'back');
}
} else {
if (this.props.onIonTabsWillChange) {
this.props.onIonTabsWillChange(new CustomEvent('ionTabWillChange', { detail: { tab: e.detail.tab } }));
}
if (this.props.onIonTabsDidChange) {
this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } }));
}
this.context.navigate(this.state.tabs[e.detail.tab].currentHref, 'none');
}
}

View File

@@ -1,3 +1,4 @@
import { JSX as LocalJSX } from '@ionic/core';
import React from 'react';
import { NavContext } from '../../contexts/NavContext';
@@ -5,7 +6,7 @@ import { IonRouterOutlet } from '../IonRouterOutlet';
import { IonTabBar } from './IonTabBar';
interface Props {
interface Props extends LocalJSX.IonTabs {
children: React.ReactNode;
}
@@ -28,7 +29,7 @@ const tabsInner: React.CSSProperties = {
contain: 'layout size style'
};
export const IonTabs = /*@__PURE__*/(() => class extends React.Component<Props> {
export class IonTabs extends React.Component<Props> {
context!: React.ContextType<typeof NavContext>;
routerOutletRef: React.Ref<HTMLIonRouterOutletElement> = React.createRef();
@@ -38,7 +39,7 @@ export const IonTabs = /*@__PURE__*/(() => class extends React.Component<Props>
render() {
let outlet: React.ReactElement<{}> | undefined;
let tabBar: React.ReactElement<{ slot: 'bottom' | 'top' }> | undefined;
let tabBar: React.ReactElement | undefined;
React.Children.forEach(this.props.children, (child: any) => {
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
@@ -48,7 +49,8 @@ export const IonTabs = /*@__PURE__*/(() => class extends React.Component<Props>
outlet = child;
}
if (child.type === IonTabBar) {
tabBar = child;
const { onIonTabsDidChange, onIonTabsWillChange } = this.props;
tabBar = React.cloneElement(child, { onIonTabsDidChange, onIonTabsWillChange });
}
});
@@ -71,11 +73,7 @@ export const IonTabs = /*@__PURE__*/(() => class extends React.Component<Props>
);
}
static get displayName() {
return 'IonTabs';
}
static get contextType() {
return NavContext;
}
})();
}

View File

@@ -2,8 +2,6 @@ import { RouterDirection } from '@ionic/core';
import React from 'react';
export interface NavContextState {
getHistory: () => History;
getLocation: () => Location;
getPageManager: () => any;
getStackManager: () => any;
goBack: (defaultHref?: string) => void;
@@ -15,8 +13,6 @@ export interface NavContextState {
}
export const NavContext = /*@__PURE__*/React.createContext<NavContextState>({
getHistory: () => window.history,
getLocation: () => window.location,
getPageManager: () => undefined,
getStackManager: () => undefined,
goBack: (defaultHref?: string) => {