From e0bc64f027ee8e88476cdbbc56df19cf8929469e Mon Sep 17 00:00:00 2001
From: Dominic Go <18517029+dominicstop@users.noreply.github.com>
Date: Sun, 14 Nov 2021 15:14:58 +0800
Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20Types=20-=20Added=20Types?=
=?UTF-8?q?=20For=20`ContextMenuButton`?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/ContextMenuButton.ios.js | 214 -------------------
src/components/ContextMenuButton.js | 11 -
src/components/ContextMenuButton.tsx | 261 ++++++++++++++++++++++++
3 files changed, 261 insertions(+), 225 deletions(-)
delete mode 100644 src/components/ContextMenuButton.ios.js
delete mode 100644 src/components/ContextMenuButton.js
create mode 100644 src/components/ContextMenuButton.tsx
diff --git a/src/components/ContextMenuButton.ios.js b/src/components/ContextMenuButton.ios.js
deleted file mode 100644
index cbce4ed..0000000
--- a/src/components/ContextMenuButton.ios.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import React from 'react';
-import { StyleSheet, View, TouchableOpacity } from 'react-native';
-import Proptypes from 'prop-types';
-
-import { RNIContextMenuButton } from '../native_components/RNIContextMenuButton';
-
-import { ActionSheetFallback } from '../functions/ActionSheetFallback';
-import { ContextMenuView } from './ContextMenuView';
-
-import { LIB_ENV } from '../constants/LibEnv';
-
-const NATIVE_PROP_KEYS = {
- // props: values --------
- menuConfig: 'menuConfig',
- // props: flags ---------------------------
- enableContextMenu : 'enableContextMenu' ,
- isMenuPrimaryAction: 'isMenuPrimaryAction',
- // props: events --------------------
- onMenuWillShow : 'onMenuWillShow' ,
- onMenuWillHide : 'onMenuWillHide' ,
- onMenuWillCancel: 'onMenuWillCancel',
- onMenuDidShow : 'onMenuDidShow' ,
- onMenuDidHide : 'onMenuDidHide' ,
- onMenuDidCancel : 'onMenuDidCancel' ,
- // props: onPress events ----------
- onPressMenuItem: 'onPressMenuItem',
-};
-
-
-export class ContextMenuButton extends React.PureComponent {
- static proptypes = {
- menuConfig: Proptypes.object,
- // flags ------------------------------
- enableContextMenu : Proptypes.bool,
- isMenuPrimaryAction : Proptypes.bool,
- useActionSheetFallback: Proptypes.bool,
- wrapNativeComponent : Proptypes.bool,
- // events -----------------------
- onMenuWillShow : Proptypes.func,
- onMenuWillHide : Proptypes.func,
- onMenuWillCancel: Proptypes.func,
- onMenuDidShow : Proptypes.func,
- onMenuDidHide : Proptypes.func,
- onMenuDidCancel : Proptypes.func,
- // onPress events --------------
- onPressMenuItem: Proptypes.func,
- };
-
- static defaultProps = {
- enableContextMenu : true,
- wrapNativeComponent : true,
- useActionSheetFallback: !LIB_ENV.isContextMenuViewSupported,
- };
-
- constructor(props){
- super(props);
-
- this.state = {
- menuVisible: false,
- };
- };
-
- getProps(){
- const otherProps = { ...this.props };
- const nativeProps = {};
-
- const nativeKeys = Object.keys(NATIVE_PROP_KEYS);
-
- for (const key of nativeKeys) {
- nativeProps[key] = otherProps[key];
- delete otherProps[key];
- };
-
- return { nativeProps, ...otherProps };
- };
-
- //#region - Event Handlers
- _handleOnLongPress = async () => {
- const { menuConfig, ...props } = this.props;
- const item = await ActionSheetFallback.show(menuConfig);
-
- if(item == null){
- // cancelled pressed
- props.onMenuDidCancel?.();
-
- } else {
- props.onPressMenuItem?.({nativeEvent: {...item}});
- };
- };
-
- _handleOnMenuWillShow = (event) => {
- const { onMenuWillShow } = this.props;
- onMenuWillShow?.(event);
-
- this.setState({menuVisible: true});
- };
-
- _handleOnMenuWillHide = (event) => {
- const { onMenuWillHide } = this.props;
- onMenuWillHide?.(event);
-
- this.setState({menuVisible: false});
- };
-
- _handleOnMenuWillCancel = (event) => {
- const { onMenuWillCancel } = this.props;
- onMenuWillCancel?.(event);
- };
-
- _handleOnMenuDidShow = (event) => {
- const { onMenuDidShow } = this.props;
- onMenuDidShow?.(event);
- };
-
- _handleOnMenuDidHide = (event) => {
- const { onMenuDidHide } = this.props;
- onMenuDidHide?.(event);
- };
-
- _handleOnMenuDidCancel = (event) => {
- const { onMenuDidCancel } = this.props;
- onMenuDidCancel?.(event);
- };
-
- _handleOnPressMenuItem = (event) => {
- this.props.onPressMenuItem?.(event);
- };
- //#endregion
-
- _renderContextMenuView(){
- const { nativeProps, style, children, ...props } = this.getProps();
- const { menuVisible } = this.state;
-
- const nativeCompProps = {
- ...nativeProps,
- // Native Props: Events ------------------------------------------
- [NATIVE_PROP_KEYS.onMenuWillShow ]: this._handleOnMenuWillShow ,
- [NATIVE_PROP_KEYS.onMenuWillHide ]: this._handleOnMenuWillHide ,
- [NATIVE_PROP_KEYS.onMenuWillCancel]: this._handleOnMenuWillCancel,
- [NATIVE_PROP_KEYS.onMenuDidShow ]: this._handleOnMenuDidShow ,
- [NATIVE_PROP_KEYS.onMenuDidHide ]: this._handleOnMenuDidHide ,
- [NATIVE_PROP_KEYS.onMenuDidCancel ]: this._handleOnMenuDidCancel ,
- // Native Props: OnPress Events --------------------------------
- [NATIVE_PROP_KEYS.onPressMenuItem]: this._handleOnPressMenuItem,
- };
-
- const childItems = React.Children.map(children, child =>
- React.cloneElement(child, {menuVisible})
- );
-
- const nativeComp = (LIB_ENV.isContextMenuButtonSupported? (
-
- {childItems}
-
- ):(
-
- {childItems}
-
- ));
-
- if(props.wrapNativeComponent){
- return(
-
- {nativeComp}
-
- );
- } else {
- return nativeComp;
- };
- };
-
- render(){
- const { useActionSheetFallback } = this.props;
- const useContextMenu =
- (LIB_ENV.isContextMenuViewSupported && !useActionSheetFallback);
-
- return(
- useContextMenu? this._renderContextMenuView() :
- useActionSheetFallback? (
-
- {this.props.children}
-
- ):(
-
- {this.props.children}
-
- )
- );
- };
-};
-
-const styles = StyleSheet.create({
- menuButton: {
- backgroundColor: 'transparent',
- },
- wrappedMenuButton: {
- flex: 1,
- },
-});
\ No newline at end of file
diff --git a/src/components/ContextMenuButton.js b/src/components/ContextMenuButton.js
deleted file mode 100644
index 5cc1631..0000000
--- a/src/components/ContextMenuButton.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { View } from 'react-native';
-
-
-export function ContextMenuButton(props){
- return(
-
- {props.children}
-
- );
-};
\ No newline at end of file
diff --git a/src/components/ContextMenuButton.tsx b/src/components/ContextMenuButton.tsx
new file mode 100644
index 0000000..ad9e5e3
--- /dev/null
+++ b/src/components/ContextMenuButton.tsx
@@ -0,0 +1,261 @@
+import React from 'react';
+import { StyleSheet, View, TouchableOpacity, ViewProps } from 'react-native';
+
+import { RNIContextMenuButton, RNIContextMenuButtonBaseProps } from '../native_components/RNIContextMenuButton';
+
+import type { OnMenuWillShowEvent, OnMenuWillHideEvent, OnMenuDidShowEvent, OnMenuDidHideEvent, OnMenuWillCancelEvent, OnMenuDidCancelEvent, OnPressMenuItemEvent } from '../types/MenuEvents';
+
+// @ts-ignore - TODO
+import { ActionSheetFallback } from '../functions/ActionSheetFallback';
+import { ContextMenuView } from './ContextMenuView';
+
+import { LIB_ENV, IS_PLATFORM_IOS } from '../constants/LibEnv';
+
+
+export type ContextMenuButtonBaseProps = Pick & {
+ useActionSheetFallback?: boolean;
+ wrapNativeComponent?: boolean;
+};
+
+export type ContextMenuButtonProps =
+ ViewProps & ContextMenuButtonBaseProps;
+
+export type ContextMenuButtonState = {
+ menuVisible: boolean;
+};
+
+export class ContextMenuButton extends React.PureComponent {
+
+ constructor(props: ContextMenuButtonProps){
+ super(props);
+
+ this.state = {
+ menuVisible: false,
+ };
+ };
+
+ getProps = () => {
+ const {
+ menuConfig,
+ enableContextMenu,
+ isMenuPrimaryAction,
+ useActionSheetFallback,
+ wrapNativeComponent,
+ onMenuWillShow,
+ onMenuWillHide,
+ onMenuWillCancel,
+ onMenuDidShow,
+ onMenuDidHide,
+ onMenuDidCancel,
+ onPressMenuItem,
+ ...viewProps
+ } = this.props;
+
+ return {
+ // A. Provide default values to props...
+ enableContextMenu: (
+ enableContextMenu ?? true
+ ),
+ wrapNativeComponent: (
+ wrapNativeComponent ?? true
+ ),
+ useActionSheetFallback: (
+ useActionSheetFallback ?? !LIB_ENV.isContextMenuViewSupported
+ ),
+
+ // B. Pass down props...
+ menuConfig,
+ isMenuPrimaryAction,
+ onMenuWillShow,
+ onMenuWillHide,
+ onMenuWillCancel,
+ onMenuDidShow,
+ onMenuDidHide,
+ onMenuDidCancel,
+ onPressMenuItem,
+ // C. Move all the default view-related
+ // props here...
+ viewProps
+ };
+ };
+
+ //#region - Event Handlers
+ _handleOnLongPress = async () => {
+ const props = this.props;
+
+ const selectedItem =
+ await ActionSheetFallback.show(props.menuConfig);
+
+ if(selectedItem == null){
+ // A. cancelled pressed
+ props.onMenuDidCancel?.({
+ isUsingActionSheetFallback: true
+ });
+
+ } else {
+ // B. an item was selected
+ props.onPressMenuItem?.({
+ isUsingActionSheetFallback: true,
+ nativeEvent: {
+ ...selectedItem,
+ }
+ });
+ };
+ };
+
+ _handleOnMenuWillShow: OnMenuWillShowEvent = (event) => {
+ this.props.onMenuWillShow?.(event);
+ event.stopPropagation();
+
+ this.setState({menuVisible: true});
+ };
+
+ _handleOnMenuWillHide: OnMenuWillHideEvent = (event) => {
+ this.props.onMenuWillHide?.(event);
+ event.stopPropagation();
+
+ this.setState({menuVisible: false});
+ };
+
+ _handleOnMenuWillCancel: OnMenuWillCancelEvent = (event) => {
+ this.props.onMenuWillCancel?.(event);
+ event.stopPropagation();
+ };
+
+ _handleOnMenuDidShow: OnMenuDidShowEvent = (event) => {
+ this.props.onMenuDidShow?.(event);
+ event.stopPropagation();
+ };
+
+ _handleOnMenuDidHide: OnMenuDidHideEvent = (event) => {
+ this.props.onMenuDidHide?.(event);
+ event.stopPropagation();
+ };
+
+ _handleOnMenuDidCancel: OnMenuDidCancelEvent = (event) => {
+ this.props.onMenuDidCancel?.(event);
+
+ // guard: event is a native event
+ if(event.isUsingActionSheetFallback) return;
+ event.stopPropagation();
+ };
+
+ _handleOnPressMenuItem: OnPressMenuItemEvent = (event) => {
+ this.props.onPressMenuItem?.(event);
+
+ // guard: event is a native event
+ if(event.isUsingActionSheetFallback) return;
+ event.stopPropagation();
+ };
+ //#endregion
+
+ render(){
+ const props = this.getProps();
+ const { menuVisible } = this.state;
+
+ const isNativeComponentSupported = (
+ LIB_ENV.isContextMenuButtonSupported &&
+ !props.useActionSheetFallback
+ );
+
+ const shouldUseActionSheetFallback = (
+ IS_PLATFORM_IOS && props.useActionSheetFallback
+ );
+
+ const nativeComponentProps: RNIContextMenuButtonBaseProps = {
+ menuConfig: props.menuConfig,
+ enableContextMenu: props.enableContextMenu,
+ isMenuPrimaryAction: props.isMenuPrimaryAction,
+
+ // event handlers
+ onMenuWillShow : this._handleOnMenuWillShow ,
+ onMenuWillHide : this._handleOnMenuWillHide ,
+ onMenuDidShow : this._handleOnMenuDidShow ,
+ onMenuDidHide : this._handleOnMenuDidHide ,
+ onMenuDidCancel : this._handleOnMenuDidCancel ,
+ onMenuWillCancel: this._handleOnMenuWillCancel,
+ onPressMenuItem : this._handleOnPressMenuItem ,
+ };
+
+ if(isNativeComponentSupported){
+ const childItems = React.Children.map(this.props.children, child =>
+ //@ts-ignore
+ React.cloneElement(child, {menuVisible})
+ );
+
+ const nativeComponent = (LIB_ENV.isContextMenuButtonSupported? (
+
+ {childItems}
+
+ ):(
+
+ {childItems}
+
+ ));
+
+ if(props.wrapNativeComponent){
+ return(
+
+ {nativeComponent}
+
+ );
+ } else {
+ return nativeComponent;
+ };
+
+ } else if(shouldUseActionSheetFallback){
+ return (
+
+ {this.props.children}
+
+ );
+
+ } else {
+ return (
+
+ {this.props.children}
+
+ );
+ };
+ };
+};
+
+const styles = StyleSheet.create({
+ menuButton: {
+ backgroundColor: 'transparent',
+ },
+ wrappedMenuButton: {
+ flex: 1,
+ },
+});
\ No newline at end of file