-
-
Notifications
You must be signed in to change notification settings - Fork 640
feat(Tabs): add preventNativeSelection support #3838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
669db9a
feat(Tabs): add preventNativeSelection prop to TabsScreen
kkafar c66fe54
feat(Tabs): add onTabSelectionPrevented event to TabsHost
kkafar 4b880ca
test(example): add prevent native selection test scenario
kkafar a0816d0
PoC of prevent native selection for iOS w/o more view controller
kkafar 30503a4
PoC of handling the more navigation controller
kkafar 34fef3d
Add two more tabs to example to test more navigation controller
kkafar 8ebd657
Some light cleanup
kkafar b7281dd
feat(android): prevent native tab selection in TabsContainer
kkafar 64aea23
fix(iOS): harden moreNavigationController push interceptor
kkafar 80ffaa6
Format Android
kkafar 610a4df
Prevent navigation to "preventNativeSelection enabled" tabs that are on
kkafar 7560688
fix(ios): make moreNavigationController push interceptor resilient to…
kkafar ca3317d
Add logging for debugging purposes
kkafar 34af6a9
fix(ios): prevent infinite recursion in moreNavigationController push…
kkafar db5ddee
fix(ios): add missing super calls in RNSTabsScreenViewController (#3839)
kkafar 3ae2472
Improve category naming
kkafar 12f9c59
Remove no Longer needed forward declaration
kkafar b0540f3
Remove debugging setup
kkafar a7c35f1
Add debug log when we fail to find a table view & document unbounded DFS
kkafar 492da4f
Add comment documenting assumption of event asynchornicity
kkafar 1e1b966
refactor(ios): replace associated object with UIKit parent chain lookup
kkafar 3267fa0
style(ios): use C++ casts in rns_pushViewController
kkafar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
47 changes: 47 additions & 0 deletions
47
.../java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionPreventedEvent.kt
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.swmansion.rnscreens.gamma.tabs.host.event | ||
|
|
||
| import com.facebook.react.bridge.Arguments | ||
| import com.facebook.react.bridge.WritableMap | ||
| import com.facebook.react.uimanager.events.Event | ||
| import com.swmansion.rnscreens.gamma.common.event.NamingAwareEventType | ||
| import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState | ||
|
|
||
| /** | ||
| * React Native event dispatched to JS when a tab selection is prevented because the target | ||
| * screen has `preventNativeSelection` enabled. | ||
| * | ||
| * This event is never coalesced — every prevention is delivered individually. | ||
| */ | ||
| class TabsHostTabSelectionPreventedEvent( | ||
| surfaceId: Int, | ||
| viewId: Int, | ||
| val currentNavState: TabsNavState, | ||
| val preventedScreenKey: String, | ||
| ) : Event<TabsHostTabSelectionPreventedEvent>(surfaceId, viewId), | ||
| NamingAwareEventType { | ||
| override fun getEventName() = EVENT_NAME | ||
|
|
||
| override fun getEventRegistrationName() = EVENT_REGISTRATION_NAME | ||
|
|
||
| override fun canCoalesce(): Boolean = false | ||
|
|
||
| override fun getEventData(): WritableMap? = | ||
| Arguments.createMap().apply { | ||
| putString(EK_SELECTED_KEY, currentNavState.selectedKey) | ||
| putInt(EK_PROVENANCE, currentNavState.provenance) | ||
| putString(EK_PREVENTED_KEY, preventedScreenKey) | ||
| } | ||
|
|
||
| companion object : NamingAwareEventType { | ||
| const val EVENT_NAME = "topTabSelectionPrevented" | ||
| const val EVENT_REGISTRATION_NAME = "onTabSelectionPrevented" | ||
|
|
||
| private const val EK_SELECTED_KEY = "selectedScreenKey" | ||
| private const val EK_PROVENANCE = "provenance" | ||
| private const val EK_PREVENTED_KEY = "preventedScreenKey" | ||
|
|
||
| override fun getEventName() = EVENT_NAME | ||
|
|
||
| override fun getEventRegistrationName() = EVENT_REGISTRATION_NAME | ||
| } | ||
| } |
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
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
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
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
124 changes: 124 additions & 0 deletions
124
apps/src/tests/single-feature-tests/tabs/test-tabs-prevent-native-selection.tsx
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| import React from 'react'; | ||
| import type { Scenario } from '../../shared/helpers'; | ||
| import { Button, Text, View } from 'react-native'; | ||
| import { | ||
| type TabRouteConfig, | ||
| DEFAULT_TAB_ROUTE_OPTIONS, | ||
| useTabsNavigationContext, | ||
| TabsContainerWithHostConfigContext, | ||
| } from '../../../shared/gamma/containers/tabs'; | ||
| import { CenteredLayoutView } from '../../../shared/CenteredLayoutView'; | ||
| import { ToastProvider, useToast } from '../../../shared/'; | ||
| import Colors from '../../../shared/styling/Colors'; | ||
|
|
||
| const SCENARIO: Scenario = { | ||
| name: 'Prevent native selection', | ||
| key: 'test-tabs-prevent-native-selection', | ||
| details: 'Test preventNativeSelection prop on TabsScreen', | ||
| platforms: ['android', 'ios'], | ||
| AppComponent: App, | ||
| }; | ||
|
|
||
| export default SCENARIO; | ||
|
|
||
| function ContentView() { | ||
| const nav = useTabsNavigationContext(); | ||
|
|
||
| const preventNativeSelection = | ||
| nav.routeOptions.preventNativeSelection ?? false; | ||
|
|
||
| return ( | ||
| <CenteredLayoutView> | ||
| <Text style={{ fontWeight: 'bold', textAlign: 'center' }}> | ||
| {nav.routeKey} | ||
| </Text> | ||
| <Text style={{ textAlign: 'center' }}> | ||
| preventNativeSelection: {JSON.stringify(preventNativeSelection)} | ||
| </Text> | ||
| <Button | ||
| title="Toggle preventNativeSelection" | ||
| onPress={() => | ||
| nav.setRouteOptions(nav.routeKey, { | ||
| preventNativeSelection: !preventNativeSelection, | ||
| }) | ||
| } | ||
| /> | ||
| <TabsNavigationButtons /> | ||
| </CenteredLayoutView> | ||
| ); | ||
| } | ||
|
|
||
| function TabsNavigationButtons() { | ||
| const nav = useTabsNavigationContext(); | ||
|
|
||
| return ( | ||
| <View> | ||
| <Button title="Select First" onPress={() => nav.selectTab('First')} /> | ||
| <Button title="Select Second" onPress={() => nav.selectTab('Second')} /> | ||
| <Button title="Select Third" onPress={() => nav.selectTab('Third')} /> | ||
| <Button title="Select Fourth" onPress={() => nav.selectTab('Fourth')} /> | ||
| <Button title="Select Fifth" onPress={() => nav.selectTab('Fifth')} /> | ||
| <Button title="Select Sixth" onPress={() => nav.selectTab('Sixth')} /> | ||
| </View> | ||
| ); | ||
| } | ||
|
|
||
| const ROUTE_CONFIGS: TabRouteConfig[] = [ | ||
| { | ||
| name: 'First', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'First' }, | ||
| }, | ||
| { | ||
| name: 'Second', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Second' }, | ||
| }, | ||
| { | ||
| name: 'Third', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Third' }, | ||
| }, | ||
| { | ||
| name: 'Fourth', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Fourth' }, | ||
| }, | ||
| { | ||
| name: 'Fifth', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Fifth' }, | ||
| }, | ||
| { | ||
| name: 'Sixth', | ||
| Component: ContentView, | ||
| options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Sixth' }, | ||
| }, | ||
| ]; | ||
|
|
||
| export function App() { | ||
| return ( | ||
| <ToastProvider> | ||
| <AppContents /> | ||
| </ToastProvider> | ||
| ); | ||
| } | ||
|
|
||
| function AppContents() { | ||
| const toast = useToast(); | ||
|
|
||
| return ( | ||
| <TabsContainerWithHostConfigContext | ||
| routeConfigs={ROUTE_CONFIGS} | ||
| onTabSelectionPrevented={event => { | ||
| const message = `onTabSelectionPrevented: ${event.nativeEvent.preventedScreenKey}`; | ||
| console.warn(message); | ||
| toast.push({ | ||
| message: message, | ||
| backgroundColor: Colors.GreenLight60, | ||
| }); | ||
| }} | ||
| /> | ||
| ); | ||
| } | ||
|
|
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.