* fix(ios): use native backgroundEffect for blur on iOS 26.1+
- Extract blur style mapping into BlurUtil
- Refactor setupBackground and setupGrabber into helper methods
- Add sheet getter for cleaner code
- Use native UIBlurEffect on backgroundEffect when only blurTint is set (iOS 26.1+)
* refactor: rename blurTint to backgroundBlur
* docs: add planning doc
* refactor(android): migrate from DialogFragment to CoordinatorLayout
This solves the touch lag issue when TrueSheet is presented over interactive
components like Maps. The sheet now stays in the same activity window instead
of a separate dialog window.
Changes:
- Add TrueSheetCoordinatorLayout to host sheet and dim view
- Add TrueSheetBottomSheetView with BottomSheetBehavior
- Refactor TrueSheetViewController to use CoordinatorLayout approach
- Update TrueSheetDimView for in-hierarchy usage with touch handling
- Remove TrueSheetDialogFragment (no longer needed)
- Remove unused dialog styles and animations
* fix(android): animate sheet on present using BottomSheetBehavior
* fix(android): animate sheet on present when not dismissible
* refactor(android): simplify dismiss animation using ViewPropertyAnimator
* docs: update AGENTS.md with new Android architecture
* fix(android): prevent duplicate initial present on re-mount
* fix(android): fix keyboard handling and parent sheet translation
* fix(android): prevent parent sheet layout reset when keyboard shows
- Add TrueSheetBottomSheetViewDelegate with isTopmostSheet property
- Skip onLayout for parent sheets to prevent BottomSheetBehavior from
resetting translationY during system layout passes
- Refactor TrueSheetCoordinatorLayout.Delegate to standalone interface
* fix(android): preserve parent sheet translation during keyboard transitions
Override setTranslationY in TrueSheetBottomSheetView to prevent
keyboard inset animations from resetting parent sheet translation to 0.
Parent sheets (non-topmost) now maintain their translation value.
* refactor(android): rename TrueSheetDialogObserver to TrueSheetStackManager
* refactor(android): remove edgeToEdgeFullScreen prop
* fix(android): prevent sheet from showing during navigation within modal
* fix(android): clamp detent heights to available screen space
* fix(android): post when initialDetentAnimated is false
* fix(android): restore original code
* refactor(android): use BottomSheetDialogFragment instead of BottomSheetDialog
- Create TrueSheetDialogFragment in core/ for better lifecycle management
- Refactor TrueSheetViewController to use the new fragment
- Add TrueSheetDialogFragmentDelegate for fragment callbacks
- Maintain all existing functionality (detents, animations, keyboard, stacking)
* fix(android): fix dialog fragment presentation issues
- Move setupSheetDetents and setupDimmedBackground to onDialogShow
- Clear FLAG_DIM_BEHIND in fragment's onCreateDialog
- Fix footer positioning with post and isPresented check
- Rename setDraggable to updateDraggable to fix JVM signature clash
* fix(android): animate sheet on content size change
- Add animate parameter to configureDetents
- Use setPeekHeight with animate flag when sheet is presented
- Remove unnecessary footerView.post wrapper
* fix(android): position footer during keyboard transitions
* fix(android): restore translationY animation for present
- Restore translationY logic in animator for child sheets
- Remove duplicate setStateForDetentIndex call in onDialogShow
- Position sheet off-screen before animation starts
- Clean up debug logging
* fix(android): fix dismissible behavior and clean up onSlide
- Re-apply isHideable after dialog show to fix dismissible
- Move isAnimating check to early return in onSlide
- Clean up debug logging
* feat: update slide animation styles
* fix: move rn-screen observer to preAttached and detached
* feat(android): implement programmatic slide animations for present/dismiss
* refactor(android): cleanup unused animation resources and fix present animation flash
* fix(android): animate footer with sheet during present/dismiss
* refactor(android): sync dim alpha with sheet translation during animations
- Update updateDimAmount() to accept optional sheetTop parameter
- Call updateDimAmount() on each frame during present/dismiss animations
- Remove unused animateDimAlpha() from TrueSheetViewController
- Remove unused animateAlpha() from TrueSheetDimView
* refactor(android): cleanup TrueSheetViewController
- Remove unused imports (Log, ViewCompat)
- Remove unused positionAnimator and setupTransitionTracker
- Use AnimatorListenerAdapter instead of full Animator.AnimatorListener
- Simplify comments and remove debug logs
* fix: move setup methods out of onShowListener
* refactor: make methods consistent
* refactor(android): use alpha + window flags for modal hide/show
- Use alpha fade instead of visibility for hiding sheet during RN Screens modal
- Add FLAG_NOT_TOUCHABLE and FLAG_NOT_FOCUSABLE to prevent interaction when hidden
- Remove unused TrueSheetSlideAnimation style and anim resources
* feat: translate bottomSheetView instead of setupSheetDetents with keyboard
* fix(android): clamp sheet translation during drag to prevent going beyond visible screen
* feat(android): dismiss keyboard when sheet is dragged down to a lower detent
* feat(android): expand to last detent on keyboard show, restore on hide
- Refactor keyboard observer delegate callbacks
- Track pre-keyboard detent and restore on hide
- Skip emitting detent change for keyboard transitions
- Fix 2-detent state map to include STATE_HALF_EXPANDED
* refactor(android): extract TrueSheetDetentCalculator and TrueSheetAnimator
- Extract detent calculations into TrueSheetDetentCalculator class
- Extract present/dismiss animations into TrueSheetAnimator class
- Use interface-based pattern for dynamic prop updates
- Consolidate state variables (InteractionState, KeyboardState)
- Reduce TrueSheetViewController from ~900 to ~650 lines
* refactor(ios): extract TrueSheetDetentCalculator from TrueSheetViewController
- Create TrueSheetDetentCalculator with TrueSheetDetentMeasurements protocol
- Extract detent calculation methods: detentValueForIndex, estimatedPositionForIndex,
findSegmentForPosition, interpolatedIndexForPosition, interpolatedDetentForPosition
- TrueSheetViewController conforms to protocol for dynamic prop access
- Mirrors Android's interface-based pattern for consistency
* feat(android): skip keyboard handling when sheet is not topmost or hidden by modal
* feat(android): use setupSheetDetents for keyboard handling instead of Y translation
* feat(android): dismiss keyboard when dragged below original position
* chore: run tidy
* chore: tidy clean script
* fix: implement TrueSheetProvider for web
* refactor(example): move TrueSheetProvider to screen level and improve web support
- Move TrueSheetProvider and ReanimatedTrueSheetProvider from root layout to individual screens
- Remove (sheet) folder and rename route to 'sheet'
- Improve web grabber defaults and container layout
- Fix Platform.select to use 'default' instead of 'android' for web compatibility
- Update Input placeholder color and add text color for web visibility
- Add backgroundComponent={null} and fix handle zIndex in web implementation
* feat(web): add stackBehavior prop for sheet stacking control
* docs: simplify Expo Router example with proper types
* feat(expo-example): update to match example app structure
- Add promise-based present/dismiss to TrueSheet.web.tsx
- Remove tabs navigation, use stack-based routing
- Add screens: Map, Standard, Modal, Test
- Add shared components and sheet components
- Add utils (constants, times, random)
- Add react-native-maps dependency
* feat(expo-example): add Map component and SheetStack with withLayoutContext
- Add platform-specific Map component (native MapView, web View fallback)
- Add sheet-stack route using expo-router's withLayoutContext
- Integrate createTrueSheetNavigator with expo-router file-based routing
* refactor: create shared example-shared package for common components
- Create @truesheet/example-shared workspace package
- Move common components (Button, Header, Footer, etc.) to shared
- Move sheet components (BasicSheet, PromptSheet, etc.) to shared
- Move utils (constants, times, random) to shared
- Update example and expo-example to re-export from shared
* chore: reorganize examples into examples/ folder
- Move example/ to examples/bare/
- Move expo-example/ to examples/expo/
- Move example-shared/ to examples/shared/
- Update workspace paths in root package.json
- Rename packages to @truesheet/bare-example, @truesheet/expo-example
- Update script names (example -> bare, expo)
* chore: update config paths for examples folder reorganization
* chore: rename examples to example and update package names to @example/*
* chore: move screen components to shared package
- Add MapScreen, ModalScreen, StandardScreen, TestScreen to shared
- Make screens navigation-agnostic with callback props
- Add MapComponent prop to MapScreen for platform-specific map
- Create Map component in bare example
- Update expo and bare examples to use shared screens
* chore: import screens directly from @example/shared/screens
* chore: import components and utils directly from @example/shared
* chore: remove unused sheets index files
* chore: move Map component to shared package
* chore: remove unused constants folder from expo example
* chore: remove unused ReanimatedExample component
* chore: update scripts for new example folder structure
* chore: exclude example folder from jest test paths
* chore: add expo prebuild step to clean script
* fix: update config paths for new example folder structure
* chore: categorize steps in clean script
* fix: use workspace:* for example dependencies
- Change @lodev09/react-native-true-sheet from * to workspace:* in bare and expo examples
- Fixes duplicate view registration error caused by npm version being installed alongside workspace
- Silence clean.sh script output while preserving error visibility
* fix: interpolated index and detent for single detent
When only one detent is provided (e.g., [1]), the interpolated index
and detent values were fixed at 0 and 1 respectively instead of
changing as the sheet moves.
Updated findSegmentForPosition on both iOS and Android to calculate
the interpolation between the closed state and the single detent.
* refactor: simplify findSegmentForPosition
Deduplicate the 'above first detent' logic by handling it once
before the single/multi-detent branching.
* chore: restore MapScreen
- Simplify API: accept worklet function directly
- Add positionChangeHandler to regular TrueSheetScreen
- When reanimated enabled, handler must be a worklet
- Remove ReanimatedTrueSheetScreenProps type
- Update documentation
- Use ColorValue type in native component spec for proper color handling
- iOS: Use RCTUIColorFromSharedColor directly with SharedColor
- Android: Use customType="Color" for automatic color conversion
- Remove manual processColor call in TrueSheet.tsx
* feat(android): adjust android layout calculations
* fix(android): fix footer positioning
* fix(android): emit correct position relative to js screen height
* fix(android): fix halfExpandedRatio calculation with 3 detents
* refactor(android): pre-calculate positions by index
* chore: restore examples
* fix(android): fix halfExpandedRatio calculation
* feat(android): add bottomInset to detent heights for iOS consistency
- Add bottomInset to auto and fractional detent heights to match iOS behavior
- Update ScreenUtils to use ReactContext instead of View for reliable inset retrieval
- Remove unused getScreenY method
- Simplify currentSheetTop to use view.top directly
* fix(android): adjust halfExpandedRatio and expandedOffset for edgeToEdgeFullScreen
- Use maxOf(edgeToEdgeTopInset, realHeight - detentHeight) for expandedOffset
- Subtract edgeToEdgeTopInset from detent heights when calculating halfExpandedRatio
- Ensures sheet respects top inset when edgeToEdgeFullScreen is disabled
* fix(android): emit position on dismiss and sheet stacking
- Add emitDismissedPosition() for dismiss scenarios
- Add emitPosition parameter to hideDialog/showDialog
- Emit position when sheet is hidden/shown due to sheet stacking
- Skip position emission for RN Screens modal show/hide
* refactor(android): simplify setupSheetDetents calculation
- Extract common pattern for peekHeight, halfExpandedRatio, expandedOffset
- Fix halfExpandedRatio to cap at maxAvailableHeight instead of subtracting edgeToEdgeTopInset
- Remove redundant when block with unified calculation logic
* feat: add insetAdjustment prop for controlling bottom inset behavior
* fix(ios): fix ios insetAdjustment logic
* fix(ios): add pending layout update flag for detents and insetAdjustment changes
* refactor(ios): rename to detentBottomInsetForHeight, skip for iOS 26 floating sheets
* docs: add insetAdjustment prop documentation
* docs: fix broken links
* feat: add react-navigation integration
- Add createTrueSheetNavigator for custom sheet navigator
- Add TrueSheetRouter with snapTo action creator
- Add TrueSheetView component for rendering sheet screens
- Add useTrueSheetNavigation hook
- Export as separate optional import via /navigation
- Add optional peer dependencies for @react-navigation/native, nanoid
* docs: add expo-router support section to navigation guide
* feat: add sheet navigator for react-navigation integration
- Add createTrueSheetNavigator for react-navigation support
- Add TrueSheetRouter with RESIZE action
- Add TrueSheetView to render first screen as content, rest as sheets
- Add useTrueSheetNavigation hook with resize method
- Add navigation module as separate import (@lodev09/react-native-true-sheet/navigation)
- Refactor example to use navigators folder structure
- Update documentation with usage examples and Expo Router support
* fix: wait for sheet dismiss animation before removing route
- Intercept GO_BACK/POP actions to mark route as closing instead of removing
- Add DISMISS and REMOVE custom actions to TrueSheetRouter
- Sheet stays in navigation state until dismiss animation completes
- Handle user swipe dismiss by calling goBack then skipping dismiss
- Refactor example: rename NavigationScreen to StandardScreen
- Remove MapView from SheetNavigator example
- Add navigation examples to SheetNavigator (Test screen, Modal)
* refactor(navigation): use Pick for TrueSheetNavigationOptions type
* fix(android): prevent state reset during resize animation
* refactor(navigation): clean up types and remove redundancies
- Remove unused TrueSheetNavigationConfig type
- Combine GO_BACK, POP, and DISMISS action handling in router
- Remove unused navigation prop from TrueSheetView
- Remove unused rest spread from TrueSheetNavigator
- Export TrueSheetActionType and TrueSheetNavigationState types
* refactor(navigation): simplify detentIndex logic and use initialDetentIndex
- Use initialDetentIndex prop for faster initial presentation (no JS-native roundtrip)
- Capture initialDetentIndex in ref to prevent prop changes on resize
- Extract clampDetentIndex helper for cleaner index calculation
- Apply detent defaults in destructuring instead of inline nullish coalescing
* feat(navigation): add sheet-specific navigation events
- Add sheetWillPresent, sheetDidPresent events
- Add sheetWillDismiss, sheetDidDismiss events
- Add sheetDetentChange event
- Add sheetDragBegin, sheetDragChange, sheetDragEnd events
- Add sheetPositionChange event with realtime flag
- Add sheetWillFocus, sheetDidFocus, sheetWillBlur, sheetDidBlur events
- Export DetentChangeEventData and PositionChangeEventData types
- Add example usage in SheetNavigator
* refactor(navigation): reuse event payload types from TrueSheet.types
- Replace DetentChangeEventData with DetentInfoEventPayload
- Replace PositionChangeEventData with PositionChangeEventPayload
- Re-export payload types from TrueSheet.types in navigation index
* refactor(navigation): use nested pattern instead of independent tree
- First screen in Sheet.Navigator is base content (existing app/navigator)
- Subsequent screens are presented as sheets on top
- Prevents dismissing base screen in router
- Updated docs to show wrapping existing navigation pattern
- Updated Expo Router example with (main)/ route group structure
* feat(navigation): support initialRouteName to determine base screen
- Base screen is determined by initialRouteName (defaults to first screen)
- Updated docs and example to reflect the new pattern
* docs: simplify navigation doc
* docs: update navigation doc
* docs: tidy
* chore(example): restore example
* fix(navigation): bubble goBack to parent when on base screen
- Return null instead of state when goBack is called on base screen
- Allows navigation actions to propagate to parent navigator
- Simplified navigation docs
- Remove unconditional reanimated export from main index
- Add separate export path for reanimated integration
- Update example app to use new import path
Users can now import reanimated features via:
import { ReanimatedTrueSheet } from '@lodev09/react-native-true-sheet/reanimated'
* feat(ios): add custom grabber view with vibrancy effect
* refactor(ios): simplify blur and grabber view setup
* feat: add grabberOptions prop for customizing grabber appearance
- Add GrabberOptions type with width, height, topMargin, and color options
- iOS: Use system grabber by default, custom grabber when options provided
- Android: Pass options to TrueSheetGrabberView
- Update docs with new prop and type reference
* fix(ios): fix grabberOptions color handling
- Use Int32 for color in codegen spec (like background prop)
- Process color with processColor in TrueSheet.tsx
- Apply color to vibrancy view backgroundColor
* refactor(ios): consolidate blur options into blurOptions prop
- Add BlurOptions type with intensity and interaction properties
- Use -1 as sentinel value for intensity to support value of 0
- Keep blurTint as separate prop
- Update docs
* refactor: use WithDefault in codegen for blurOptions
* feat: add cornerRadius option to grabberOptions
* feat(ios): emit consistent position values for lifecycle events
- Update delegate protocol to pass index, position, and detent params
- Use dispatch_async for willPresent, didPresent, detentChange events
- Remove unused methods from public header
- Update TrueSheetView to use delegate params directly
* refactor(ios): remove layoutTransitioning property
* fix(ios): correct interpolated index and detent values for position changes
- Store actual Y positions when sheet settles at each detent
- Use stored positions for accurate interpolation instead of estimating from detent fractions
- Add estimatedPositionForIndex helper to calculate positions with offset correction
- Fixes incorrect interpolated values caused by iOS safe area insets
Fixes#255
* fix(ios): update resolved position in viewDidLayoutSubviews
- Move position storage to viewDidLayoutSubviews for centralized handling
- Handles content size changes correctly
- Remove duplicate storage from detent change delegate
* feat(example): add content toggle to MapScreen for testing dynamic height
* fix(android): correct interpolated index and detent values for position changes
* refactor(ios): extract findSegmentForPosition helper to reduce duplication
* fix(ios): emit detent change after sheet settles for programmatic resize
* refactor(ios): simplify position tracking and remove transition animation tracking
* fix(ios): emit realtime position changes when another controller is presented
* fix(android): adjust sheet position when content size changes at auto detent
* docs: remove auto detent placement restriction note