Skip to content

feat(lynx): render formSheet routes - #16

Merged
upupming merged 1 commit into
mainfrom
feat/form-sheet
Sep 9, 2026
Merged

upupming merged 1 commit into
mainfrom
feat/form-sheet

Conversation

@upupming

@upupming upupming commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

presentation: 'formSheet' was accepted by the types and then thrown on, so the option could not be used. It now renders.

The shape follows the native stack's own draft of this architecture on @satya164/native-stack (#13115), which already has a SheetScreen beside the CardScreen and NativeStackViewState this package mirrors:

  • A native sheet is its own host rather than a screen inside the stack, so sheets render as siblings of the stack host.
  • isOpen follows focus — a sheet covered by a pushed card has to close.
  • fitToContents must not be handed a full-height content view, or the native side has nothing to measure.
  • The popped route is dropped in onDidDisappear, which is what gives the sheet something to animate out.
  • onNativeDismiss carries whether the route was really dismissed, so ADD_NATIVELY_DISMISSED_ROUTES does not fire for a sheet whose dismissal was prevented.

Two guards come with it: an unsupported presentation now says so instead of silently rendering a card, and a formSheet as the first route is rejected.

Option names follow @react-navigation/native-stack. Three of its sheet options have no counterpart on FormSheetProps and are left out rather than faked: sheetSelectedDetentIndex, preventNativeDismissDragFeedback, and preventNativeDismiss as a channel array, which is a boolean here. sheetDetentChange carries only the index; upstream also reports whether the detent is stable, which onDetentChanged does not provide.

preventNativeDismiss is read from usePreventRemove rather than screen options, matching CardScreen: onNativeDismissPrevented pops unconditionally, so a static option would have the native side block the gesture and the round-trip pop the route anyway. Supporting it means guarding that dispatch, which changes cards too.

Not yet verified on a device — the example gains a sheet with two detents that logs where it settles, and that is the next step.

`presentation: 'formSheet'` was accepted by the types and then thrown on, so
the option could not be used. It now renders.

The shape follows the native stack's own draft of this architecture on
`@satya164/native-stack`, which already has a `SheetScreen` beside the
`CardScreen` and `NativeStackViewState` this package mirrors:

- A native sheet is its own host rather than a screen inside the stack, so
  sheets render as siblings of the stack host.
- `isOpen` follows focus. A sheet covered by a pushed card has to close, so
  keying it off whether the route was popped would leave it open underneath.
- `fitToContents` must not be handed a full-height content view, or the native
  side has nothing to measure.
- The popped route is dropped in `onDidDisappear`, which is what gives the
  sheet something to animate out.
- `onNativeDismiss` carries whether the route was really dismissed.
  `ADD_NATIVELY_DISMISSED_ROUTES` must not fire for a sheet whose dismissal was
  prevented, because that screen is still on the native stack.

Two guards come with it: an unsupported `presentation` now says so instead of
silently rendering a card, and a `formSheet` as the first route is rejected -
it has nothing to present over.

Option names follow `@react-navigation/native-stack`. Three of its sheet
options have no counterpart on `FormSheetProps` and are left out rather than
faked: `sheetSelectedDetentIndex`, `preventNativeDismissDragFeedback`, and
`preventNativeDismiss` as a channel array, which is a boolean here.
`sheetDetentChange` carries only the index; upstream also reports whether the
detent is stable, which `onDetentChanged` does not provide.

`preventNativeDismiss` is read from `usePreventRemove` rather than screen
options, matching `CardScreen`: `onNativeDismissPrevented` pops
unconditionally, so a static option would have the native side block the
gesture and the round-trip pop the route anyway.

The example gains a sheet with two detents that logs where it settles.
@changeset-bot

changeset-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4a84762

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@react-navigation/lynx Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026

Copy link
Copy Markdown
pnpm add https://pkg.pr.new/@react-navigation/lynx@4a84762

commit: 4a84762

@upupming
upupming merged commit fa1c06b into main Sep 9, 2026
6 checks passed
@upupming
upupming deleted the feat/form-sheet branch September 9, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant