Skip to content

allowOutsideInteraction=true breaks Expanded -> Peeked settling because drag velocity is not tracked #243

Description

@wangtianya

Describe the bug

When using the embedded BottomSheetLayout with SheetBehaviors(allowOutsideInteraction = true) and skipPeeked = false, a slow pull-down from Expanded settles directly to Collapsed instead of settling to Peeked. This makes an embedded map/detail sheet dismiss after a short slow drag from full-screen.

Expected behavior

  • From Expanded, dragging down should settle to Peeked.
  • From Peeked, a further downward drag should settle to Collapsed.
  • While the sheet is Peeked, the content behind it should remain interactive.

Actual behavior

  • With allowOutsideInteraction = true, a short slow pull-down from Expanded goes straight to Collapsed.
  • With allowOutsideInteraction = false, the Expanded -> Peeked behavior is closer to expected, but the background can no longer be interacted with.
  • A fast downward flick also dismisses directly in both modes.

Reproduction

val state = rememberBottomSheetState(initialValue = BottomSheetValue.Peeked)

Box(modifier = Modifier.fillMaxSize()) {
    Map() // background content that must remain interactive while peeked

    BottomSheetLayout(
        state = state,
        skipPeeked = false,
        peekHeight = PeekHeight.fraction(0.2f),
        behaviors = SheetBehaviors(allowOutsideInteraction = true),
    ) {
        // detail content
    }
}

From the fully expanded state, drag the sheet down slowly and release.

Root cause

Velocity tracking is coupled to allowOutsideInteraction. In CoreBottomSheetLayout, detectPointerPositionChanges is installed only in the allowOutsideInteraction == false branch:

https://github.com/dokar3/sheets/blob/main/sheets-core/src/commonMain/kotlin/com/dokar/sheets/CoreBottomSheetLayout.kt#L245-L277

When allowOutsideInteraction = true, that branch returns Modifier, so state.dragVelocity remains 0f.

With zero velocity, BottomSheetState.nextValue() falls through to the position-only logic and ends at the default return value:

https://github.com/dokar3/sheets/blob/main/sheets-core/src/commonMain/kotlin/com/dokar/sheets/BottomSheetState.kt#L502-L552

A small slow downward offset from Expanded moves outside the peekTop..peekBottom band toward the larger offset side, so it becomes Collapsed.

Suggested fix

Decouple drag-velocity tracking from outside interaction. For example, track pointer position changes whenever either outside interaction is disabled or an explicit velocity/settling behavior is enabled, rather than tying velocity collection to the modal scrim branch. This would preserve background interactivity while still allowing Expanded -> Peeked -> Collapsed settlement.

Environment

  • Library: io.github.dokar3:sheets-m3:0.7.5
  • Layout: embedded BottomSheetLayout, non-modal, over an interactive map
  • Related, but distinct: Swipe down to dismiss #187

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions