feat: add releaseProjection and settleDuration - #83
Open
NicholasBoccuzzi wants to merge 1 commit into
Open
Conversation
Two props for tuning how a drag release resolves and how the sheet travels to the detent it resolved to. Both default to current behavior. `releaseProjection` is seconds of release velocity projected onto the sheet's position before the nearest-detent search. A release is otherwise resolved on where the gesture stopped, so a short but deliberate flick cannot reach the next detent unless it also crossed the midpoint to it or exceeded the flick threshold. Projecting the release forward lets that momentum count. The flick branches deliberately keep using the raw position: they mean "one detent along from where the sheet actually is", and projecting there could skip past one. `settleDuration` is how long the settle spring takes. iOS had this hardcoded at 0.45s; Android used SpringForce.STIFFNESS_MEDIUM, which is closer to 0.2s, so the two platforms did not settle alike. Since both springs are critically damped, a duration maps to Android's stiffness as (8 / duration)^2 — omega*t ~= 8 is the settled point, and SpringForce's stiffness is omega^2. Left unset each platform keeps its own default, so existing sheets are unchanged. Both are validated as finite and non-negative, matching validateIndex.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows up on a Slack thread with @patrick — adds the two props we discussed for tuning how a drag release resolves and how the sheet travels to the detent it resolved to. The proposed commit-threshold prop is deliberately not here.
Both props default to current behavior, so no existing sheet changes until one is set.
releaseProjectionSeconds of release velocity projected onto the sheet's position before the nearest-detent search in
bestSnapIndex/snapshotBestSnapIndex.A release is otherwise resolved on where the gesture stopped, so a short but deliberate flick toward a detent can't reach it unless it also crossed the midpoint or exceeded the flick threshold. The closer two detents sit, the more that shows — a small, confident gesture reads as a non-event. Projecting the release forward lets its momentum count toward the detent it was aimed at.
Two things kept deliberately narrow:
settleDurationHow long the spring that carries the sheet to the resolved detent takes.
This also surfaced a pre-existing inconsistency worth flagging on its own: iOS hardcoded
duration = 0.45, while Android usedSpringForce.STIFFNESS_MEDIUM(1500), which is ω ≈ 38.7 and so settles in roughly 0.2s — the two platforms have not been settling alike.Both springs are critically damped (
CriticalSpringis ζ = 1 by construction; Android usesDAMPING_RATIO_NO_BOUNCY), and such a spring is settled within ~0.5% at ω·t ≈ 8 whileSpringForce's stiffness is ω². So a duration maps exactly onto Android's stiffness as(8 / duration)²— the same relation iOS already uses foromega = 8.0 / duration, not an approximation.I left both platform defaults in place so this PR doesn't change Android's existing feel, but setting
settleDurationnow gives both platforms the same settle, which the docs note.Release velocity is still carried into the spring at any duration.
Notes
validateReleaseTuning, followingvalidateIndex's style. A negative projection would resolve a release against the detent it was moving away from; a negative duration has no spring solution.ModalBottomSheetProps extends BottomSheetPropsandModalBottomSheetspreads props, so both work there without extra plumbing.release-and-settle.mdx, registered in the sidebar afterdetents-and-index.tsc --noEmitandeslint srcare clean. I have not run the Android unit/instrumented suites or built the example app — worth a CI pass, particularly on the@ReactPropoverrides, which assume codegen emitsDoubleforWithDefault<Double, 0>.Where this came from
We're shipping a persistent map sheet whose top two detents sit
insets.top + toolbarHeightapart (~120pt) while the next one down is most of the screen away (~700pt). Users reported that expanding took too much gesture. We trialled both changes as a local patch and measured on device: a slow ~34pt drag now resolves to the adjacent detent in either direction, where stock needed ~61pt up and ~365pt down.Happy to adjust naming, defaults, or split this into two PRs if you'd prefer them landed separately.