Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(modalSheet): change gesture to allow draging when content scrolle… #27696

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 45 additions & 28 deletions core/src/components/modal/gestures/sheet.ts
Expand Up @@ -41,7 +41,6 @@ export const createSheetGesture = (
backdropBreakpoint: number,
animation: Animation,
breakpoints: number[] = [],
getCurrentBreakpoint: () => number,
onDismiss: () => void,
onBreakpointChange: (breakpoint: number) => void
) => {
Expand Down Expand Up @@ -134,24 +133,24 @@ export const createSheetGesture = (
contentEl.scrollY = false;
}

const canStart = (detail: GestureDetail) => {
/**
* If the sheet is fully expanded and
* the user is swiping on the content,
* the gesture should not start to
* allow for scrolling on the content.
*/
const content = (detail.event.target! as HTMLElement).closest('ion-content');
currentBreakpoint = getCurrentBreakpoint();

if (currentBreakpoint === 1 && content) {
return false;
}

return true;
};
let hasSwitchFromScrollToSwipe = false;
let hasComputedDeltaYOffset = false;
let deltaYWhenSwitched = 0;
let lastScrollTopValue = 0;
if (contentEl) {
contentEl.getScrollElement().then((scrollEl) => {
lastScrollTopValue = scrollEl.scrollTop;
scrollEl.onscroll = () => {
lastScrollTopValue = scrollEl.scrollTop;
if (scrollEl.scrollTop <= 0) {
contentEl.scrollY = false;
hasSwitchFromScrollToSwipe = true;
}
};
});
}

const onStart = () => {
const onStart = (detail: GestureDetail) => {
/**
* If canDismiss is anything other than `true`
* then users should be able to swipe down
Expand All @@ -165,14 +164,9 @@ export const createSheetGesture = (
* Remove undefined check
*/
canDismissBlocksGesture = baseEl.canDismiss !== undefined && baseEl.canDismiss !== true && minBreakpoint === 0;

/**
* If swiping on the content
* we should disable scrolling otherwise
* the sheet will expand and the content will scroll.
*/
if (contentEl) {
if (contentEl && lastScrollTopValue <= 0 && detail.deltaY > 0) {
contentEl.scrollY = false;
hasSwitchFromScrollToSwipe = true;
}

raf(() => {
Expand All @@ -187,14 +181,26 @@ export const createSheetGesture = (
};

const onMove = (detail: GestureDetail) => {
/**
* Prevent the drag gesture on the Y axis if scrolling is possible and if user is touching the content.
*/
const isTouchEventInContent =
contentEl?.scrollY && detail.event.target && contentEl.contains(detail.event.target as HTMLElement);
if (contentEl?.scrollY && isTouchEventInContent) return;

if (hasSwitchFromScrollToSwipe && !hasComputedDeltaYOffset) {
hasComputedDeltaYOffset = true;
deltaYWhenSwitched = detail.deltaY;
}

/**
* Given the change in gesture position on the Y axis,
* compute where the offset of the animation should be
* relative to where the user dragged.
*/
const initialStep = 1 - currentBreakpoint;
const secondToLastBreakpoint = breakpoints.length > 1 ? 1 - breakpoints[1] : undefined;
const step = initialStep + detail.deltaY / height;
const step = initialStep + (detail.deltaY - deltaYWhenSwitched) / height;
const isAttemptingDismissWithCanDismiss =
secondToLastBreakpoint !== undefined && step >= secondToLastBreakpoint && canDismissBlocksGesture;

Expand Down Expand Up @@ -230,18 +236,28 @@ export const createSheetGesture = (
};

const onEnd = (detail: GestureDetail) => {
/**
* Prevent the drag gesture on the Y axis if scrolling is possible and if user is touching the content.
*/
const isTouchEventInContent =
contentEl?.scrollY && detail.event.target && contentEl.contains(detail.event.target as HTMLElement);
if (contentEl?.scrollY && isTouchEventInContent) return;
/**
* When the gesture releases, we need to determine
* the closest breakpoint to snap to.
*/
const velocity = detail.velocityY;
const threshold = (detail.deltaY + velocity * 350) / height;
const threshold = (detail.deltaY - deltaYWhenSwitched + velocity * 350) / height;

const diff = currentBreakpoint - threshold;
const closest = breakpoints.reduce((a, b) => {
return Math.abs(b - diff) < Math.abs(a - diff) ? b : a;
});

deltaYWhenSwitched = 0;
hasSwitchFromScrollToSwipe = false;
hasComputedDeltaYOffset = false;

moveSheetToBreakpoint({
breakpoint: closest,
breakpointOffset: offset,
Expand Down Expand Up @@ -328,6 +344,8 @@ export const createSheetGesture = (
*/
if (contentEl && currentBreakpoint === breakpoints[breakpoints.length - 1]) {
contentEl.scrollY = true;
} else if (contentEl) {
contentEl.scrollY = false;
}

/**
Expand Down Expand Up @@ -370,7 +388,6 @@ export const createSheetGesture = (
gesturePriority: 40,
direction: 'y',
threshold: 10,
canStart,
onStart,
onMove,
onEnd,
Expand Down
1 change: 0 additions & 1 deletion core/src/components/modal/modal.tsx
Expand Up @@ -602,7 +602,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
backdropBreakpoint,
ani,
this.sortedBreakpoints,
() => this.currentBreakpoint ?? 0,
() => this.sheetOnDismiss(),
(breakpoint: number) => {
if (this.currentBreakpoint !== breakpoint) {
Expand Down