-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: In React Native 0.75, we will remove UIManager.showPopupMenu(), UIManager.dismissPopupMenu(). To replace that API, we are introducing this <PopupMenuAndroid> component. This component works in both Fabric and Paper! For the usage, please see PopupMenuAndroidExample.js. Changelog: [Android][Added] - Introduce PopupMenuAndroid to replace UIManager.showPopupMenu() Reviewed By: mdvacca Differential Revision: D52712758 fbshipit-source-id: a87628a168d64fabbcc4d0f7b694fa639a927448
- Loading branch information
1 parent
7f549ec
commit 35308a7
Showing
15 changed files
with
499 additions
and
0 deletions.
There are no files selected for viewing
69 changes: 69 additions & 0 deletions
69
packages/react-native/Libraries/Components/PopupMenuAndroid/PopupMenuAndroid.android.js
This file contains 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,69 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
* @flow strict-local | ||
*/ | ||
|
||
import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; | ||
import type {SyntheticEvent} from '../../Types/CoreEventTypes'; | ||
import type {RefObject} from 'react'; | ||
|
||
import PopupMenuAndroidNativeComponent, { | ||
Commands, | ||
} from './PopupMenuAndroidNativeComponent'; | ||
import nullthrows from 'nullthrows'; | ||
import * as React from 'react'; | ||
import {useCallback, useImperativeHandle, useRef} from 'react'; | ||
|
||
type PopupMenuSelectionEvent = SyntheticEvent< | ||
$ReadOnly<{ | ||
item: number, | ||
}>, | ||
>; | ||
|
||
export type PopupMenuAndroidInstance = { | ||
+show: () => void, | ||
}; | ||
|
||
type Props = { | ||
menuItems: $ReadOnlyArray<string>, | ||
onSelectionChange: number => void, | ||
children: React.Node, | ||
instanceRef: RefObject<?PopupMenuAndroidInstance>, | ||
}; | ||
|
||
export default function PopupMenuAndroid({ | ||
menuItems, | ||
onSelectionChange, | ||
children, | ||
instanceRef, | ||
}: Props): React.Node { | ||
const nativeRef = useRef<React.ElementRef<HostComponent<mixed>> | null>(null); | ||
const _onSelectionChange = useCallback( | ||
(event: PopupMenuSelectionEvent) => { | ||
onSelectionChange(event.nativeEvent.item); | ||
}, | ||
[onSelectionChange], | ||
); | ||
|
||
useImperativeHandle(instanceRef, ItemViewabilityInstance => { | ||
return { | ||
show() { | ||
Commands.show(nullthrows(nativeRef.current)); | ||
}, | ||
}; | ||
}); | ||
|
||
return ( | ||
<PopupMenuAndroidNativeComponent | ||
ref={nativeRef} | ||
onSelectionChange={_onSelectionChange} | ||
menuItems={menuItems}> | ||
{children} | ||
</PopupMenuAndroidNativeComponent> | ||
); | ||
} |
24 changes: 24 additions & 0 deletions
24
packages/react-native/Libraries/Components/PopupMenuAndroid/PopupMenuAndroid.d.ts
This file contains 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,24 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
*/ | ||
|
||
import type * as React from 'react'; | ||
import {HostComponent} from '../../../types/public/ReactNativeTypes'; | ||
|
||
type PopupMenuAndroidInstance = { | ||
show: () => void; | ||
}; | ||
|
||
type Props = { | ||
menuItems: Array<string>; | ||
onSelectionChange: (number) => void; | ||
children: React.ReactNode | undefined; | ||
instanceRef: React.ElementRef<HostComponent<PopupMenuAndroidInstance>>; | ||
}; | ||
|
||
declare class PopupMenuAndroid extends React.Component<Props> {} |
33 changes: 33 additions & 0 deletions
33
packages/react-native/Libraries/Components/PopupMenuAndroid/PopupMenuAndroid.js
This file contains 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,33 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
* @flow strict-local | ||
*/ | ||
|
||
import type {RefObject} from 'react'; | ||
import type {Node} from 'react'; | ||
|
||
import * as React from 'react'; | ||
|
||
const UnimplementedView = require('../UnimplementedViews/UnimplementedView'); | ||
|
||
export type PopupMenuAndroidInstance = { | ||
+show: () => void, | ||
}; | ||
|
||
type Props = { | ||
menuItems: $ReadOnlyArray<string>, | ||
onSelectionChange: number => void, | ||
children: Node, | ||
instanceRef: RefObject<?PopupMenuAndroidInstance>, | ||
}; | ||
|
||
function PopupMenuAndroid(props: Props): Node { | ||
return <UnimplementedView />; | ||
} | ||
|
||
export default PopupMenuAndroid; |
13 changes: 13 additions & 0 deletions
13
...ges/react-native/Libraries/Components/PopupMenuAndroid/PopupMenuAndroidNativeComponent.js
This file contains 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,13 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
* @flow strict-local | ||
*/ | ||
|
||
export * from '../../../src/private/specs/components/PopupMenuAndroidNativeComponent'; | ||
import PopupMenuAndroidNativeComponent from '../../../src/private/specs/components/PopupMenuAndroidNativeComponent'; | ||
export default PopupMenuAndroidNativeComponent; |
This file contains 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 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 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
36 changes: 36 additions & 0 deletions
36
.../ReactAndroid/src/main/java/com/facebook/react/views/popupmenu/PopupMenuSelectionEvent.kt
This file contains 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,36 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.views.popupmenu | ||
|
||
import com.facebook.react.bridge.Arguments | ||
import com.facebook.react.bridge.WritableMap | ||
import com.facebook.react.uimanager.events.Event | ||
import com.facebook.react.uimanager.events.RCTEventEmitter | ||
|
||
class PopupMenuSelectionEvent(surfaceId: Int, viewId: Int, val item: Int) : | ||
Event<PopupMenuSelectionEvent>(surfaceId, viewId) { | ||
|
||
override fun getEventName(): String { | ||
return EVENT_NAME | ||
} | ||
|
||
override fun getEventData(): WritableMap { | ||
val eventData: WritableMap = Arguments.createMap() | ||
eventData.putInt("target", viewTag) | ||
eventData.putDouble("item", item.toDouble()) | ||
return eventData | ||
} | ||
|
||
override fun dispatch(rctEventEmitter: RCTEventEmitter) { | ||
rctEventEmitter.receiveEvent(viewTag, eventName, eventData) | ||
} | ||
|
||
companion object { | ||
const val EVENT_NAME: String = "topSelectionChange" | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
.../ReactAndroid/src/main/java/com/facebook/react/views/popupmenu/ReactPopupMenuContainer.kt
This file contains 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,50 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.views.popupmenu | ||
|
||
import android.content.Context | ||
import android.os.Build | ||
import android.view.Menu | ||
import android.widget.FrameLayout | ||
import android.widget.PopupMenu | ||
import com.facebook.react.bridge.ReactContext | ||
import com.facebook.react.bridge.ReadableArray | ||
import com.facebook.react.uimanager.UIManagerHelper | ||
|
||
class ReactPopupMenuContainer(context: Context) : FrameLayout(context) { | ||
private var menuItems: ReadableArray? = null | ||
|
||
fun setMenuItems(items: ReadableArray?) { | ||
menuItems = items | ||
} | ||
|
||
fun showPopupMenu() { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { | ||
val view = getChildAt(0) | ||
val popupMenu = PopupMenu(context, view) | ||
var menu: Menu? = null | ||
menu = popupMenu.menu | ||
val items = menuItems | ||
if (items != null) { | ||
for (i in 0 until items.size()) { | ||
menu.add(Menu.NONE, Menu.NONE, i, items.getString(i)) | ||
} | ||
} | ||
popupMenu.setOnMenuItemClickListener { menuItem -> | ||
val reactContext = context as ReactContext | ||
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) | ||
if (eventDispatcher != null) { | ||
val surfaceId = UIManagerHelper.getSurfaceId(reactContext) | ||
eventDispatcher.dispatchEvent(PopupMenuSelectionEvent(surfaceId, id, menuItem.order)) | ||
} | ||
true | ||
} | ||
popupMenu.show() | ||
} | ||
} | ||
} |
Oops, something went wrong.