Fix mobile bottom sheets reopening after dismiss
This commit is contained in:
@@ -118,4 +118,44 @@ describe("bottom sheet visibility tracker", () => {
|
||||
tracker.handleSheetIndexChange(-1);
|
||||
expect(closeCount()).toBe(2);
|
||||
});
|
||||
|
||||
it("does not re-present when the controller reattaches before parent state acknowledges a user dismiss", () => {
|
||||
const { sheet, tracker, closeCount } = setup();
|
||||
tracker.attachController(sheet);
|
||||
tracker.syncDesired({ visible: true });
|
||||
|
||||
tracker.handleSheetIndexChange(-1);
|
||||
tracker.attachController(null);
|
||||
tracker.attachController(sheet);
|
||||
|
||||
expect(closeCount()).toBe(1);
|
||||
expect(sheet.events).toEqual([{ type: "present" }]);
|
||||
});
|
||||
|
||||
it("does not re-present when dismiss fires before parent state acknowledges a user dismiss", () => {
|
||||
const { sheet, tracker, closeCount } = setup();
|
||||
tracker.attachController(sheet);
|
||||
tracker.syncDesired({ visible: true });
|
||||
|
||||
tracker.handleSheetDismiss();
|
||||
tracker.attachController(null);
|
||||
tracker.attachController(sheet);
|
||||
|
||||
expect(closeCount()).toBe(1);
|
||||
expect(sheet.events).toEqual([{ type: "present" }]);
|
||||
});
|
||||
|
||||
it("allows a fresh open after parent state acknowledges a dismissed sheet", () => {
|
||||
const { sheet, tracker } = setup();
|
||||
tracker.attachController(sheet);
|
||||
tracker.syncDesired({ visible: true });
|
||||
|
||||
tracker.handleSheetIndexChange(-1);
|
||||
tracker.attachController(null);
|
||||
tracker.attachController(sheet);
|
||||
tracker.syncDesired({ visible: false });
|
||||
tracker.syncDesired({ visible: true });
|
||||
|
||||
expect(sheet.events).toEqual([{ type: "present" }, { type: "present" }]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,25 +15,27 @@ export interface BottomSheetVisibilityTracker {
|
||||
handleSheetDismiss(): void;
|
||||
}
|
||||
|
||||
type BottomSheetPhase = "closed" | "presenting" | "presented" | "dismissing";
|
||||
|
||||
export function createBottomSheetVisibilityTracker(opts: {
|
||||
onClose: () => void;
|
||||
}): BottomSheetVisibilityTracker {
|
||||
let controller: BottomSheetController | null = null;
|
||||
let visible = false;
|
||||
let isEnabled: boolean | undefined;
|
||||
let isPresented = false;
|
||||
let phase: BottomSheetPhase = "closed";
|
||||
let hasNotifiedClose = false;
|
||||
|
||||
function present(): void {
|
||||
if (!controller || isPresented) return;
|
||||
isPresented = true;
|
||||
if (!controller || phase !== "closed") return;
|
||||
phase = "presenting";
|
||||
hasNotifiedClose = false;
|
||||
controller.present();
|
||||
}
|
||||
|
||||
function dismiss(): void {
|
||||
if (!controller || !isPresented) return;
|
||||
isPresented = false;
|
||||
if (!controller || phase === "closed" || phase === "dismissing") return;
|
||||
phase = "dismissing";
|
||||
controller.dismiss();
|
||||
}
|
||||
|
||||
@@ -58,19 +60,34 @@ export function createBottomSheetVisibilityTracker(opts: {
|
||||
present();
|
||||
return;
|
||||
}
|
||||
if (phase === "dismissing") {
|
||||
phase = "closed";
|
||||
hasNotifiedClose = false;
|
||||
return;
|
||||
}
|
||||
dismiss();
|
||||
},
|
||||
handleSheetIndexChange(index) {
|
||||
if (index === -1 && visible) {
|
||||
if (index !== -1) {
|
||||
if (phase === "presenting") {
|
||||
phase = "presented";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (phase === "presenting" || phase === "presented") {
|
||||
phase = "dismissing";
|
||||
}
|
||||
if (visible) {
|
||||
notifyClose();
|
||||
}
|
||||
},
|
||||
handleSheetDismiss() {
|
||||
isPresented = false;
|
||||
if (visible) {
|
||||
phase = "dismissing";
|
||||
notifyClose();
|
||||
return;
|
||||
}
|
||||
phase = "closed";
|
||||
hasNotifiedClose = false;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user