Skip to content

Releases: ramssutharr/react-native-inline-sheet

v0.3.2 — native collection views get the scroll lock

Choose a tag to compare

@ramssutharr ramssutharr released this 16 Oct 07:31

Fixed

  • iOS: a native UICollectionView in the body now takes part in the scroll↔sheet hand-off. The resolver only knew React lists, so a body whose list is native (the Giphy grid, for example) scrolled under a half-open sheet instead of expanding it to the top first. When the body holds no React scroll view, the first vertical UICollectionView is used; pickers, date pickers and text views (and anything inside them) are never candidates.

Full Changelog: v0.3.1...v0.3.2

v0.3.1 — keyboard follows interactive dismissal

Choose a tag to compare

@ramssutharr ramssutharr released this 28 Sep 09:30

iOS fixes for the keyboard and gesture edges, back-ported from the frame's lift into a pure-Swift app where they were found in daily use.

Fixed

  • Footer follows an interactive keyboard dismissal. A list with keyboardDismissMode="interactive" drags the keyboard down with the finger, and iOS fires no keyboard notification for that, so the footer stayed lifted in mid-air until the keyboard had fully gone. A 1pt view now rides the keyboardLayoutGuide and re-lays out the sheet on every move (iOS 17+ reads the guide without the safe area; iOS 15/16 treat the safe-area rest position as "no keyboard").
  • No jump when the keyboard hides mid-drag. With enableBlurKeyboardOnGesture, the resign fired a keyboard hide that animated the sheet to a detent while the finger was still moving it. While the sheet owns the drag, the hide only updates the lift; the release settles as usual.
  • In-gesture hand-off reports a settled layout. When the header reaches the top and the list takes the rest of the gesture, no settle follows, so onChange / onLayoutChange never fired and content kept the previous detent's body size.
  • Footer / handle unmount go through the same path as a height change, so an auto detent re-settles and the layout event carries the new geometry.
  • Body unmount drops the content-lock observation instead of leaving it pinned to the old list.
  • The content-sized height re-lays out even while resting at a fixed detent (dim progress, footer anchor), and the grabber is drawn above the slots so grabberAreaHeight={0} cannot hide it.

Notes

  • iOS only; Android is unchanged.
  • The "lift unchanged" early return in the keyboard notification handler is gone: the guide tracker updates the lift first, and the handler still owns keyboardBehavior expand / keyboardBlurBehavior restore and the events.

Full Changelog: v0.3.0...v0.3.1

v0.3.0 — presses survive a moving finger

Choose a tag to compare

@ramssutharr ramssutharr released this 16 Sep 09:57

Fix (iOS): buttons inside the sheet no longer drop presses on real devices. On Fabric, Pressable checks every touch-move against a rect from measure(), which reads the shadow tree. The shadow tree placed sheet content at the hidden host, not where the native sheet draws it. So any press that emitted a touch-move was lost: a slightly rolling finger, or just pressing harder on a 3D Touch iPhone. Simulator clicks emit no moves, which is why it never reproduced there. Each sheet slot now reports its real on-screen position to the shadow tree, so the measured and drawn rects match.

Fix (iOS): a tap that drifts is no longer taken as a drag. The sheet's pan now waits for 16pt of travel, the iOS counterpart of Android's touch slop.

Upgrading: this release adds a native component (NativeBottomSheetSlot), so run pod install after upgrading. No API changes; Android is unchanged.

v0.2.1 — date picker crash fix

Choose a tag to compare

@ramssutharr ramssutharr released this 12 Sep 06:59

Fixed

  • iOS: crash when a sheet holds a UIDatePicker (or a multiline TextInput). The plain-UIKit scroll view search ran whenever the React resolver found no list, latched onto the picker's internal table (a UIScrollView), and pinned its offset to 0 while the picker snapped it back, until the stack overflowed. The host's resolver is now authoritative; the UIKit-wide fallback only runs when no resolver is injected, and skips pickers and text views.

Full Changelog: v0.2.0...v0.2.1

v0.2.0 — gorhom parity

Choose a tag to compare

@ramssutharr ramssutharr released this 12 Sep 06:36

Everything @gorhom/bottom-sheet does that a user can see or feel, on the native frame. Sheets ported from gorhom keep their prop names and, from this release, their defaults.

Stacking

  • stackBehavior — 'switch' (default: the sheet on top slides out with its content still mounted and comes back when the new one is dismissed), 'push', 'replace'. No provider needed.
  • name, useBottomSheetModal().dismiss(name?) / dismissAll(), and dismissAllSheets() outside React.
  • Ref gains minimize() / restore().

Animated values (Reanimated, optional)

  • Native onPositionChange emits the sheet's live position per frame, armed only while something listens.
  • A useEvent worklet writes it into shared values on the UI thread: animatedIndex / animatedPosition props, useBottomSheetAnimated(), and gorhom's useBottomSheet() shape.
  • Reanimated stays an optional peer; without it the same objects update when the sheet settles.

Modal mode

  • mode="modal" (or a containerComponent) attaches to React Native's root surface view, above every screen, with React touches intact.

Sizing and gestures

  • Detents are sorted by resolved height, so a content-sized detent lands wherever the content puts it (gorhom's dynamic-sizing rule). Every index refers to that order.
  • maxDynamicContentSize, snapToPosition(dp | '50%'), forceClose.
  • enableContentPanningGesture, enableHandlePanningGesture.
  • enableOverDrag / overDragResistanceFactor with gorhom's exact sqrt(1 + excess) × factor curve, from the handle or a body without a list.
  • detached with style side margins or detachedMargin, all corners rounded.
  • Custom handleComponent, rendered natively in a sheet-handle slot and given the animated values.
  • presentOnMount / animateOnMount for gorhom's non-modal BottomSheet.

Keyboard

  • keyboardBehavior="interactive" (keyboardMode="lift-sheet") is now hybrid: whatever the sheet cannot rise, the footer rises on its own, so a footer always clears the keyboard.
  • keyboardBlurBehavior="restore" returns to the pre-keyboard detent.
  • enableBlurKeyboardOnGesture (alias dismissKeyboardOnDrag).
  • New contentBottomInset: the content's own safe-area padding is spent over the keyboard instead of stacking on top of it.

Events

  • onChange(index, position, type) with SNAP_POINT_TYPE.PROVIDED | DYNAMIC.
  • onAnimate(from, to, fromPosition, toPosition).
  • onClose alias of onDismiss.

Accessibility and motion

  • VoiceOver / TalkBack labels on the backdrop and handle; the handle is an adjustable control that moves between detents.
  • Reduce Motion (iOS) and animator duration scale (Android) shorten the springs.

Also in this release (from 0.1.1)

  • Android: the hardware back press is claimed in JS while presented, so back closes the sheet instead of leaving the screen.

⚠️ Breaking: defaults now match gorhom 5.x

0.1.x 0.2.0
enableDynamicSizing false true
enableOverDrag false true (2.5)
keyboardBehavior expand to top 'interactive'
dismissKeyboardOnDrag true false
background system, radius 24 white, radius 15
handle 36×5 7.5% of the window × 4, 24dp area

Migration: sheets with fixed detents that must not gain a content-sized detent need enableDynamicSizing={false}; an Instagram-style comments sheet wants keyboardBehavior="extend" and dismissKeyboardOnDrag. The backdrop keeps BottomSheetBackdrop's defaults (black, 0.5, close on press); pass backdropOpacity={0} for gorhom's bare default.

Not covered

Custom backdropComponent (accepted, not rendered), gorhom's footerComponent render prop, Reanimated animationConfigs, and RNGH simultaneousHandlers / waitFor.

Full Changelog: v0.1.0...v0.2.0

v0.1.0 — Initial release

Choose a tag to compare

@ramssutharr ramssutharr released this 10 Sep 11:14

Instagram-style native bottom sheet for React Native (Fabric / New Architecture).

The frame is native — present/dismiss spring, drag, detents, dim backdrop,
scroll ↔ sheet hand-off, keyboard handling, back gesture — implemented in UIKit
on iOS and Android Views on Android, with nothing running on the JS thread per
frame. The content is ordinary React.

Highlights

  • Inline mode: the sheet attaches to the hosting screen's own native view —
    above a tab bar, below anything the navigator pushes. Tap a name in comments,
    the profile slides over the open sheet; pop, and the sheet is exactly where
    you left it.
  • Gorhom-compatible API: snapPoints ('60%', dp, 'CONTENT_HEIGHT'),
    index, enableDynamicSizing, enablePanDownToClose, topInset,
    bottomInset, backgroundStyle, handleIndicatorStyle,
    handleComponent={null}, backdropColor/backdropOpacity,
    keyboardBehavior, onAnimate, onChange — and the same imperative ref
    (present(data), dismiss, close, snapToIndex, expand, collapse).
  • Gorhom's gesture model: the list is locked at offset 0 unless the sheet is
    fully expanded; a drag that reaches the top hands the rest of the gesture to
    the list; a fling settles the sheet with the list still.
  • Keyboard: the footer slot is pinned to the visible bottom and lifted
    natively; the sheet springs to its top detent when the keyboard opens
    (expandOnKeyboard) and drops the keyboard when dragged (dismissKeyboardOnDrag).
  • Instagram footer: pinned at the screen edge while the sheet is at or above
    its lowest detent; slides off with the sheet when dragged to dismiss.
  • SheetRouter: push/pop multi-step content inside one sheet.
  • useBottomSheetNativeLayout() / useBottomSheetNativeActions() for content.

Requirements

  • React Native ≥ 0.80 with the New Architecture (Fabric)
  • iOS 15.1+, Android minSdk 24
  • Autolinked; run pod install on iOS

Known limitations

  • Inline mode only (a sheet that must sit above pushed screens — "modal" mode — is planned)
  • A custom handleComponent is not rendered natively yet (null hides the grabber)
  • Ships untranspiled TypeScript: allow it through Jest's transformIgnorePatterns