Skip to content

Commit 1dcf5c9

Browse files
committed
refactor(modal): replaced snapBreakpoints array implementation with scrollAtEdge boolean
1 parent 95c5314 commit 1dcf5c9

File tree

5 files changed

+49
-43
lines changed

5 files changed

+49
-43
lines changed

core/api.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,8 +1085,8 @@ ion-modal,prop,keyboardClose,boolean,true,false,false
10851085
ion-modal,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
10861086
ion-modal,prop,mode,"ios" | "md",undefined,false,false
10871087
ion-modal,prop,presentingElement,HTMLElement | undefined,undefined,false,false
1088+
ion-modal,prop,scrollAtEdge,boolean,true,false,false
10881089
ion-modal,prop,showBackdrop,boolean,true,false,false
1089-
ion-modal,prop,snapBreakpoints,number[] | undefined,undefined,false,false
10901090
ion-modal,prop,trigger,string | undefined,undefined,false,false
10911091
ion-modal,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
10921092
ion-modal,method,getCurrentBreakpoint,getCurrentBreakpoint() => Promise<number | undefined>

core/src/components.d.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,10 @@ export namespace Components {
17931793
* 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.
17941794
*/
17951795
"presentingElement"?: HTMLElement;
1796+
/**
1797+
* Determines whether or not the sheet modal will only scroll when fully expanded. If the value is `true`, the modal will only scroll when fully expanded. If the value is `false`, the modal will scroll at any breakpoint.
1798+
*/
1799+
"scrollAtEdge": boolean;
17961800
/**
17971801
* Move a sheet style modal to a specific breakpoint. The breakpoint value must be a value defined in your `breakpoints` array.
17981802
*/
@@ -1801,10 +1805,6 @@ export namespace Components {
18011805
* 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.
18021806
*/
18031807
"showBackdrop": boolean;
1804-
/**
1805-
* The snapBreakpoints to use when creating a sheet modal. Each value in the array must be a decimal between 0 and 1 where 0 indicates the modal is fully closed and 1 indicates the modal is fully open. Values are relative to the height of the modal, not the height of the screen. One of the values in this array must be the value of the `initialBreakpoint` property and they must be a value in `breakpoints` property. The difference between `breakpoints` and `snapBreakpoints` is that `snapBreakpoints` allows the content to scroll, and the modal will only be draggable by the handle.
1806-
*/
1807-
"snapBreakpoints"?: number[];
18081808
/**
18091809
* An ID corresponding to the trigger element that causes the modal to open when clicked.
18101810
*/
@@ -6623,13 +6623,13 @@ declare namespace LocalJSX {
66236623
*/
66246624
"presentingElement"?: HTMLElement;
66256625
/**
6626-
* 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.
6626+
* Determines whether or not the sheet modal will only scroll when fully expanded. If the value is `true`, the modal will only scroll when fully expanded. If the value is `false`, the modal will scroll at any breakpoint.
66276627
*/
6628-
"showBackdrop"?: boolean;
6628+
"scrollAtEdge"?: boolean;
66296629
/**
6630-
* The snapBreakpoints to use when creating a sheet modal. Each value in the array must be a decimal between 0 and 1 where 0 indicates the modal is fully closed and 1 indicates the modal is fully open. Values are relative to the height of the modal, not the height of the screen. One of the values in this array must be the value of the `initialBreakpoint` property and they must be a value in `breakpoints` property. The difference between `breakpoints` and `snapBreakpoints` is that `snapBreakpoints` allows the content to scroll, and the modal will only be draggable by the handle.
6630+
* 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.
66316631
*/
6632-
"snapBreakpoints"?: number[];
6632+
"showBackdrop"?: boolean;
66336633
/**
66346634
* An ID corresponding to the trigger element that causes the modal to open when clicked.
66356635
*/

core/src/components/modal/gestures/sheet.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const createSheetGesture = (
5050
backdropBreakpoint: number,
5151
animation: Animation,
5252
breakpoints: number[] = [],
53-
snapBreakpoints: number[] = [],
53+
scrollAtEdge: boolean,
5454
getCurrentBreakpoint: () => number,
5555
onDismiss: () => void,
5656
onBreakpointChange: (breakpoint: number) => void
@@ -90,7 +90,12 @@ export const createSheetGesture = (
9090
const wrapperAnimation = animation.childAnimations.find((ani) => ani.id === 'wrapperAnimation');
9191
const backdropAnimation = animation.childAnimations.find((ani) => ani.id === 'backdropAnimation');
9292
let contentAnimation: Animation | undefined;
93-
if (snapBreakpoints.length > 0) {
93+
if (!scrollAtEdge) {
94+
/**
95+
* If scrollAtEdge is disabled, the content should be scrollable
96+
* at any breakpoint and the maxHeight animated so the content is
97+
* fully viewable at any breakpoint.
98+
*/
9499
contentAnimation = animation
95100
.addAnimation(
96101
createAnimation('contentAnimation')
@@ -154,7 +159,7 @@ export const createSheetGesture = (
154159
}
155160
}
156161

157-
if (contentEl && currentBreakpoint !== maxBreakpoint && !snapBreakpoints.includes(currentBreakpoint)) {
162+
if (contentEl && currentBreakpoint !== maxBreakpoint && scrollAtEdge) {
158163
contentEl.scrollY = false;
159164
}
160165

@@ -171,9 +176,10 @@ export const createSheetGesture = (
171176
currentBreakpoint = getCurrentBreakpoint();
172177

173178
/**
174-
* If we are in a snap breakpoint, we should not allow the swipe to start.
179+
* If we have scrollAtEdge disabled, we should not allow the swipe gesture to start
180+
* if the content is being swiped.
175181
*/
176-
if (snapBreakpoints.includes(currentBreakpoint) && contentEl) {
182+
if (!scrollAtEdge && contentEl) {
177183
return false;
178184
}
179185

@@ -347,6 +353,13 @@ export const createSheetGesture = (
347353
]);
348354

349355
if (contentAnimation) {
356+
/**
357+
* The modal content should scroll at any breakpoint when scrollAtEdge
358+
* is disabled. In order to do this, the content needs to be completely
359+
* viewable so scrolling can access everything. Othewise, the default
360+
* behavior would show the content off the screen and only allow
361+
* scrolling when the sheet is fully expanded.
362+
*/
350363
contentAnimation.keyframes([
351364
{ offset: 0, maxHeight: `${(1 - breakpointOffset) * 100}%` },
352365
{ offset: 1, maxHeight: `${snapToBreakpoint * 100}%` },
@@ -369,16 +382,14 @@ export const createSheetGesture = (
369382
}
370383

371384
/**
372-
* If the sheet is going to be fully expanded then we should enable
373-
* scrolling immediately. The sheet modal animation takes ~500ms to finish
374-
* so if we wait until then there is a visible delay for when scrolling is
375-
* re-enabled. Native iOS allows for scrolling on the sheet modal as soon
376-
* as the gesture is released, so we align with that.
385+
* If the sheet is going to be fully expanded or if the sheet has toggled
386+
* to scroll at any breakpoint then we should enable scrolling immediately.
387+
* then we should enable scrolling immediately. The sheet modal animation
388+
* takes ~500ms to finish so if we wait until then there is a visible delay
389+
* for when scrolling is re-enabled. Native iOS allows for scrolling on the
390+
* sheet modal as soon as the gesture is released, so we align with that.
377391
*/
378-
if (
379-
contentEl &&
380-
(snapToBreakpoint === breakpoints[breakpoints.length - 1] || snapBreakpoints.includes(snapToBreakpoint))
381-
) {
392+
if (contentEl && (snapToBreakpoint === breakpoints[breakpoints.length - 1] || !scrollAtEdge)) {
382393
contentEl.scrollY = true;
383394
}
384395

core/src/components/modal/modal.tsx

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
7575
private wrapperEl?: HTMLElement;
7676
private backdropEl?: HTMLIonBackdropElement;
7777
private sortedBreakpoints?: number[];
78-
private sortedSnapBreakpoints?: number[];
7978
private keyboardOpenCallback?: () => void;
8079
private moveSheetToBreakpoint?: (options: MoveSheetToBreakpointOptions) => Promise<void>;
8180
private inheritedAttributes: Attributes = {};
@@ -132,17 +131,15 @@ export class Modal implements ComponentInterface, OverlayInterface {
132131
@Prop() breakpoints?: number[];
133132

134133
/**
135-
* The snapBreakpoints to use when creating a sheet modal. Each value in the
136-
* array must be a decimal between 0 and 1 where 0 indicates the modal is fully
137-
* closed and 1 indicates the modal is fully open. Values are relative
138-
* to the height of the modal, not the height of the screen. One of the values in this
139-
* array must be the value of the `initialBreakpoint` property and they must be a
140-
* value in `breakpoints` property.
134+
* Determines whether or not the sheet modal will only
135+
* scroll when fully expanded.
141136
*
142-
* The difference between `breakpoints` and `snapBreakpoints` is that `snapBreakpoints`
143-
* allows the content to scroll, and the modal will only be draggable by the handle.
137+
* If the value is `true`, the modal will only scroll
138+
* when fully expanded.
139+
* If the value is `false`, the modal will scroll at
140+
* any breakpoint.
144141
*/
145-
@Prop() snapBreakpoints?: number[];
142+
@Prop() scrollAtEdge = true;
146143

147144
/**
148145
* A decimal value between 0 and 1 that indicates the
@@ -368,12 +365,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
368365
}
369366
}
370367

371-
snapBreakpointsChanged(snapBreakpoints: number[] | undefined) {
372-
if (snapBreakpoints !== undefined) {
373-
this.sortedSnapBreakpoints = snapBreakpoints.sort((a, b) => a - b);
374-
}
375-
}
376-
377368
connectedCallback() {
378369
const { el } = this;
379370
prepareOverlay(el);
@@ -449,7 +440,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
449440
raf(() => this.present());
450441
}
451442
this.breakpointsChanged(this.breakpoints);
452-
this.snapBreakpointsChanged(this.snapBreakpoints);
453443

454444
/**
455445
* When binding values in frameworks such as Angular
@@ -701,7 +691,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
701691
backdropBreakpoint,
702692
ani,
703693
this.sortedBreakpoints,
704-
this.sortedSnapBreakpoints,
694+
this.scrollAtEdge,
705695
() => this.currentBreakpoint ?? 0,
706696
() => this.sheetOnDismiss(),
707697
(breakpoint: number) => {

core/src/components/modal/test/sheet/index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@
102102
</button>
103103
<button
104104
id="custom-breakpoint-modal"
105-
onclick="presentModal({ initialBreakpoint: 0.5, breakpoints: [0,0.25, 0.5, 0.75], snapBreakpoints: [0.5, 0.75] })"
105+
onclick="presentModal({ initialBreakpoint: 0.5, breakpoints: [0,0.25, 0.5, 0.75], scrollAtEdge: false })"
106106
>
107-
Present Sheet Modal (SnapBreakpoints)
107+
Present Sheet Modal (scrollAtEdge)
108108
</button>
109109
<button
110110
id="custom-backdrop-modal"
@@ -190,6 +190,11 @@
190190
${items}
191191
</ion-list>
192192
</ion-content>
193+
<ion-footer>
194+
<ion-toolbar>
195+
<ion-title>Footer</ion-title>
196+
</ion-toolbar>
197+
</ion-footer>
193198
`;
194199

195200
let extraOptions = {

0 commit comments

Comments
 (0)