release-4.11.9

This commit is contained in:
Ely Lucas 2020-01-23 13:56:20 -07:00 committed by GitHub
commit 445f129e2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 102 additions and 42 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 {
/**

View File

@ -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() {

View File

@ -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

View File

@ -1,6 +1,6 @@
import { RouteProps, match } from 'react-router-dom';
export interface IonRouteData {
match: match<{ tab: string }> | null;
match: match | null;
childProps: RouteProps;
}

View File

@ -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;
}
}

View File

@ -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}

View File

@ -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;
}

View File

@ -6,7 +6,7 @@ export interface ActionSheetButton extends Omit<ActionSheetButtonCore, 'icon'> {
icon?: {
ios: string;
md: string;
};
} | string;
}
export interface ActionSheetOptions extends Omit<ActionSheetOptionsCore, 'buttons'> {

View File

@ -6,7 +6,7 @@ export interface ToastButton extends Omit<ToastButtonCore, 'icon'> {
icon?: {
ios: string;
md: string;
};
} | string;
}
export interface ToastOptions extends Omit<ToastOptionsCore, 'buttons'> {

View File

@ -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.

View File

@ -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
);
}

View File

@ -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';

View File

@ -9,7 +9,7 @@ type Props = Omit<LocalJSX.IonBackButton, 'icon'> & IonicReactProps & {
icon?: {
ios: string;
md: string;
};
} | string;
ref?: React.RefObject<HTMLIonBackButtonElement>;
};