Skip to content

Commit

Permalink
refactor(modal): remove swipeToClose in favor of canDismiss (#26050)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

- The `swipeToClose` property has been removed in favor of `canDismiss`.
- The `canDismiss` property now defaults to `true` and can no longer be set to `undefined`.
  • Loading branch information
liamdebeasi committed Sep 29, 2022
1 parent 219a205 commit 1f3ddf2
Show file tree
Hide file tree
Showing 12 changed files with 20 additions and 80 deletions.
6 changes: 6 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Accordion Group](#version-7x-accordion-group)
- [Checkbox](#version-7x-checkbox)
- [Input](#version-7x-input)
- [Modal](#version-7x-modal)
- [Overlays](#version-7x-overlays)
- [Range](#version-7x-range)
- [Segment](#version-7x-segment)
Expand Down Expand Up @@ -71,6 +72,11 @@ This section details the desktop browser, JavaScript framework, and mobile platf

- The `debounce` property has been updated to control the timing in milliseconds to delay the event emission of the `ionInput` event after each keystroke. Previously it would delay the event emission of `ionChange`.

<h4 id="version-7x-modal">Modal</h4>

- The `swipeToClose` property has been removed in favor of `canDismiss`.
- The `canDismiss` property now defaults to `true` and can no longer be set to `undefined`.

<h4 id="version-7x-overlays">Overlays</h4>

Ionic now listens on the `keydown` event instead of the `keyup` event when determining when to dismiss overlays via the "Escape" key. Any applications that were listening on `keyup` to suppress this behavior should listen on `keydown` instead.
Expand Down
2 changes: 0 additions & 2 deletions angular/src/directives/overlays/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ export declare interface IonModal extends Components.IonModal {
'mode',
'presentingElement',
'showBackdrop',
'swipeToClose',
'translucent',
'trigger',
],
Expand Down Expand Up @@ -102,7 +101,6 @@ export declare interface IonModal extends Components.IonModal {
'mode',
'presentingElement',
'showBackdrop',
'swipeToClose',
'translucent',
'trigger',
],
Expand Down
3 changes: 1 addition & 2 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ ion-modal,prop,animated,boolean,true,false,false
ion-modal,prop,backdropBreakpoint,number,0,false,false
ion-modal,prop,backdropDismiss,boolean,true,false,false
ion-modal,prop,breakpoints,number[] | undefined,undefined,false,false
ion-modal,prop,canDismiss,(() => Promise<boolean>) | boolean | undefined,undefined,false,false
ion-modal,prop,canDismiss,(() => Promise<boolean>) | boolean,true,false,false
ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-modal,prop,handle,boolean | undefined,undefined,false,false
ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'none',false,false
Expand All @@ -791,7 +791,6 @@ ion-modal,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefin
ion-modal,prop,mode,"ios" | "md",undefined,false,false
ion-modal,prop,presentingElement,HTMLElement | undefined,undefined,false,false
ion-modal,prop,showBackdrop,boolean,true,false,false
ion-modal,prop,swipeToClose,boolean,false,false,false
ion-modal,prop,trigger,string | undefined,undefined,false,false
ion-modal,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-modal,method,getCurrentBreakpoint,getCurrentBreakpoint() => Promise<number | undefined>
Expand Down
14 changes: 2 additions & 12 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,7 @@ export namespace Components {
/**
* Determines whether or not a modal can dismiss when calling the `dismiss` method. If the value is `true` or the value's function returns `true`, the modal will close when trying to dismiss. If the value is `false` or the value's function returns `false`, the modal will not close when trying to dismiss.
*/
"canDismiss"?: undefined | boolean | (() => Promise<boolean>);
"canDismiss": boolean | (() => Promise<boolean>);
/**
* The component to display inside of the modal.
*/
Expand Down Expand Up @@ -1637,11 +1637,6 @@ export namespace Components {
* If `true`, a backdrop will be displayed behind the modal. This property controls whether or not the backdrop darkens the screen when the modal is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop": boolean;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
* @deprecated - To prevent modals from dismissing, use canDismiss instead.
*/
"swipeToClose": boolean;
/**
* An ID corresponding to the trigger element that causes the modal to open when clicked.
*/
Expand Down Expand Up @@ -5332,7 +5327,7 @@ declare namespace LocalJSX {
/**
* Determines whether or not a modal can dismiss when calling the `dismiss` method. If the value is `true` or the value's function returns `true`, the modal will close when trying to dismiss. If the value is `false` or the value's function returns `false`, the modal will not close when trying to dismiss.
*/
"canDismiss"?: undefined | boolean | (() => Promise<boolean>);
"canDismiss"?: boolean | (() => Promise<boolean>);
/**
* The component to display inside of the modal.
*/
Expand Down Expand Up @@ -5432,11 +5427,6 @@ declare namespace LocalJSX {
* If `true`, a backdrop will be displayed behind the modal. This property controls whether or not the backdrop darkens the screen when the modal is presented. It does not control whether or not the backdrop is active or present in the DOM.
*/
"showBackdrop"?: boolean;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
* @deprecated - To prevent modals from dismissing, use canDismiss instead.
*/
"swipeToClose"?: boolean;
/**
* An ID corresponding to the trigger element that causes the modal to open when clicked.
*/
Expand Down
5 changes: 0 additions & 5 deletions core/src/components/modal/modal-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ export interface ModalOptions<T extends ComponentRef = ComponentRef> {
cssClass?: string | string[];
delegate?: FrameworkDelegate;
animated?: boolean;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
* @deprecated - To prevent modals from dismissing, use canDismiss instead.
*/
swipeToClose?: boolean;
canDismiss?: boolean | (() => Promise<boolean>);

mode?: Mode;
Expand Down
63 changes: 10 additions & 53 deletions core/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;

/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
* @deprecated - To prevent modals from dismissing, use canDismiss instead.
*/
@Prop() swipeToClose = false;

/**
* The element that presented the modal. This is used for card presentation effects
* and for stacking multiple modals on top of each other. Only applies in iOS mode.
Expand Down Expand Up @@ -250,22 +244,14 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Prop() keepContentsMounted = false;

/**
* TODO (FW-937)
* This needs to default to true in the next
* major release. We default it to undefined
* so we can force the card modal to be swipeable
* when using canDismiss.
*/

/**
* Determines whether or not a modal can dismiss
* when calling the `dismiss` method.
*
* If the value is `true` or the value's function returns `true`, the modal will close when trying to dismiss.
* If the value is `false` or the value's function returns `false`, the modal will not close when trying to dismiss.
*/
@Prop() canDismiss?: undefined | boolean | (() => Promise<boolean>);
@Prop() canDismiss: boolean | (() => Promise<boolean>) = true;

/**
* Emitted after the modal has presented.
Expand Down Expand Up @@ -316,15 +302,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Event({ eventName: 'didDismiss' }) didDismissShorthand!: EventEmitter<OverlayEventDetail>;

@Watch('swipeToClose')
async swipeToCloseChanged(enable: boolean) {
if (this.gesture) {
this.gesture.enable(enable);
} else if (enable) {
await this.initSwipeToClose();
}
}

breakpointsChanged(breakpoints: number[] | undefined) {
if (breakpoints !== undefined) {
this.sortedBreakpoints = breakpoints.sort((a, b) => a - b);
Expand All @@ -336,7 +313,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
}

componentWillLoad() {
const { breakpoints, initialBreakpoint, swipeToClose, el } = this;
const { breakpoints, initialBreakpoint, el } = this;

this.inheritedAttributes = inheritAttributes(el, ['role']);

Expand All @@ -354,12 +331,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
if (breakpoints !== undefined && initialBreakpoint !== undefined && !breakpoints.includes(initialBreakpoint)) {
printIonWarning('Your breakpoints array must include the initialBreakpoint value.');
}

if (swipeToClose) {
printIonWarning(
'swipeToClose has been deprecated in favor of canDismiss.\n\nIf you want a card modal to be swipeable, set canDismiss to `true`. In the next major release of Ionic, swipeToClose will be removed, and all card modals will be swipeable by default.'
);
}
}

componentDidLoad() {
Expand Down Expand Up @@ -441,14 +412,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
private async checkCanDismiss() {
const { canDismiss } = this;

/**
* TODO (FW-937) - Remove the following check in
* the next major release of Ionic.
*/
if (canDismiss === undefined) {
return true;
}

if (typeof canDismiss === 'function') {
return canDismiss();
}
Expand All @@ -465,6 +428,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
return;
}

const { presentingElement } = this;

/**
* When using an inline modal
* and dismissing a modal it is possible to
Expand Down Expand Up @@ -496,21 +461,12 @@ export class Modal implements ComponentInterface, OverlayInterface {
writeTask(() => this.el.classList.add('show-modal'));

this.currentTransition = present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, {
presentingEl: this.presentingElement,
presentingEl: presentingElement,
currentBreakpoint: this.initialBreakpoint,
backdropBreakpoint: this.backdropBreakpoint,
});

/**
* TODO (FW-937) - In the next major release of Ionic, all card modals
* will be swipeable by default. canDismiss will be used to determine if the
* modal can be dismissed. This check should change to check the presence of
* presentingElement instead.
*
* If we did not do this check, then not using swipeToClose would mean you could
* not run canDismiss on swipe as there would be no swipe gesture created.
*/
const hasCardModal = this.swipeToClose || (this.canDismiss !== undefined && this.presentingElement !== undefined);
const hasCardModal = presentingElement !== undefined;

/**
* We need to change the status bar at the
Expand Down Expand Up @@ -676,13 +632,14 @@ export class Modal implements ComponentInterface, OverlayInterface {
return false;
}

const { presentingElement } = this;

/**
* We need to start the status bar change
* before the animation so that the change
* finishes when the dismiss animation does.
* TODO (FW-937)
*/
const hasCardModal = this.swipeToClose || (this.canDismiss !== undefined && this.presentingElement !== undefined);
const hasCardModal = presentingElement !== undefined;
if (hasCardModal && getIonMode(this) === 'ios') {
setCardStatusBarDefault();
}
Expand All @@ -707,7 +664,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
const enteringAnimation = activeAnimations.get(this) || [];

this.currentTransition = dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, {
presentingEl: this.presentingElement,
presentingEl: presentingElement,
currentBreakpoint: this.currentBreakpoint || this.initialBreakpoint,
backdropBreakpoint: this.backdropBreakpoint,
});
Expand Down
1 change: 0 additions & 1 deletion core/src/components/modal/test/card-refresher/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
const modalElement = await modalController.create({
presentingElement: presentingEl,
component: element,
swipeToClose: true,
...opts,
});
return modalElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@
const modalElement = await modalController.create({
presentingElement: presentingEl,
component: element,
swipeToClose: true,
...opts,
});
return modalElement;
Expand Down
1 change: 0 additions & 1 deletion core/src/components/modal/test/card/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@
const modalElement = await modalController.create({
presentingElement: presentingEl,
component: element,
swipeToClose: true,
...opts,
});
return modalElement;
Expand Down
1 change: 0 additions & 1 deletion core/src/components/modal/test/spec/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,6 @@ <h3>${p.position}</h3>
const modalElement = await modalController.create({
presentingElement: presentingEl,
component: element,
swipeToClose: true,
enterAnimation: toggle.checked ? enterAnimation : undefined,
leaveAnimation: toggle.checked ? leaveAnimation : undefined,
});
Expand Down
1 change: 0 additions & 1 deletion core/src/themes/test/css-variables/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,6 @@ <h2>Street Fighter II</h2>
// present the modal
const modalElement = Object.assign(document.createElement('ion-modal'), {
component: element,
swipeToClose: true,
presentingElement: document.querySelector('ion-tabs'),
});

Expand Down
2 changes: 1 addition & 1 deletion packages/vue/src/components/Overlays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const IonPicker = /*@__PURE__*/ defineOverlayContainer<JSX.IonPicker>('io

export const IonToast = /*@__PURE__*/ defineOverlayContainer<JSX.IonToast>('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController);

export const IonModal = /*@__PURE__*/ defineOverlayContainer<JSX.IonModal>('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'canDismiss', 'enterAnimation', 'handle', 'handleBehavior', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'swipeToClose', 'trigger']);
export const IonModal = /*@__PURE__*/ defineOverlayContainer<JSX.IonModal>('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'canDismiss', 'enterAnimation', 'handle', 'handleBehavior', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'trigger']);

export const IonPopover = /*@__PURE__*/ defineOverlayContainer<JSX.IonPopover>('ion-popover', defineIonPopoverCustomElement, ['alignment', 'animated', 'arrow', 'backdropDismiss', 'component', 'componentProps', 'dismissOnSelect', 'enterAnimation', 'event', 'htmlAttributes', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'reference', 'showBackdrop', 'side', 'size', 'translucent', 'trigger', 'triggerAction']);

0 comments on commit 1f3ddf2

Please sign in to comment.