release-4.11.9
This commit is contained in:
commit
445f129e2d
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,3 +1,16 @@
|
|||
## [4.11.9](https://github.com/ionic-team/ionic/compare/v4.11.8...v4.11.9) (2020-01-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** updating type of input value to accept numbers, fixes [#20173](https://github.com/ionic-team/ionic/issues/20173) ([#20267](https://github.com/ionic-team/ionic/issues/20267)) ([7080205](https://github.com/ionic-team/ionic/commit/708020551f9c51ca3b32d7b49bf4572db3dda12e))
|
||||
* **react:** adding missing overlay component events, fixes [#19923](https://github.com/ionic-team/ionic/issues/19923) ([#20266](https://github.com/ionic-team/ionic/issues/20266)) ([ec6a8dd](https://github.com/ionic-team/ionic/commit/ec6a8dd86f3854edba367f79a6ebac7d60eed839))
|
||||
* **react:** Don't render overlay children if isOpen is false, fixes [#20225](https://github.com/ionic-team/ionic/issues/20225) ([#20226](https://github.com/ionic-team/ionic/issues/20226)) ([aff9612](https://github.com/ionic-team/ionic/commit/aff9612d1197dca48eab6eff9d749032c380cf82))
|
||||
* **react:** re attach props on update, fixes 20192 ([#20228](https://github.com/ionic-team/ionic/issues/20228)) ([9e35ebe](https://github.com/ionic-team/ionic/commit/9e35ebed4a1590ef2521f5f8c393bdd9dea32a04))
|
||||
* **react:** remove leaving view when routerdirection is back, fixes [#20124](https://github.com/ionic-team/ionic/issues/20124) ([#20268](https://github.com/ionic-team/ionic/issues/20268)) ([63d4e87](https://github.com/ionic-team/ionic/commit/63d4e877fb18c90d70c4cbd5f66ffccb8ee6489c))
|
||||
* **react:** support routes without a path for notfound routes, fixes [#20259](https://github.com/ionic-team/ionic/issues/20259) ([#20261](https://github.com/ionic-team/ionic/issues/20261)) ([2f8c13b](https://github.com/ionic-team/ionic/commit/2f8c13b6960f9bcfb941c36fa6e1742b96f80ba9))
|
||||
* **react:** update icon types to be a string as well, fixes [#20229](https://github.com/ionic-team/ionic/issues/20229) ([#20230](https://github.com/ionic-team/ionic/issues/20230)) ([1411d8a](https://github.com/ionic-team/ionic/commit/1411d8a173bfefd7db5241218fd5641b7e9da823))
|
||||
|
||||
|
||||
# [5.0.0-beta.5](https://github.com/ionic-team/ionic/compare/v4.11.8...v5.0.0-beta.5) (2020-01-17)
|
||||
|
||||
|
||||
|
|
|
@ -435,7 +435,7 @@ ion-input,prop,size,number | undefined,undefined,false,false
|
|||
ion-input,prop,spellcheck,boolean,false,false,false
|
||||
ion-input,prop,step,string | undefined,undefined,false,false
|
||||
ion-input,prop,type,"date" | "email" | "number" | "password" | "search" | "tel" | "text" | "time" | "url",'text',false,false
|
||||
ion-input,prop,value,null | string | undefined,'',false,false
|
||||
ion-input,prop,value,null | number | string | undefined,'',false,false
|
||||
ion-input,method,getInputElement,getInputElement() => Promise<HTMLInputElement>
|
||||
ion-input,method,setFocus,setFocus() => Promise<void>
|
||||
ion-input,event,ionBlur,void,true
|
||||
|
|
|
@ -978,7 +978,7 @@ export namespace Components {
|
|||
/**
|
||||
* The value of the input.
|
||||
*/
|
||||
'value'?: string | null;
|
||||
'value'?: string | number | null;
|
||||
}
|
||||
interface IonItem {
|
||||
/**
|
||||
|
@ -4232,7 +4232,7 @@ declare namespace LocalJSX {
|
|||
/**
|
||||
* The value of the input.
|
||||
*/
|
||||
'value'?: string | null;
|
||||
'value'?: string | number | null;
|
||||
}
|
||||
interface IonItem {
|
||||
/**
|
||||
|
|
|
@ -169,7 +169,7 @@ export class Input implements ComponentInterface {
|
|||
/**
|
||||
* The value of the input.
|
||||
*/
|
||||
@Prop({ mutable: true }) value?: string | null = '';
|
||||
@Prop({ mutable: true }) value?: string | number | null = '';
|
||||
|
||||
/**
|
||||
* Update the native input element when the value changes
|
||||
|
@ -177,7 +177,7 @@ export class Input implements ComponentInterface {
|
|||
@Watch('value')
|
||||
protected valueChanged() {
|
||||
this.emitStyle();
|
||||
this.ionChange.emit({ value: this.value });
|
||||
this.ionChange.emit({ value: this.value == null ? this.value : this.value.toString() });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,7 +263,8 @@ export class Input implements ComponentInterface {
|
|||
}
|
||||
|
||||
private getValue(): string {
|
||||
return this.value || '';
|
||||
return typeof this.value === 'number' ? this.value.toString() :
|
||||
(this.value || '').toString();
|
||||
}
|
||||
|
||||
private emitStyle() {
|
||||
|
|
|
@ -238,7 +238,7 @@ export const InputExample: React.FC = () => (
|
|||
| `spellcheck` | `spellcheck` | If `true`, the element will have its spelling and grammar checked. | `boolean` | `false` |
|
||||
| `step` | `step` | Works with the min and max attributes to limit the increments at which a value can be set. Possible values are: `"any"` or a positive floating point number. | `string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of control to display. The default type is text. | `"date" \| "email" \| "number" \| "password" \| "search" \| "tel" \| "text" \| "time" \| "url"` | `'text'` |
|
||||
| `value` | `value` | The value of the input. | `null \| string \| undefined` | `''` |
|
||||
| `value` | `value` | The value of the input. | `null \| number \| string \| undefined` | `''` |
|
||||
|
||||
|
||||
## Events
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { RouteProps, match } from 'react-router-dom';
|
||||
|
||||
export interface IonRouteData {
|
||||
match: match<{ tab: string }> | null;
|
||||
match: match | null;
|
||||
childProps: RouteProps;
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
|
|||
* record the view that originally directed to the new view for back button purposes.
|
||||
*/
|
||||
enteringView.prevId = leavingView.id;
|
||||
} else if (action === 'pop' || action === 'replace') {
|
||||
} else {
|
||||
leavingView.mount = false;
|
||||
this.removeOrphanedViews(enteringView, enteringViewStack);
|
||||
}
|
||||
|
@ -255,12 +255,23 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
|
|||
const views: ViewItem[] = [];
|
||||
let activeId: string | undefined;
|
||||
const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
|
||||
let foundMatch = false;
|
||||
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
|
||||
const routeId = generateId();
|
||||
this.routes[routeId] = child;
|
||||
views.push(createViewItem(child, routeId, this.props.history.location));
|
||||
});
|
||||
|
||||
if (!foundMatch) {
|
||||
const notFoundRoute = views.find(r => {
|
||||
// try to find a route that doesn't have a path or from prop, that will be our not found route
|
||||
return !r.routeData.childProps.path && !r.routeData.childProps.from;
|
||||
});
|
||||
if (notFoundRoute) {
|
||||
notFoundRoute.show = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.registerViewStack(id, activeId, views, routerOutlet, this.props.location);
|
||||
|
||||
function createViewItem(child: React.ReactElement<any>, routeId: string, location: HistoryLocation) {
|
||||
|
@ -289,6 +300,9 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
|
|||
if (match && view.isIonRoute) {
|
||||
activeId = viewId;
|
||||
}
|
||||
if (!foundMatch && match) {
|
||||
foundMatch = true;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +374,7 @@ export class RouteManager extends React.Component<RouteManagerProps, RouteManage
|
|||
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
|
||||
for (const routeKey in this.routes) {
|
||||
const route = this.routes[routeKey];
|
||||
if (route.props.path === child.props.path) {
|
||||
if (typeof route.props.path !== 'undefined' && route.props.path === (child.props.path || child.props.from)) {
|
||||
this.routes[routeKey] = child;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ export class View extends React.Component<ViewProps, {}> {
|
|||
...value,
|
||||
registerIonPage: this.registerIonPage.bind(this)
|
||||
};
|
||||
|
||||
return (
|
||||
<NavContext.Provider value={newProvider}>
|
||||
{this.props.children}
|
||||
|
|
|
@ -13,7 +13,7 @@ export interface ViewStack {
|
|||
* The holistic view of all the Routes configured for an application inside of an IonRouterOutlet.
|
||||
*/
|
||||
export class ViewStacks {
|
||||
private viewStacks: { [key: string]: ViewStack | undefined } = {};
|
||||
private viewStacks: { [key: string]: ViewStack | undefined; } = {};
|
||||
|
||||
get(key: string) {
|
||||
return this.viewStacks[key];
|
||||
|
@ -31,25 +31,34 @@ export class ViewStacks {
|
|||
delete this.viewStacks[key];
|
||||
}
|
||||
|
||||
findViewInfoByLocation(location: HistoryLocation, viewKey?: string) {
|
||||
findViewInfoByLocation(location: HistoryLocation, viewKey: string) {
|
||||
let view: ViewItem<IonRouteData> | undefined;
|
||||
let match: IonRouteData['match'] | null | undefined;
|
||||
let viewStack: ViewStack | undefined;
|
||||
if (viewKey) {
|
||||
viewStack = this.viewStacks[viewKey];
|
||||
if (viewStack) {
|
||||
viewStack.views.some(matchView);
|
||||
|
||||
viewStack = this.viewStacks[viewKey];
|
||||
if (viewStack) {
|
||||
viewStack.views.some(matchView);
|
||||
|
||||
if (!view) {
|
||||
viewStack.views.some(r => {
|
||||
// try to find a route that doesn't have a path or from prop, that will be our not found route
|
||||
if (!r.routeData.childProps.path && !r.routeData.childProps.from) {
|
||||
match = {
|
||||
path: location.pathname,
|
||||
url: location.pathname,
|
||||
isExact: true,
|
||||
params: {}
|
||||
};
|
||||
view = r;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const keys = this.getKeys();
|
||||
keys.some(key => {
|
||||
viewStack = this.viewStacks[key];
|
||||
return viewStack!.views.some(matchView);
|
||||
});
|
||||
}
|
||||
|
||||
const result = { view, viewStack, match };
|
||||
return result;
|
||||
return { view, viewStack, match };
|
||||
|
||||
function matchView(v: ViewItem) {
|
||||
const matchProps = {
|
||||
|
@ -61,7 +70,7 @@ export class ViewStacks {
|
|||
if (myMatch) {
|
||||
view = v;
|
||||
match = myMatch;
|
||||
return view.location === location.pathname;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ export interface ActionSheetButton extends Omit<ActionSheetButtonCore, 'icon'> {
|
|||
icon?: {
|
||||
ios: string;
|
||||
md: string;
|
||||
};
|
||||
} | string;
|
||||
}
|
||||
|
||||
export interface ActionSheetOptions extends Omit<ActionSheetOptionsCore, 'buttons'> {
|
||||
|
|
|
@ -6,7 +6,7 @@ export interface ToastButton extends Omit<ToastButtonCore, 'icon'> {
|
|||
icon?: {
|
||||
ios: string;
|
||||
md: string;
|
||||
};
|
||||
} | string;
|
||||
}
|
||||
|
||||
export interface ToastOptions extends Omit<ToastOptionsCore, 'buttons'> {
|
||||
|
|
|
@ -11,13 +11,19 @@ interface OverlayBase extends HTMLElement {
|
|||
export interface ReactControllerProps {
|
||||
isOpen: boolean;
|
||||
onDidDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onDidPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onWillDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onWillPresent?: (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`;
|
||||
const didDismissEventName = `on${displayName}DidDismiss`;
|
||||
const didPresentEventName = `on${displayName}DidPresent`;
|
||||
const willDismissEventName = `on${displayName}WillDismiss`;
|
||||
const willPresentEventName = `on${displayName}WillPresent`;
|
||||
|
||||
type Props = OptionsType & ReactControllerProps & {
|
||||
forwardedRef?: React.RefObject<OverlayType>;
|
||||
|
@ -67,12 +73,15 @@ export const createControllerComponent = <OptionsType extends object, OverlayTyp
|
|||
}
|
||||
|
||||
async present(prevProps?: Props) {
|
||||
const { isOpen, onDidDismiss, ...cProps } = this.props;
|
||||
const { isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props;
|
||||
this.overlay = await controller.create({
|
||||
...cProps as any
|
||||
});
|
||||
attachProps(this.overlay, {
|
||||
[dismissEventName]: this.handleDismiss
|
||||
[didDismissEventName]: this.handleDismiss,
|
||||
[didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e),
|
||||
[willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e),
|
||||
[willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e)
|
||||
}, 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.
|
||||
|
|
|
@ -13,13 +13,19 @@ export interface ReactOverlayProps {
|
|||
children?: React.ReactNode;
|
||||
isOpen: boolean;
|
||||
onDidDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onDidPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onWillDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
onWillPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||
}
|
||||
|
||||
export const createOverlayComponent = <OverlayComponent extends object, OverlayType extends OverlayElement>(
|
||||
displayName: string,
|
||||
controller: { create: (options: any) => Promise<OverlayType>; }
|
||||
) => {
|
||||
const dismissEventName = `on${displayName}DidDismiss`;
|
||||
const didDismissEventName = `on${displayName}DidDismiss`;
|
||||
const didPresentEventName = `on${displayName}DidPresent`;
|
||||
const willDismissEventName = `on${displayName}WillDismiss`;
|
||||
const willPresentEventName = `on${displayName}WillPresent`;
|
||||
|
||||
type Props = OverlayComponent & ReactOverlayProps & {
|
||||
forwardedRef?: React.RefObject<OverlayType>;
|
||||
|
@ -40,7 +46,7 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.isOpen as boolean) {
|
||||
if (this.props.isOpen) {
|
||||
this.present();
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +65,10 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
|
|||
}
|
||||
|
||||
async componentDidUpdate(prevProps: Props) {
|
||||
if (this.overlay) {
|
||||
attachProps(this.overlay, this.props, prevProps);
|
||||
}
|
||||
|
||||
if (prevProps.isOpen !== this.props.isOpen && this.props.isOpen === true) {
|
||||
this.present(prevProps);
|
||||
}
|
||||
|
@ -68,31 +78,34 @@ export const createOverlayComponent = <OverlayComponent extends object, OverlayT
|
|||
}
|
||||
|
||||
async present(prevProps?: Props) {
|
||||
const { children, isOpen, onDidDismiss, ...cProps } = this.props;
|
||||
const { children, isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props;
|
||||
const elementProps = {
|
||||
...cProps,
|
||||
ref: this.props.forwardedRef,
|
||||
[dismissEventName]: this.handleDismiss
|
||||
[didDismissEventName]: this.handleDismiss,
|
||||
[didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e),
|
||||
[willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e),
|
||||
[willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e)
|
||||
};
|
||||
|
||||
const overlay = this.overlay = await controller.create({
|
||||
this.overlay = await controller.create({
|
||||
...elementProps,
|
||||
component: this.el,
|
||||
componentProps: {}
|
||||
});
|
||||
|
||||
if (this.props.forwardedRef) {
|
||||
(this.props.forwardedRef as any).current = overlay;
|
||||
(this.props.forwardedRef as any).current = this.overlay;
|
||||
}
|
||||
|
||||
attachProps(overlay, elementProps, prevProps);
|
||||
attachProps(this.overlay, elementProps, prevProps);
|
||||
|
||||
await overlay.present();
|
||||
await this.overlay.present();
|
||||
}
|
||||
|
||||
render() {
|
||||
return ReactDOM.createPortal(
|
||||
this.props.children,
|
||||
this.props.isOpen ? this.props.children : null,
|
||||
this.el
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ export * from './proxies';
|
|||
// createControllerComponent
|
||||
export { IonAlert } from './IonAlert';
|
||||
export { IonLoading } from './IonLoading';
|
||||
export { IonToast } from './IonToast';
|
||||
export * from './IonToast';
|
||||
export { IonPicker } from './IonPicker';
|
||||
|
||||
// createOverlayComponent
|
||||
export { IonActionSheet } from './IonActionSheet';
|
||||
export * from './IonActionSheet';
|
||||
export { IonModal } from './IonModal';
|
||||
export { IonPopover } from './IonPopover';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ type Props = Omit<LocalJSX.IonBackButton, 'icon'> & IonicReactProps & {
|
|||
icon?: {
|
||||
ios: string;
|
||||
md: string;
|
||||
};
|
||||
} | string;
|
||||
ref?: React.RefObject<HTMLIonBackButtonElement>;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue