@ionic/react
Advanced tools
Comparing version 0.0.6-3 to 0.0.6-4
@@ -1,3 +0,1 @@ | ||
import { addIcons } from 'ionicons'; | ||
import { ICON_PATHS } from 'ionicons/icons'; | ||
import { defineCustomElements } from '@ionic/core/loader'; | ||
@@ -9,3 +7,4 @@ import { __rest } from 'tslib'; | ||
export { setupConfig } from '@ionic/core'; | ||
import { withRouter, matchPath } from 'react-router'; | ||
import { withRouter, Switch, matchPath } from 'react-router'; | ||
import { matchPath as matchPath$1, Redirect, withRouter as withRouter$1 } from 'react-router-dom'; | ||
@@ -408,3 +407,3 @@ function attachEventProps(node, newProps, oldProps = {}) { | ||
class StackItemInternal extends React.Component { | ||
class ViewInternal extends React.Component { | ||
constructor(props) { | ||
@@ -417,3 +416,3 @@ super(props); | ||
componentDidMount() { | ||
const { forwardedRef, activateView } = this.props; | ||
const { forwardedRef } = this.props; | ||
this.setState({ ref: forwardedRef }); | ||
@@ -425,5 +424,2 @@ if (forwardedRef && forwardedRef.current) { | ||
forwardedRef.current.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); | ||
if (activateView) { | ||
activateView(forwardedRef.current); | ||
} | ||
} | ||
@@ -453,3 +449,3 @@ } | ||
render() { | ||
const _a = this.props, { className, children, forwardedRef, activateView } = _a, rest = __rest(_a, ["className", "children", "forwardedRef", "activateView"]); | ||
const _a = this.props, { className, children, forwardedRef } = _a, rest = __rest(_a, ["className", "children", "forwardedRef"]); | ||
const { ref } = this.state; | ||
@@ -459,12 +455,20 @@ return (React.createElement("div", Object.assign({ className: className ? `ion-page ${className}` : 'ion-page', ref: forwardedRef }, rest), ref && children)); | ||
} | ||
StackItemInternal.contextType = IonLifeCycleContext; | ||
ViewInternal.contextType = IonLifeCycleContext; | ||
function forwardRef$1(props, ref) { | ||
return React.createElement(StackItemInternal, Object.assign({ forwardedRef: ref }, props)); | ||
return React.createElement(ViewInternal, Object.assign({ forwardedRef: ref }, props)); | ||
} | ||
forwardRef$1.displayName = 'StackItem'; | ||
const StackItem = /*@__PURE__*/ React.forwardRef(forwardRef$1); | ||
forwardRef$1.displayName = 'View'; | ||
const View = /*@__PURE__*/ React.forwardRef(forwardRef$1); | ||
const NavContext = /*@__PURE__*/ React.createContext({ | ||
goBack: () => { } | ||
viewStacks: {}, | ||
hideView: () => { navContextNotFoundError(); }, | ||
goBack: () => { navContextNotFoundError(); }, | ||
registerViewStack: () => { navContextNotFoundError(); }, | ||
removeViewStack: () => { navContextNotFoundError(); }, | ||
transitionView: () => { navContextNotFoundError(); } | ||
}); | ||
function navContextNotFoundError() { | ||
console.error('IonRouter not found, did you add it to the app?'); | ||
} | ||
@@ -525,3 +529,3 @@ const withIonLifeCycle = (WrappedComponent) => { | ||
class StackItemManager extends React.Component { | ||
class ViewItemManager extends React.Component { | ||
constructor(props) { | ||
@@ -536,13 +540,9 @@ super(props); | ||
if (!this.props.mount) { | ||
/** | ||
* Give child component time to finish calling its | ||
* own onViewDidLeave before destroying it | ||
*/ | ||
setTimeout(() => { | ||
if (this._isMounted) { | ||
this.setState({ | ||
show: false | ||
}); | ||
} | ||
}, 1000); | ||
if (this._isMounted) { | ||
this.setState({ | ||
show: false | ||
}, () => { | ||
this.context.hideView(this.props.id); | ||
}); | ||
} | ||
} | ||
@@ -563,172 +563,55 @@ }); | ||
// TODO: treeshake | ||
StackItemManager.contextType = IonLifeCycleContext; | ||
ViewItemManager.contextType = NavContext; | ||
class RouterOutlet extends React.Component { | ||
class IonRouterOutletUnWrapped extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.enteringEl = React.createRef(); | ||
this.leavingEl = React.createRef(); | ||
this.containerEl = React.createRef(); | ||
this.inTransition = false; | ||
this.goBack = (defaultHref) => { | ||
const prevView = this.state.views.find(v => v.id === this.state.activeId); | ||
const newView = this.state.views.find(v => v.id === prevView.prevId); | ||
if (newView) { | ||
this.props.history.replace(newView.location.pathname || defaultHref); | ||
} | ||
else { | ||
this.id = this.props.id || generateUniqueId(); | ||
} | ||
componentDidMount() { | ||
const views = []; | ||
let activeId; | ||
React.Children.forEach(this.props.children, (child) => { | ||
if (child.type === Switch) { | ||
/** | ||
* find the parent view based on the defaultHref and add it | ||
* to the views collection so that navigation works properly | ||
* If the first child is a Switch, loop through its children to build the viewStack | ||
*/ | ||
let element; | ||
let match; | ||
React.Children.forEach(this.props.children, (child) => { | ||
if (match == null) { | ||
element = child; | ||
match = matchPath(defaultHref, child.props); | ||
} | ||
React.Children.forEach(child.props.children, (grandChild) => { | ||
addView.call(this, grandChild); | ||
}); | ||
if (element && match) { | ||
const viewId = generateUniqueId(); | ||
const parentView = { | ||
id: viewId, | ||
location: { | ||
pathname: defaultHref | ||
}, | ||
element: element, | ||
match: match, | ||
prevId: undefined, | ||
mount: true | ||
}; | ||
prevView.prevId = viewId; | ||
this.setState({ | ||
views: [parentView, prevView] | ||
}); | ||
} | ||
this.props.history.replace(defaultHref); | ||
} | ||
}; | ||
this.state = { | ||
direction: undefined, | ||
activeId: undefined, | ||
prevActiveId: undefined, | ||
tabActiveIds: {}, | ||
views: [] | ||
}; | ||
this.activateView = this.activateView.bind(this); | ||
} | ||
static getDerivedStateFromProps(props, state) { | ||
const location = props.location; | ||
let match = null; | ||
let element; | ||
/** | ||
* Remove any views that have been unmounted previously | ||
*/ | ||
const views = state.views.filter(x => x.mount === true); | ||
/** | ||
* Get the current active view and if the path is the same then do nothing | ||
*/ | ||
const activeView = views.find(v => v.id === state.activeId); | ||
/** | ||
* Look at all available paths and find the one that matches | ||
*/ | ||
React.Children.forEach(props.children, (child) => { | ||
if (match == null) { | ||
element = child; | ||
match = matchPath(location.pathname, child.props); | ||
else { | ||
addView.call(this, child); | ||
} | ||
}); | ||
/** | ||
* If there are no matches then set the active view to null and exit | ||
*/ | ||
if (!match) { | ||
return { | ||
direction: undefined, | ||
activeId: undefined, | ||
prevActiveId: undefined | ||
this.context.registerViewStack(this.id, activeId, views, this.containerEl.current, this.props.location); | ||
function addView(child) { | ||
const location = this.props.history.location; | ||
const viewId = generateUniqueId(); | ||
const key = generateUniqueId(); | ||
const element = child; | ||
const match = matchPath(location.pathname, child.props); | ||
const view = { | ||
id: viewId, | ||
key, | ||
match, | ||
element, | ||
mount: true, | ||
show: !!match, | ||
ref: React.createRef(), | ||
childProps: child.props | ||
}; | ||
} | ||
/** | ||
* Get the active view for the tab that matches. | ||
* If the location matches the existing tab path then set that view as active | ||
*/ | ||
const id = state.tabActiveIds[match.params.tab]; | ||
const currentActiveTabView = views.find(v => v.id === id); | ||
if (currentActiveTabView && currentActiveTabView.location.pathname === props.location.pathname) { | ||
if (currentActiveTabView.id === state.activeId) { | ||
/** | ||
* The current tab was clicked, so do nothing | ||
*/ | ||
return null; | ||
if (!!match) { | ||
activeId = viewId; | ||
} | ||
/** | ||
* Activate a tab that is already in views | ||
*/ | ||
return { | ||
direction: undefined, | ||
activeId: currentActiveTabView.id, | ||
prevActiveId: state.activeId, | ||
views: views | ||
}; | ||
views.push(view); | ||
return activeId; | ||
} | ||
/** | ||
* If the new active view is a previous view, then animate it back in | ||
*/ | ||
if (activeView) { | ||
const prevActiveView = views.find(v => v.id === activeView.prevId); | ||
if (prevActiveView && activeView.match.params.tab === match.params.tab && prevActiveView.match.url === match.url) { | ||
return { | ||
direction: 'back', | ||
activeId: prevActiveView.id, | ||
prevActiveId: activeView.id, | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: prevActiveView.id }), | ||
views: views.map(x => { | ||
if (x.id === activeView.id) { | ||
return Object.assign({}, x, { mount: false }); | ||
} | ||
return x; | ||
}) | ||
}; | ||
} | ||
} | ||
/** | ||
* If the current view does not match the url, see if the view that matches the url is currently in the stack. | ||
* If so, show the view that matches the url and remove the current view. | ||
*/ | ||
if (currentActiveTabView && currentActiveTabView.location.pathname !== props.location.pathname) { | ||
const view = views.find(x => x.location.pathname == props.location.pathname); | ||
if (view && view.id === currentActiveTabView.prevId) { | ||
return { | ||
direction: undefined, | ||
activeId: view.id, | ||
prevActiveId: undefined, | ||
views: views.filter(x => x.id !== currentActiveTabView.id), | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: view.id }), | ||
}; | ||
} | ||
} | ||
/** | ||
* Else add this new view to the stack | ||
*/ | ||
const viewId = generateUniqueId(); | ||
const newState = { | ||
direction: (state.tabActiveIds[match.params.tab]) ? 'forward' : undefined, | ||
activeId: viewId, | ||
prevActiveId: state.tabActiveIds[match.params.tab] || state.activeId, | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: viewId }), | ||
views: views.concat({ | ||
id: viewId, | ||
location, | ||
match, | ||
element, | ||
prevId: state.tabActiveIds[match.params.tab], | ||
mount: true | ||
}) | ||
}; | ||
return newState; | ||
} | ||
componentWillUnmount() { | ||
this.context.removeViewStack(this.id); | ||
} | ||
renderChild(item) { | ||
const component = React.cloneElement(item.element, { | ||
location: item.location, | ||
computedMatch: item.match | ||
@@ -738,73 +621,15 @@ }); | ||
} | ||
activateView(el) { | ||
/** | ||
* Gets called from StackItem to initialize a new view | ||
*/ | ||
if (!this.state.direction) { | ||
const leavingEl = (this.leavingEl.current != null) ? this.leavingEl.current : undefined; | ||
this.transitionView(el, leavingEl); | ||
} | ||
} | ||
transitionView(enteringEl, leavingEl) { | ||
// | ||
/** | ||
* Super hacky workaround to make sure containerEL is available | ||
* since activateView might be called from StackItem before IonRouterOutlet is mounted | ||
*/ | ||
if (this.containerEl && this.containerEl.current && this.containerEl.current.componentOnReady) { | ||
this.commitView(enteringEl, leavingEl); | ||
} | ||
else { | ||
setTimeout(() => { | ||
this.transitionView(enteringEl, leavingEl); | ||
}, 10); | ||
} | ||
} | ||
async commitView(enteringEl, leavingEl) { | ||
if (!this.inTransition) { | ||
this.inTransition = true; | ||
await this.containerEl.current.componentOnReady(); | ||
await this.containerEl.current.commit(enteringEl, leavingEl, { | ||
deepWait: true, | ||
duration: this.state.direction === undefined ? 0 : undefined, | ||
direction: this.state.direction, | ||
showGoBack: this.state.direction === 'forward', | ||
progressAnimation: false | ||
}); | ||
if (leavingEl) { | ||
/** | ||
* add hidden attributes | ||
*/ | ||
leavingEl.classList.add('ion-page-hidden'); | ||
leavingEl.setAttribute('aria-hidden', 'true'); | ||
} | ||
this.inTransition = false; | ||
} | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
/** | ||
* Don't transition the view if the state didn't change | ||
* Probably means we are still on the same view | ||
*/ | ||
if (prevState !== this.state) { | ||
const enteringEl = (this.enteringEl.current != null) ? this.enteringEl.current : undefined; | ||
const leavingEl = (this.leavingEl.current != null) ? this.leavingEl.current : undefined; | ||
this.transitionView(enteringEl, leavingEl); | ||
} | ||
} | ||
render() { | ||
return (React.createElement(IonRouterOutletInner, { ref: this.containerEl }, | ||
React.createElement(NavContext.Provider, { value: { goBack: this.goBack } }, this.state.views.map((item) => { | ||
return (React.createElement(NavContext.Consumer, null, context => { | ||
this.context = context; | ||
const viewStack = context.viewStacks[this.id]; | ||
const activeId = viewStack ? viewStack.activeId : ''; | ||
const views = (viewStack || { views: [] }).views.filter(x => x.show); | ||
return (React.createElement(IonRouterOutletInner, { "data-id": this.id, ref: this.containerEl }, views.map((item) => { | ||
let props = {}; | ||
if (item.id === this.state.prevActiveId) { | ||
if (item.id === activeId) { | ||
props = { | ||
'ref': this.leavingEl | ||
'className': ' ion-page-invisible' | ||
}; | ||
} | ||
else if (item.id === this.state.activeId) { | ||
props = { | ||
'ref': this.enteringEl, | ||
'className': (this.state.direction != null ? ' ion-page-invisible' : '') | ||
}; | ||
} | ||
else { | ||
@@ -816,8 +641,9 @@ props = { | ||
} | ||
return (React.createElement(StackItemManager, { key: item.id, mount: item.mount }, | ||
React.createElement(StackItem, Object.assign({ activateView: this.activateView }, props), this.renderChild(item)))); | ||
})))); | ||
return (React.createElement(ViewItemManager, { id: item.id, key: item.key, mount: item.mount }, | ||
React.createElement(View, Object.assign({ ref: item.ref }, props), this.renderChild(item)))); | ||
}))); | ||
})); | ||
} | ||
} | ||
const IonRouterOutlet = /*@__PURE__*/ withRouter(RouterOutlet); | ||
const IonRouterOutlet = /*@__PURE__*/ withRouter(IonRouterOutletUnWrapped); | ||
@@ -877,5 +703,222 @@ const hostStyles = { | ||
addIcons(ICON_PATHS); | ||
class IonRouter extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.goBack = (defaultHref) => { | ||
const { view: leavingView } = this.findViewInfoByLocation(this.props.location, this.state.viewStacks); | ||
if (leavingView) { | ||
const { view: enteringView } = this.findViewInfoById(leavingView.prevId, this.state.viewStacks); | ||
if (enteringView) { | ||
this.props.history.replace(enteringView.match.url, { direction: 'back' }); | ||
} | ||
else { | ||
this.props.history.replace(defaultHref, { direction: 'back' }); | ||
} | ||
} | ||
else { | ||
this.props.history.replace(defaultHref, { direction: 'back' }); | ||
} | ||
}; | ||
this.state = { | ||
viewStacks: {}, | ||
hideView: this.hideView.bind(this), | ||
registerViewStack: this.registerView.bind(this), | ||
removeViewStack: this.removeViewStack.bind(this), | ||
goBack: this.goBack.bind(this), | ||
transitionView: this.transitionView.bind(this) | ||
}; | ||
} | ||
componentWillMount() { | ||
this.listenUnregisterCallback = this.props.history.listen(this.historyChange.bind(this)); | ||
} | ||
hideView(viewId) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
const { view } = this.findViewInfoById(viewId, viewStacks); | ||
if (view) { | ||
view.show = false; | ||
view.key = generateUniqueId(); | ||
this.setState({ | ||
viewStacks | ||
}); | ||
} | ||
} | ||
historyChange(location, action) { | ||
this.setActiveView(location, action); | ||
} | ||
findViewInfoByLocation(location, viewStacks) { | ||
let view; | ||
let match; | ||
let viewStack; | ||
const keys = Object.keys(viewStacks); | ||
keys.some(key => { | ||
const vs = viewStacks[key]; | ||
return vs.views.some(x => { | ||
match = matchPath$1(location.pathname, x.childProps); | ||
if (match) { | ||
view = x; | ||
viewStack = vs; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
}); | ||
const result = { view, viewStack, match }; | ||
return result; | ||
} | ||
findViewInfoById(id, viewStacks) { | ||
let view; | ||
let viewStack; | ||
const keys = Object.keys(viewStacks); | ||
keys.some(key => { | ||
const vs = viewStacks[key]; | ||
view = vs.views.find(x => x.id === id); | ||
if (view) { | ||
viewStack = vs; | ||
return true; | ||
} | ||
else { | ||
return false; | ||
} | ||
}); | ||
return { view, viewStack }; | ||
} | ||
setActiveView(location, action) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
const { view: enteringView, viewStack: enteringViewStack, match } = this.findViewInfoByLocation(location, viewStacks); | ||
let direction = location.state && location.state.direction; | ||
if (!enteringViewStack) { | ||
return; | ||
} | ||
const { view: leavingView } = this.findViewInfoById(this.activeViewId, viewStacks); | ||
if (leavingView && leavingView.match.url === location.pathname) { | ||
return; | ||
} | ||
if (enteringView) { | ||
/** | ||
* If the page is being pushed into the stack by another view, | ||
* record the view that originally directed to the new view for back button purposes. | ||
*/ | ||
if (!enteringView.show && action === 'PUSH') { | ||
enteringView.prevId = leavingView && leavingView.id; | ||
} | ||
enteringView.show = true; | ||
enteringView.mount = true; | ||
enteringView.match = match; | ||
enteringViewStack.activeId = enteringView.id; | ||
this.activeViewId = enteringView.id; | ||
if (leavingView) { | ||
this.prevViewId = leavingView.id; | ||
if (leavingView.match.params.tab === enteringView.match.params.tab) { | ||
if (action === 'PUSH') { | ||
direction = direction || 'forward'; | ||
} | ||
else { | ||
direction = direction || 'back'; | ||
leavingView.mount = false; | ||
} | ||
} | ||
/** | ||
* Attempt to determine if the leaving view is a route redirect. | ||
* If it is, take it out of the rendering phase. | ||
* We assume Routes with render props are redirects, because of this users should not use | ||
* the render prop for non redirects, and instead provide a component in its place. | ||
*/ | ||
if (leavingView.element.type === Redirect || leavingView.element.props.render) { | ||
leavingView.mount = false; | ||
leavingView.show = false; | ||
} | ||
} | ||
this.setState({ | ||
viewStacks | ||
}, () => { | ||
const enteringEl = enteringView.ref && enteringView.ref.current ? enteringView.ref.current : undefined; | ||
const leavingEl = leavingView && leavingView.ref && leavingView.ref.current ? leavingView.ref.current : undefined; | ||
this.transitionView(enteringEl, leavingEl, enteringViewStack.routerOutlet, direction); | ||
}); | ||
} | ||
} | ||
componentWillUnmount() { | ||
this.listenUnregisterCallback(); | ||
} | ||
registerView(stack, activeId, stackItems, routerOutlet, location) { | ||
this.setState((prevState) => { | ||
const prevViewStacks = Object.assign({}, prevState.viewStacks); | ||
prevViewStacks[stack] = { | ||
activeId: activeId, | ||
views: stackItems, | ||
routerOutlet | ||
}; | ||
return { | ||
viewStacks: prevViewStacks | ||
}; | ||
}, () => { | ||
const { view: activeView } = this.findViewInfoById(activeId, this.state.viewStacks); | ||
if (activeView) { | ||
this.prevViewId = this.activeViewId; | ||
this.activeViewId = activeView.id; | ||
const direction = location.state && location.state.direction; | ||
const { view: prevView } = this.findViewInfoById(this.prevViewId, this.state.viewStacks); | ||
this.transitionView(activeView.ref.current, prevView && prevView.ref.current || undefined, routerOutlet, direction); | ||
} | ||
}); | ||
} | ||
; | ||
removeViewStack(stack) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
delete viewStacks[stack]; | ||
this.setState({ | ||
viewStacks | ||
}); | ||
} | ||
findActiveView(views) { | ||
let view; | ||
views.some(x => { | ||
const match = matchPath$1(this.props.location.pathname, x.childProps); | ||
if (match) { | ||
view = x; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return view; | ||
} | ||
transitionView(enteringEl, leavingEl, ionRouterOuter, direction) { | ||
/** | ||
* Super hacky workaround to make sure ionRouterOutlet is available | ||
* since transitionView might be called before IonRouterOutlet is fully mounted | ||
*/ | ||
if (ionRouterOuter && ionRouterOuter.componentOnReady) { | ||
this.commitView(enteringEl, leavingEl, ionRouterOuter, direction); | ||
} | ||
else { | ||
setTimeout(() => { | ||
this.transitionView(enteringEl, leavingEl, ionRouterOuter, direction); | ||
}, 10); | ||
} | ||
} | ||
async commitView(enteringEl, leavingEl, ionRouterOuter, direction) { | ||
await ionRouterOuter.componentOnReady(); | ||
await ionRouterOuter.commit(enteringEl, leavingEl, { | ||
deepWait: true, | ||
duration: direction === undefined ? 0 : undefined, | ||
direction: direction, | ||
showGoBack: direction === 'forward', | ||
progressAnimation: false | ||
}); | ||
if (leavingEl && (enteringEl !== leavingEl)) { | ||
/** | ||
* add hidden attributes | ||
*/ | ||
leavingEl.classList.add('ion-page-hidden'); | ||
leavingEl.setAttribute('aria-hidden', 'true'); | ||
} | ||
} | ||
render() { | ||
return (React.createElement(NavContext.Provider, { value: this.state }, this.props.children)); | ||
} | ||
} | ||
const IonRouterWrapped = withRouter$1(IonRouter); | ||
defineCustomElements(window); | ||
export { IonActionSheet, IonAlert, IonAnchor, IonApp, IonAvatar, IonBackButton, IonBackButtonInner, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonLifeCycleContext, IonList, IonListHeader, IonLoading, IonMenu, IonMenuButton, IonMenuToggle, IonModal, IonNav, IonNote, IonPage, IonPicker, IonPickerColumn, IonPopover, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRouterOutlet, IonRouterOutletInner, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSelectPopover, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTab, IonTabBar, IonTabBarInner, IonTabButton, IonTabs, IonText, IonTextarea, IonThumbnail, IonTitle, IonToast, IonToggle, IonToolbar, IonVirtualScroll, useIonViewDidEnter, useIonViewDidLeave, useIonViewWillEnter, useIonViewWillLeave, withIonLifeCycle }; | ||
export { IonActionSheet, IonAlert, IonAnchor, IonApp, IonAvatar, IonBackButton, IonBackButtonInner, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonLifeCycleContext, IonList, IonListHeader, IonLoading, IonMenu, IonMenuButton, IonMenuToggle, IonModal, IonNav, IonNote, IonPage, IonPicker, IonPickerColumn, IonPopover, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRouterWrapped as IonRouter, IonRouterOutlet, IonRouterOutletInner, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSelectPopover, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTab, IonTabBar, IonTabBarInner, IonTabButton, IonTabs, IonText, IonTextarea, IonThumbnail, IonTitle, IonToast, IonToggle, IonToolbar, IonVirtualScroll, useIonViewDidEnter, useIonViewDidLeave, useIonViewWillEnter, useIonViewWillLeave, withIonLifeCycle }; |
@@ -7,4 +7,2 @@ 'use strict'; | ||
var ionicons = require('ionicons'); | ||
var icons = require('ionicons/icons'); | ||
var loader = require('@ionic/core/loader'); | ||
@@ -16,2 +14,3 @@ var tslib_1 = require('tslib'); | ||
var reactRouter = require('react-router'); | ||
var reactRouterDom = require('react-router-dom'); | ||
@@ -414,3 +413,3 @@ function attachEventProps(node, newProps, oldProps = {}) { | ||
class StackItemInternal extends React.Component { | ||
class ViewInternal extends React.Component { | ||
constructor(props) { | ||
@@ -423,3 +422,3 @@ super(props); | ||
componentDidMount() { | ||
const { forwardedRef, activateView } = this.props; | ||
const { forwardedRef } = this.props; | ||
this.setState({ ref: forwardedRef }); | ||
@@ -431,5 +430,2 @@ if (forwardedRef && forwardedRef.current) { | ||
forwardedRef.current.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); | ||
if (activateView) { | ||
activateView(forwardedRef.current); | ||
} | ||
} | ||
@@ -459,3 +455,3 @@ } | ||
render() { | ||
const _a = this.props, { className, children, forwardedRef, activateView } = _a, rest = tslib_1.__rest(_a, ["className", "children", "forwardedRef", "activateView"]); | ||
const _a = this.props, { className, children, forwardedRef } = _a, rest = tslib_1.__rest(_a, ["className", "children", "forwardedRef"]); | ||
const { ref } = this.state; | ||
@@ -465,12 +461,20 @@ return (React.createElement("div", Object.assign({ className: className ? `ion-page ${className}` : 'ion-page', ref: forwardedRef }, rest), ref && children)); | ||
} | ||
StackItemInternal.contextType = IonLifeCycleContext; | ||
ViewInternal.contextType = IonLifeCycleContext; | ||
function forwardRef$1(props, ref) { | ||
return React.createElement(StackItemInternal, Object.assign({ forwardedRef: ref }, props)); | ||
return React.createElement(ViewInternal, Object.assign({ forwardedRef: ref }, props)); | ||
} | ||
forwardRef$1.displayName = 'StackItem'; | ||
const StackItem = /*@__PURE__*/ React.forwardRef(forwardRef$1); | ||
forwardRef$1.displayName = 'View'; | ||
const View = /*@__PURE__*/ React.forwardRef(forwardRef$1); | ||
const NavContext = /*@__PURE__*/ React.createContext({ | ||
goBack: () => { } | ||
viewStacks: {}, | ||
hideView: () => { navContextNotFoundError(); }, | ||
goBack: () => { navContextNotFoundError(); }, | ||
registerViewStack: () => { navContextNotFoundError(); }, | ||
removeViewStack: () => { navContextNotFoundError(); }, | ||
transitionView: () => { navContextNotFoundError(); } | ||
}); | ||
function navContextNotFoundError() { | ||
console.error('IonRouter not found, did you add it to the app?'); | ||
} | ||
@@ -531,3 +535,3 @@ const withIonLifeCycle = (WrappedComponent) => { | ||
class StackItemManager extends React.Component { | ||
class ViewItemManager extends React.Component { | ||
constructor(props) { | ||
@@ -542,13 +546,9 @@ super(props); | ||
if (!this.props.mount) { | ||
/** | ||
* Give child component time to finish calling its | ||
* own onViewDidLeave before destroying it | ||
*/ | ||
setTimeout(() => { | ||
if (this._isMounted) { | ||
this.setState({ | ||
show: false | ||
}); | ||
} | ||
}, 1000); | ||
if (this._isMounted) { | ||
this.setState({ | ||
show: false | ||
}, () => { | ||
this.context.hideView(this.props.id); | ||
}); | ||
} | ||
} | ||
@@ -569,172 +569,55 @@ }); | ||
// TODO: treeshake | ||
StackItemManager.contextType = IonLifeCycleContext; | ||
ViewItemManager.contextType = NavContext; | ||
class RouterOutlet extends React.Component { | ||
class IonRouterOutletUnWrapped extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.enteringEl = React.createRef(); | ||
this.leavingEl = React.createRef(); | ||
this.containerEl = React.createRef(); | ||
this.inTransition = false; | ||
this.goBack = (defaultHref) => { | ||
const prevView = this.state.views.find(v => v.id === this.state.activeId); | ||
const newView = this.state.views.find(v => v.id === prevView.prevId); | ||
if (newView) { | ||
this.props.history.replace(newView.location.pathname || defaultHref); | ||
} | ||
else { | ||
this.id = this.props.id || generateUniqueId(); | ||
} | ||
componentDidMount() { | ||
const views = []; | ||
let activeId; | ||
React.Children.forEach(this.props.children, (child) => { | ||
if (child.type === reactRouter.Switch) { | ||
/** | ||
* find the parent view based on the defaultHref and add it | ||
* to the views collection so that navigation works properly | ||
* If the first child is a Switch, loop through its children to build the viewStack | ||
*/ | ||
let element; | ||
let match; | ||
React.Children.forEach(this.props.children, (child) => { | ||
if (match == null) { | ||
element = child; | ||
match = reactRouter.matchPath(defaultHref, child.props); | ||
} | ||
React.Children.forEach(child.props.children, (grandChild) => { | ||
addView.call(this, grandChild); | ||
}); | ||
if (element && match) { | ||
const viewId = generateUniqueId(); | ||
const parentView = { | ||
id: viewId, | ||
location: { | ||
pathname: defaultHref | ||
}, | ||
element: element, | ||
match: match, | ||
prevId: undefined, | ||
mount: true | ||
}; | ||
prevView.prevId = viewId; | ||
this.setState({ | ||
views: [parentView, prevView] | ||
}); | ||
} | ||
this.props.history.replace(defaultHref); | ||
} | ||
}; | ||
this.state = { | ||
direction: undefined, | ||
activeId: undefined, | ||
prevActiveId: undefined, | ||
tabActiveIds: {}, | ||
views: [] | ||
}; | ||
this.activateView = this.activateView.bind(this); | ||
} | ||
static getDerivedStateFromProps(props, state) { | ||
const location = props.location; | ||
let match = null; | ||
let element; | ||
/** | ||
* Remove any views that have been unmounted previously | ||
*/ | ||
const views = state.views.filter(x => x.mount === true); | ||
/** | ||
* Get the current active view and if the path is the same then do nothing | ||
*/ | ||
const activeView = views.find(v => v.id === state.activeId); | ||
/** | ||
* Look at all available paths and find the one that matches | ||
*/ | ||
React.Children.forEach(props.children, (child) => { | ||
if (match == null) { | ||
element = child; | ||
match = reactRouter.matchPath(location.pathname, child.props); | ||
else { | ||
addView.call(this, child); | ||
} | ||
}); | ||
/** | ||
* If there are no matches then set the active view to null and exit | ||
*/ | ||
if (!match) { | ||
return { | ||
direction: undefined, | ||
activeId: undefined, | ||
prevActiveId: undefined | ||
this.context.registerViewStack(this.id, activeId, views, this.containerEl.current, this.props.location); | ||
function addView(child) { | ||
const location = this.props.history.location; | ||
const viewId = generateUniqueId(); | ||
const key = generateUniqueId(); | ||
const element = child; | ||
const match = reactRouter.matchPath(location.pathname, child.props); | ||
const view = { | ||
id: viewId, | ||
key, | ||
match, | ||
element, | ||
mount: true, | ||
show: !!match, | ||
ref: React.createRef(), | ||
childProps: child.props | ||
}; | ||
} | ||
/** | ||
* Get the active view for the tab that matches. | ||
* If the location matches the existing tab path then set that view as active | ||
*/ | ||
const id = state.tabActiveIds[match.params.tab]; | ||
const currentActiveTabView = views.find(v => v.id === id); | ||
if (currentActiveTabView && currentActiveTabView.location.pathname === props.location.pathname) { | ||
if (currentActiveTabView.id === state.activeId) { | ||
/** | ||
* The current tab was clicked, so do nothing | ||
*/ | ||
return null; | ||
if (!!match) { | ||
activeId = viewId; | ||
} | ||
/** | ||
* Activate a tab that is already in views | ||
*/ | ||
return { | ||
direction: undefined, | ||
activeId: currentActiveTabView.id, | ||
prevActiveId: state.activeId, | ||
views: views | ||
}; | ||
views.push(view); | ||
return activeId; | ||
} | ||
/** | ||
* If the new active view is a previous view, then animate it back in | ||
*/ | ||
if (activeView) { | ||
const prevActiveView = views.find(v => v.id === activeView.prevId); | ||
if (prevActiveView && activeView.match.params.tab === match.params.tab && prevActiveView.match.url === match.url) { | ||
return { | ||
direction: 'back', | ||
activeId: prevActiveView.id, | ||
prevActiveId: activeView.id, | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: prevActiveView.id }), | ||
views: views.map(x => { | ||
if (x.id === activeView.id) { | ||
return Object.assign({}, x, { mount: false }); | ||
} | ||
return x; | ||
}) | ||
}; | ||
} | ||
} | ||
/** | ||
* If the current view does not match the url, see if the view that matches the url is currently in the stack. | ||
* If so, show the view that matches the url and remove the current view. | ||
*/ | ||
if (currentActiveTabView && currentActiveTabView.location.pathname !== props.location.pathname) { | ||
const view = views.find(x => x.location.pathname == props.location.pathname); | ||
if (view && view.id === currentActiveTabView.prevId) { | ||
return { | ||
direction: undefined, | ||
activeId: view.id, | ||
prevActiveId: undefined, | ||
views: views.filter(x => x.id !== currentActiveTabView.id), | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: view.id }), | ||
}; | ||
} | ||
} | ||
/** | ||
* Else add this new view to the stack | ||
*/ | ||
const viewId = generateUniqueId(); | ||
const newState = { | ||
direction: (state.tabActiveIds[match.params.tab]) ? 'forward' : undefined, | ||
activeId: viewId, | ||
prevActiveId: state.tabActiveIds[match.params.tab] || state.activeId, | ||
tabActiveIds: Object.assign({}, state.tabActiveIds, { [match.params.tab]: viewId }), | ||
views: views.concat({ | ||
id: viewId, | ||
location, | ||
match, | ||
element, | ||
prevId: state.tabActiveIds[match.params.tab], | ||
mount: true | ||
}) | ||
}; | ||
return newState; | ||
} | ||
componentWillUnmount() { | ||
this.context.removeViewStack(this.id); | ||
} | ||
renderChild(item) { | ||
const component = React.cloneElement(item.element, { | ||
location: item.location, | ||
computedMatch: item.match | ||
@@ -744,73 +627,15 @@ }); | ||
} | ||
activateView(el) { | ||
/** | ||
* Gets called from StackItem to initialize a new view | ||
*/ | ||
if (!this.state.direction) { | ||
const leavingEl = (this.leavingEl.current != null) ? this.leavingEl.current : undefined; | ||
this.transitionView(el, leavingEl); | ||
} | ||
} | ||
transitionView(enteringEl, leavingEl) { | ||
// | ||
/** | ||
* Super hacky workaround to make sure containerEL is available | ||
* since activateView might be called from StackItem before IonRouterOutlet is mounted | ||
*/ | ||
if (this.containerEl && this.containerEl.current && this.containerEl.current.componentOnReady) { | ||
this.commitView(enteringEl, leavingEl); | ||
} | ||
else { | ||
setTimeout(() => { | ||
this.transitionView(enteringEl, leavingEl); | ||
}, 10); | ||
} | ||
} | ||
async commitView(enteringEl, leavingEl) { | ||
if (!this.inTransition) { | ||
this.inTransition = true; | ||
await this.containerEl.current.componentOnReady(); | ||
await this.containerEl.current.commit(enteringEl, leavingEl, { | ||
deepWait: true, | ||
duration: this.state.direction === undefined ? 0 : undefined, | ||
direction: this.state.direction, | ||
showGoBack: this.state.direction === 'forward', | ||
progressAnimation: false | ||
}); | ||
if (leavingEl) { | ||
/** | ||
* add hidden attributes | ||
*/ | ||
leavingEl.classList.add('ion-page-hidden'); | ||
leavingEl.setAttribute('aria-hidden', 'true'); | ||
} | ||
this.inTransition = false; | ||
} | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
/** | ||
* Don't transition the view if the state didn't change | ||
* Probably means we are still on the same view | ||
*/ | ||
if (prevState !== this.state) { | ||
const enteringEl = (this.enteringEl.current != null) ? this.enteringEl.current : undefined; | ||
const leavingEl = (this.leavingEl.current != null) ? this.leavingEl.current : undefined; | ||
this.transitionView(enteringEl, leavingEl); | ||
} | ||
} | ||
render() { | ||
return (React.createElement(IonRouterOutletInner, { ref: this.containerEl }, | ||
React.createElement(NavContext.Provider, { value: { goBack: this.goBack } }, this.state.views.map((item) => { | ||
return (React.createElement(NavContext.Consumer, null, context => { | ||
this.context = context; | ||
const viewStack = context.viewStacks[this.id]; | ||
const activeId = viewStack ? viewStack.activeId : ''; | ||
const views = (viewStack || { views: [] }).views.filter(x => x.show); | ||
return (React.createElement(IonRouterOutletInner, { "data-id": this.id, ref: this.containerEl }, views.map((item) => { | ||
let props = {}; | ||
if (item.id === this.state.prevActiveId) { | ||
if (item.id === activeId) { | ||
props = { | ||
'ref': this.leavingEl | ||
'className': ' ion-page-invisible' | ||
}; | ||
} | ||
else if (item.id === this.state.activeId) { | ||
props = { | ||
'ref': this.enteringEl, | ||
'className': (this.state.direction != null ? ' ion-page-invisible' : '') | ||
}; | ||
} | ||
else { | ||
@@ -822,8 +647,9 @@ props = { | ||
} | ||
return (React.createElement(StackItemManager, { key: item.id, mount: item.mount }, | ||
React.createElement(StackItem, Object.assign({ activateView: this.activateView }, props), this.renderChild(item)))); | ||
})))); | ||
return (React.createElement(ViewItemManager, { id: item.id, key: item.key, mount: item.mount }, | ||
React.createElement(View, Object.assign({ ref: item.ref }, props), this.renderChild(item)))); | ||
}))); | ||
})); | ||
} | ||
} | ||
const IonRouterOutlet = /*@__PURE__*/ reactRouter.withRouter(RouterOutlet); | ||
const IonRouterOutlet = /*@__PURE__*/ reactRouter.withRouter(IonRouterOutletUnWrapped); | ||
@@ -883,3 +709,220 @@ const hostStyles = { | ||
ionicons.addIcons(icons.ICON_PATHS); | ||
class IonRouter extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.goBack = (defaultHref) => { | ||
const { view: leavingView } = this.findViewInfoByLocation(this.props.location, this.state.viewStacks); | ||
if (leavingView) { | ||
const { view: enteringView } = this.findViewInfoById(leavingView.prevId, this.state.viewStacks); | ||
if (enteringView) { | ||
this.props.history.replace(enteringView.match.url, { direction: 'back' }); | ||
} | ||
else { | ||
this.props.history.replace(defaultHref, { direction: 'back' }); | ||
} | ||
} | ||
else { | ||
this.props.history.replace(defaultHref, { direction: 'back' }); | ||
} | ||
}; | ||
this.state = { | ||
viewStacks: {}, | ||
hideView: this.hideView.bind(this), | ||
registerViewStack: this.registerView.bind(this), | ||
removeViewStack: this.removeViewStack.bind(this), | ||
goBack: this.goBack.bind(this), | ||
transitionView: this.transitionView.bind(this) | ||
}; | ||
} | ||
componentWillMount() { | ||
this.listenUnregisterCallback = this.props.history.listen(this.historyChange.bind(this)); | ||
} | ||
hideView(viewId) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
const { view } = this.findViewInfoById(viewId, viewStacks); | ||
if (view) { | ||
view.show = false; | ||
view.key = generateUniqueId(); | ||
this.setState({ | ||
viewStacks | ||
}); | ||
} | ||
} | ||
historyChange(location, action) { | ||
this.setActiveView(location, action); | ||
} | ||
findViewInfoByLocation(location, viewStacks) { | ||
let view; | ||
let match; | ||
let viewStack; | ||
const keys = Object.keys(viewStacks); | ||
keys.some(key => { | ||
const vs = viewStacks[key]; | ||
return vs.views.some(x => { | ||
match = reactRouterDom.matchPath(location.pathname, x.childProps); | ||
if (match) { | ||
view = x; | ||
viewStack = vs; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
}); | ||
const result = { view, viewStack, match }; | ||
return result; | ||
} | ||
findViewInfoById(id, viewStacks) { | ||
let view; | ||
let viewStack; | ||
const keys = Object.keys(viewStacks); | ||
keys.some(key => { | ||
const vs = viewStacks[key]; | ||
view = vs.views.find(x => x.id === id); | ||
if (view) { | ||
viewStack = vs; | ||
return true; | ||
} | ||
else { | ||
return false; | ||
} | ||
}); | ||
return { view, viewStack }; | ||
} | ||
setActiveView(location, action) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
const { view: enteringView, viewStack: enteringViewStack, match } = this.findViewInfoByLocation(location, viewStacks); | ||
let direction = location.state && location.state.direction; | ||
if (!enteringViewStack) { | ||
return; | ||
} | ||
const { view: leavingView } = this.findViewInfoById(this.activeViewId, viewStacks); | ||
if (leavingView && leavingView.match.url === location.pathname) { | ||
return; | ||
} | ||
if (enteringView) { | ||
/** | ||
* If the page is being pushed into the stack by another view, | ||
* record the view that originally directed to the new view for back button purposes. | ||
*/ | ||
if (!enteringView.show && action === 'PUSH') { | ||
enteringView.prevId = leavingView && leavingView.id; | ||
} | ||
enteringView.show = true; | ||
enteringView.mount = true; | ||
enteringView.match = match; | ||
enteringViewStack.activeId = enteringView.id; | ||
this.activeViewId = enteringView.id; | ||
if (leavingView) { | ||
this.prevViewId = leavingView.id; | ||
if (leavingView.match.params.tab === enteringView.match.params.tab) { | ||
if (action === 'PUSH') { | ||
direction = direction || 'forward'; | ||
} | ||
else { | ||
direction = direction || 'back'; | ||
leavingView.mount = false; | ||
} | ||
} | ||
/** | ||
* Attempt to determine if the leaving view is a route redirect. | ||
* If it is, take it out of the rendering phase. | ||
* We assume Routes with render props are redirects, because of this users should not use | ||
* the render prop for non redirects, and instead provide a component in its place. | ||
*/ | ||
if (leavingView.element.type === reactRouterDom.Redirect || leavingView.element.props.render) { | ||
leavingView.mount = false; | ||
leavingView.show = false; | ||
} | ||
} | ||
this.setState({ | ||
viewStacks | ||
}, () => { | ||
const enteringEl = enteringView.ref && enteringView.ref.current ? enteringView.ref.current : undefined; | ||
const leavingEl = leavingView && leavingView.ref && leavingView.ref.current ? leavingView.ref.current : undefined; | ||
this.transitionView(enteringEl, leavingEl, enteringViewStack.routerOutlet, direction); | ||
}); | ||
} | ||
} | ||
componentWillUnmount() { | ||
this.listenUnregisterCallback(); | ||
} | ||
registerView(stack, activeId, stackItems, routerOutlet, location) { | ||
this.setState((prevState) => { | ||
const prevViewStacks = Object.assign({}, prevState.viewStacks); | ||
prevViewStacks[stack] = { | ||
activeId: activeId, | ||
views: stackItems, | ||
routerOutlet | ||
}; | ||
return { | ||
viewStacks: prevViewStacks | ||
}; | ||
}, () => { | ||
const { view: activeView } = this.findViewInfoById(activeId, this.state.viewStacks); | ||
if (activeView) { | ||
this.prevViewId = this.activeViewId; | ||
this.activeViewId = activeView.id; | ||
const direction = location.state && location.state.direction; | ||
const { view: prevView } = this.findViewInfoById(this.prevViewId, this.state.viewStacks); | ||
this.transitionView(activeView.ref.current, prevView && prevView.ref.current || undefined, routerOutlet, direction); | ||
} | ||
}); | ||
} | ||
; | ||
removeViewStack(stack) { | ||
const viewStacks = Object.assign({}, this.state.viewStacks); | ||
delete viewStacks[stack]; | ||
this.setState({ | ||
viewStacks | ||
}); | ||
} | ||
findActiveView(views) { | ||
let view; | ||
views.some(x => { | ||
const match = reactRouterDom.matchPath(this.props.location.pathname, x.childProps); | ||
if (match) { | ||
view = x; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return view; | ||
} | ||
transitionView(enteringEl, leavingEl, ionRouterOuter, direction) { | ||
/** | ||
* Super hacky workaround to make sure ionRouterOutlet is available | ||
* since transitionView might be called before IonRouterOutlet is fully mounted | ||
*/ | ||
if (ionRouterOuter && ionRouterOuter.componentOnReady) { | ||
this.commitView(enteringEl, leavingEl, ionRouterOuter, direction); | ||
} | ||
else { | ||
setTimeout(() => { | ||
this.transitionView(enteringEl, leavingEl, ionRouterOuter, direction); | ||
}, 10); | ||
} | ||
} | ||
async commitView(enteringEl, leavingEl, ionRouterOuter, direction) { | ||
await ionRouterOuter.componentOnReady(); | ||
await ionRouterOuter.commit(enteringEl, leavingEl, { | ||
deepWait: true, | ||
duration: direction === undefined ? 0 : undefined, | ||
direction: direction, | ||
showGoBack: direction === 'forward', | ||
progressAnimation: false | ||
}); | ||
if (leavingEl && (enteringEl !== leavingEl)) { | ||
/** | ||
* add hidden attributes | ||
*/ | ||
leavingEl.classList.add('ion-page-hidden'); | ||
leavingEl.setAttribute('aria-hidden', 'true'); | ||
} | ||
} | ||
render() { | ||
return (React.createElement(NavContext.Provider, { value: this.state }, this.props.children)); | ||
} | ||
} | ||
const IonRouterWrapped = reactRouterDom.withRouter(IonRouter); | ||
loader.defineCustomElements(window); | ||
@@ -954,2 +997,3 @@ | ||
exports.IonRippleEffect = IonRippleEffect; | ||
exports.IonRouter = IonRouterWrapped; | ||
exports.IonRouterOutlet = IonRouterOutlet; | ||
@@ -956,0 +1000,0 @@ exports.IonRouterOutletInner = IonRouterOutletInner; |
@@ -14,1 +14,2 @@ export { AlertButton, AlertInput } from '@ionic/core'; | ||
export { IonBackButton } from './navigation/IonBackButton'; | ||
export { IonRouterWrapped as IonRouter } from './navigation/IonRouter'; |
import React from 'react'; | ||
import { RouteComponentProps, match, RouteProps } from 'react-router'; | ||
import { RouteComponentProps, RouteProps, match } from 'react-router'; | ||
declare type ChildProps = RouteProps & { | ||
@@ -7,5 +7,6 @@ computedMatch: match<any>; | ||
declare type IonRouterOutletProps = RouteComponentProps & { | ||
id?: string; | ||
children?: React.ReactElement<ChildProps>[] | React.ReactElement<ChildProps>; | ||
}; | ||
export declare const IonRouterOutlet: React.ComponentClass<Pick<IonRouterOutletProps, "children">, any>; | ||
export declare const IonRouterOutlet: React.ComponentClass<Pick<IonRouterOutletProps, "id" | "children">, any>; | ||
export {}; |
import React from 'react'; | ||
interface NavContextInterface { | ||
import { ViewItem } from './ViewItem'; | ||
import { NavDirection } from '@ionic/core'; | ||
import { Location } from 'history'; | ||
export interface ViewStack { | ||
routerOutlet: HTMLIonRouterOutletElement; | ||
activeId?: string; | ||
views: ViewItem[]; | ||
} | ||
export interface ViewStacks { | ||
[key: string]: ViewStack; | ||
} | ||
export interface NavContextState { | ||
hideView: (viewId: string) => void; | ||
viewStacks: ViewStacks; | ||
registerViewStack: (stack: string, activeId: string, stackItems: ViewItem[], ionRouterOutlet: HTMLIonRouterOutletElement, location: Location) => void; | ||
removeViewStack: (stack: string) => void; | ||
goBack: (defaultHref?: string) => void; | ||
transitionView: (enteringEl: HTMLElement, leavingEl: HTMLElement, ionRouterOuter: HTMLIonRouterOutletElement, direction: NavDirection) => void; | ||
} | ||
export declare const NavContext: React.Context<NavContextInterface>; | ||
export {}; | ||
export declare const NavContext: React.Context<NavContextState>; |
{ | ||
"name": "@ionic/react", | ||
"version": "0.0.6-3", | ||
"version": "0.0.6-4", | ||
"description": "React specific wrapper for @ionic/core", | ||
@@ -39,4 +39,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@ionic/core": "4.5.0-dev.201906101548.7af9cb2", | ||
"tslib": "^1.9.3" | ||
"@ionic/core": "^4.6.0-dev.201906192117.6727cfc", | ||
"tslib": "^1.10.0" | ||
}, | ||
@@ -67,2 +67,3 @@ "peerDependencies": { | ||
"rollup-plugin-node-resolve": "^5.0.1", | ||
"rollup-plugin-sourcemaps": "^0.4.2", | ||
"ts-jest": "^24.0.2", | ||
@@ -69,0 +70,0 @@ "typescript": "3.5.1" |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
452079
35
4108
20
1
+ Added@ionic/core@4.11.13(transitive)
+ Addedionicons@4.6.3(transitive)
- Removed@ionic/core@4.5.0-dev.201906101548.7af9cb2(transitive)
- Removedionicons@4.5.9-1(transitive)
Updatedtslib@^1.10.0