From ad787810ac1f43afafbf0b88dde3b50fa09f5c0f Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:15:45 +0800 Subject: [PATCH 1/8] fix context menu when long press on url and email link --- .../BaseAnchorForCommentsOnly.js | 24 +++++++-- src/components/AnchorForCommentsOnly/index.js | 28 +++++++--- .../HTMLRenderers/ImageRenderer.js | 49 ++++++++++------- .../PreRenderer/BasePreRenderer.js | 45 +++++++++++++--- .../HTMLRenderers/PreRenderer/index.js | 15 +++++- .../index.js | 53 ++++++------------- .../index.native.js | 28 ++++------ src/components/PressableWithoutFocus.js | 11 +++- src/components/ReportActionItem/IOUAction.js | 11 ++++ src/components/ReportActionItem/IOUPreview.js | 44 ++++++++++++++- src/components/ShowContextMenuContext.js | 34 ++++++++++++ src/pages/home/report/ReportActionItem.js | 48 +++++++++++------ 12 files changed, 280 insertions(+), 110 deletions(-) create mode 100644 src/components/ShowContextMenuContext.js diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js index 77cc720445f9..01152303296f 100644 --- a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js +++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js @@ -1,6 +1,7 @@ import _ from 'underscore'; import React from 'react'; import {StyleSheet} from 'react-native'; +import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; import Text from '../Text'; @@ -11,13 +12,28 @@ import Tooltip from '../Tooltip'; import canUseTouchScreen from '../../libs/canUseTouchscreen'; import styles from '../../styles/styles'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; -import {propTypes as anchorForCommentsOnlyPropTypes, defaultProps} from './anchorForCommentsOnlyPropTypes'; +import { + propTypes as anchorForCommentsOnlyPropTypes, + defaultProps as anchorForCommentsOnlyDefaultProps, +} from './anchorForCommentsOnlyPropTypes'; const propTypes = { + /** Press in handler for the link */ + onPressIn: PropTypes.func, + + /** Press out handler for the link */ + onPressOut: PropTypes.func, + ...anchorForCommentsOnlyPropTypes, ...windowDimensionsPropTypes, }; +const defaultProps = { + onPressIn: undefined, + onPressOut: undefined, + ...anchorForCommentsOnlyDefaultProps, +}; + /* * This is a default anchor component for regular links. */ @@ -45,6 +61,9 @@ const BaseAnchorForCommentsOnly = (props) => { ); } } + onPress={linkProps.onPress} + onPressIn={props.onPressIn} + onPressOut={props.onPressOut} > { rel: props.rel, target: props.target, }} - // eslint-disable-next-line react/jsx-props-no-spreading - {...linkProps} + href={linkProps.href} // eslint-disable-next-line react/jsx-props-no-spreading {...rest} > diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js index 1526e78007fe..88010285a09d 100644 --- a/src/components/AnchorForCommentsOnly/index.js +++ b/src/components/AnchorForCommentsOnly/index.js @@ -1,11 +1,27 @@ import React from 'react'; -import * as anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes'; +import _ from 'underscore'; +import {propTypes as anchorForCommentsOnlyPropTypes, defaultProps} from './anchorForCommentsOnlyPropTypes'; import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly'; +import canUseTouchScreen from '../../libs/canUseTouchscreen'; +import ControlSelection from '../../libs/ControlSelection'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; -// eslint-disable-next-line react/jsx-props-no-spreading -const AnchorForCommentsOnly = props => ; -AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes.propTypes; -AnchorForCommentsOnly.defaultProps = anchorForCommentsOnlyPropTypes.defaultProps; +const propTypes = { + ...anchorForCommentsOnlyPropTypes, + ...windowDimensionsPropTypes, +}; + +const AnchorForCommentsOnly = props => ( + props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} + // eslint-disable-next-line react/jsx-props-no-spreading + {...(_.omit(props, ['onPressIn', 'onPressOut']))} + /> +); + +AnchorForCommentsOnly.propTypes = propTypes; +AnchorForCommentsOnly.defaultProps = defaultProps; AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly'; -export default AnchorForCommentsOnly; +export default withWindowDimensions(AnchorForCommentsOnly); diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js index f3e9009a72ca..cef91ba9a9e2 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js @@ -6,6 +6,7 @@ import styles from '../../../styles/styles'; import ThumbnailImage from '../../ThumbnailImage'; import PressableWithoutFocus from '../../PressableWithoutFocus'; import CONST from '../../../CONST'; +import {ShowContextMenuContext, showContextMenuForReport} from '../../ShowContextMenuContext'; const ImageRenderer = (props) => { const htmlAttribs = props.tnode.attributes; @@ -57,27 +58,37 @@ const ImageRenderer = (props) => { imageHeight={imageHeight} /> ) : ( - - {({show}) => ( - + {({ + anchor, + reportID, + action, + checkIfContextMenuActive, + }) => ( + - - + {({show}) => ( + showContextMenuForReport(event, anchor, reportID, action, checkIfContextMenuActive)} + > + + + )} + )} - + ); }; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js index 5edafb4dc04d..25ea94e0ae6b 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js @@ -1,28 +1,59 @@ import React, {forwardRef} from 'react'; import {ScrollView} from 'react-native-gesture-handler'; -import {View} from 'react-native'; +import {Pressable} from 'react-native'; +import PropTypes from 'prop-types'; import _ from 'underscore'; import htmlRendererPropTypes from '../htmlRendererPropTypes'; import withLocalize from '../../../withLocalize'; +import {ShowContextMenuContext, showContextMenuForReport} from '../../../ShowContextMenuContext'; + +const propTypes = { + /** Press in handler for the code block */ + onPressIn: PropTypes.func, + + /** Press out handler for the code block */ + onPressOut: PropTypes.func, + + ...htmlRendererPropTypes, +}; + +const defaultProps = { + onPressIn: undefined, + onPressOut: undefined, +}; const BasePreRenderer = forwardRef((props, ref) => { const TDefaultRenderer = props.TDefaultRenderer; - const defaultRendererProps = _.omit(props, ['TDefaultRenderer']); + const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'onPressIn', 'onPressOut', 'onLongPress']); return ( - true}> - {/* eslint-disable-next-line react/jsx-props-no-spreading */} - - + + {({ + anchor, + reportID, + action, + checkIfContextMenuActive, + }) => ( + showContextMenuForReport(event, anchor, reportID, action, checkIfContextMenuActive)} + > + {/* eslint-disable-next-line react/jsx-props-no-spreading */} + + + )} + ); }); BasePreRenderer.displayName = 'BasePreRenderer'; -BasePreRenderer.propTypes = htmlRendererPropTypes; +BasePreRenderer.propTypes = propTypes; +BasePreRenderer.defaultProps = defaultProps; export default withLocalize(BasePreRenderer); diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js index 59c05e73ed97..e8043491352e 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js @@ -3,6 +3,15 @@ import _ from 'underscore'; import withLocalize from '../../../withLocalize'; import htmlRendererPropTypes from '../htmlRendererPropTypes'; import BasePreRenderer from './BasePreRenderer'; +import compose from '../../../../libs/compose'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../../../withWindowDimensions'; +import canUseTouchScreen from '../../../../libs/canUseTouchscreen'; +import ControlSelection from '../../../../libs/ControlSelection'; + +const propTypes = { + ...htmlRendererPropTypes, + ...windowDimensionsPropTypes, +}; class PreRenderer extends React.Component { constructor(props) { @@ -55,6 +64,8 @@ class PreRenderer extends React.Component { render() { return ( this.props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} // eslint-disable-next-line react/jsx-props-no-spreading {...this.props} ref={el => this.ref = el} @@ -63,6 +74,6 @@ class PreRenderer extends React.Component { } } -PreRenderer.propTypes = htmlRendererPropTypes; +PreRenderer.propTypes = propTypes; -export default withLocalize(PreRenderer); +export default compose(withLocalize, withWindowDimensions)(PreRenderer); diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index a6b21a59e1cb..78168a9f41a5 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import React, {Component} from 'react'; import {Pressable} from 'react-native'; -import {LongPressGestureHandler, State} from 'react-native-gesture-handler'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import styles from '../../styles/styles'; import hasHoverSupport from '../../libs/hasHoverSupport'; @@ -12,7 +11,6 @@ import hasHoverSupport from '../../libs/hasHoverSupport'; class PressableWithSecondaryInteraction extends Component { constructor(props) { super(props); - this.callSecondaryInteractionWithMappedEvent = this.callSecondaryInteractionWithMappedEvent.bind(this); this.executeSecondaryInteractionOnContextMenu = this.executeSecondaryInteractionOnContextMenu.bind(this); } @@ -27,27 +25,6 @@ class PressableWithSecondaryInteraction extends Component { this.pressableRef.removeEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu); } - /** - * @param {Object} e - */ - callSecondaryInteractionWithMappedEvent(e) { - if ((e.nativeEvent.state !== State.ACTIVE) || hasHoverSupport()) { - return; - } - - // Map gesture event to normal Responder event - const { - absoluteX, absoluteY, locationX, locationY, - } = e.nativeEvent; - const mapEvent = { - ...e, - nativeEvent: { - ...e.nativeEvent, pageX: absoluteX, pageY: absoluteY, x: locationX, y: locationY, - }, - }; - this.props.onSecondaryInteraction(mapEvent); - } - /** * @param {contextmenu} e - A right-click MouseEvent. * https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event @@ -65,19 +42,23 @@ class PressableWithSecondaryInteraction extends Component { // On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text. return ( - - this.pressableRef = el} - // eslint-disable-next-line react/jsx-props-no-spreading - {...defaultPressableProps} - > - {this.props.children} - - + { + if (hasHoverSupport()) { + return; + } + this.props.onSecondaryInteraction(e); + }} + onPressOut={this.props.onPressOut} + onPress={this.props.onPress} + ref={el => this.pressableRef = el} + // eslint-disable-next-line react/jsx-props-no-spreading + {...defaultPressableProps} + > + {this.props.children} + ); } } diff --git a/src/components/PressableWithSecondaryInteraction/index.native.js b/src/components/PressableWithSecondaryInteraction/index.native.js index efb68e52eb79..f186146b4134 100644 --- a/src/components/PressableWithSecondaryInteraction/index.native.js +++ b/src/components/PressableWithSecondaryInteraction/index.native.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import React, {forwardRef} from 'react'; import {Pressable} from 'react-native'; -import {LongPressGestureHandler, State} from 'react-native-gesture-handler'; import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes'; import Text from '../Text'; import HapticFeedback from '../../libs/HapticFeedback'; @@ -16,28 +15,21 @@ const PressableWithSecondaryInteraction = (props) => { // Use Text node for inline mode to prevent content overflow. const Node = props.inline ? Text : Pressable; return ( - { - if (e.nativeEvent.state !== State.ACTIVE) { - return; - } + { e.preventDefault(); HapticFeedback.trigger(); props.onSecondaryInteraction(e); }} - > - - {props.children} - - - + {...(_.omit(props, 'onLongPress'))} + > + {props.children} + ); }; diff --git a/src/components/PressableWithoutFocus.js b/src/components/PressableWithoutFocus.js index 30668608496f..10ea16c71d06 100644 --- a/src/components/PressableWithoutFocus.js +++ b/src/components/PressableWithoutFocus.js @@ -12,6 +12,9 @@ const propTypes = { /** Callback for onPress event */ onPress: PropTypes.func.isRequired, + /** Callback for onLongPress event */ + onLongPress: PropTypes.func, + /** Styles that should be passed to touchable container */ // eslint-disable-next-line react/forbid-prop-types styles: PropTypes.arrayOf(PropTypes.object), @@ -19,6 +22,7 @@ const propTypes = { const defaultProps = { styles: [], + onLongPress: undefined, }; /** @@ -41,7 +45,12 @@ class PressableWithoutFocus extends React.Component { render() { return ( - this.pressableRef = el} style={this.props.styles}> + this.pressableRef = el} + style={this.props.styles} + > {this.props.children} ); diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 015766612056..ee79914683dc 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -20,6 +20,12 @@ const propTypes = { /** Is this IOUACTION the most recent? */ isMostRecentIOUReportAction: PropTypes.bool.isRequired, + /** Popover context menu anchor, used for showing context menu */ + contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}), + + /** Callback for updating context menu active state, used for showing context menu */ + checkIfContextMenuActive: PropTypes.func, + /* Onyx Props */ /** chatReport associated with iouReport */ chatReport: PropTypes.shape({ @@ -29,6 +35,8 @@ const propTypes = { }; const defaultProps = { + contextMenuAnchor: undefined, + checkIfContextMenuActive: () => {}, chatReport: { participants: [], }, @@ -51,6 +59,9 @@ const IOUAction = (props) => { pendingAction={lodashGet(props.action, 'pendingAction', null)} iouReportID={props.action.originalMessage.IOUReportID.toString()} chatReportID={props.chatReportID} + action={props.action} + contextMenuAnchor={props.contextMenuAnchor} + checkIfContextMenuActive={props.checkIfContextMenuActive} onPayButtonPressed={launchDetailsModal} onPreviewPressed={launchDetailsModal} containerStyles={[styles.cursorPointer]} diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 355c414e48aa..e4d69de3990d 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -24,6 +24,11 @@ import Text from '../Text'; import * as PaymentMethods from '../../libs/actions/PaymentMethods'; import OfflineWithFeedback from '../OfflineWithFeedback'; import walletTermsPropTypes from '../../pages/EnablePayments/walletTermsPropTypes'; +import ControlSelection from '../../libs/ControlSelection'; +import canUseTouchScreen from '../../libs/canUseTouchscreen'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; +import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; +import {showContextMenuForReport} from '../ShowContextMenuContext'; const propTypes = { /** Additional logic for displaying the pay button */ @@ -41,6 +46,15 @@ const propTypes = { /** Callback for the preview pressed */ onPreviewPressed: PropTypes.func, + /** All the data of the action, used for showing context menu */ + action: PropTypes.shape(reportActionPropTypes), + + /** Popover context menu anchor, used for showing context menu */ + contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}), + + /** Callback for updating context menu active state, used for showing context menu */ + checkIfContextMenuActive: PropTypes.func, + /** Extra styles to pass to View wrapper */ // eslint-disable-next-line react/forbid-prop-types containerStyles: PropTypes.arrayOf(PropTypes.object), @@ -85,6 +99,7 @@ const propTypes = { pendingAction: PropTypes.oneOf(_.values(CONST.RED_BRICK_ROAD_PENDING_ACTION)), ...withLocalizePropTypes, + ...windowDimensionsPropTypes, }; const defaultProps = { @@ -92,6 +107,9 @@ const defaultProps = { shouldHidePayButton: false, onPayButtonPressed: null, onPreviewPressed: () => {}, + action: undefined, + contextMenuAnchor: undefined, + checkIfContextMenuActive: () => {}, containerStyles: [], walletTerms: {}, pendingAction: null, @@ -129,8 +147,30 @@ const IOUPreview = (props) => { {style: 'currency', currency: props.iouReport.currency}, ) : ''; const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)]; + + const showContextMenu = (event) => { + // Use action and shouldHidePayButton props to check if we are in IOUDetailsModal, + // if it's true, do nothing when user long press, otherwise show context menu. + if (!props.action && props.shouldHidePayButton) { + return; + } + + showContextMenuForReport( + event, + props.contextMenuAnchor, + props.chatReportID, + props.action, + props.checkIfContextMenuActive, + ); + }; + return ( - + props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} + onLongPress={showContextMenu} + > {reportIsLoading ? @@ -185,6 +225,7 @@ const IOUPreview = (props) => { ); } else { - children = !this.props.draftMessage - ? ( - - ) : ( - this.textInput = el} - report={this.props.report} - shouldDisableEmojiPicker={ - (ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge)) - || ReportUtils.isArchivedRoom(this.props.report) - } - /> - ); + children = ( + + {!this.props.draftMessage + ? ( + + ) : ( + this.textInput = el} + report={this.props.report} + shouldDisableEmojiPicker={ + (ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge)) + || ReportUtils.isArchivedRoom(this.props.report) + } + /> + )} + + ); } return ( Date: Thu, 24 Nov 2022 18:41:25 +0800 Subject: [PATCH 2/8] fix no-trailing-spaces lint error --- src/components/ShowContextMenuContext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ShowContextMenuContext.js b/src/components/ShowContextMenuContext.js index 88cec8a7dbec..1a5ca0d0d18e 100644 --- a/src/components/ShowContextMenuContext.js +++ b/src/components/ShowContextMenuContext.js @@ -7,7 +7,7 @@ ShowContextMenuContext.displayName = 'ShowContextMenuContext'; /** * Show the report action context menu. - * + * * @param {Object} [event] - A press event * @param {Element} anchor - Context menu anchor * @param {String} reportID - Active Report Id From 6023879d2f3cb3aa68aa8dcc175db7455438c4f6 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Thu, 1 Dec 2022 12:04:02 +0800 Subject: [PATCH 3/8] put onPressIn and onPressOut after props spreading --- src/components/AnchorForCommentsOnly/index.js | 5 ++--- .../HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js index 88010285a09d..c8c3b6a54321 100644 --- a/src/components/AnchorForCommentsOnly/index.js +++ b/src/components/AnchorForCommentsOnly/index.js @@ -1,5 +1,4 @@ import React from 'react'; -import _ from 'underscore'; import {propTypes as anchorForCommentsOnlyPropTypes, defaultProps} from './anchorForCommentsOnlyPropTypes'; import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly'; import canUseTouchScreen from '../../libs/canUseTouchscreen'; @@ -13,10 +12,10 @@ const propTypes = { const AnchorForCommentsOnly = props => ( props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} - // eslint-disable-next-line react/jsx-props-no-spreading - {...(_.omit(props, ['onPressIn', 'onPressOut']))} /> ); diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js index e8043491352e..3b2d50b0beda 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js @@ -64,11 +64,11 @@ class PreRenderer extends React.Component { render() { return ( this.props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} - onPressOut={() => ControlSelection.unblock()} // eslint-disable-next-line react/jsx-props-no-spreading {...this.props} ref={el => this.ref = el} + onPressIn={() => this.props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} /> ); } From ca1b3118390a9f1974e4c24545917e7e739069c5 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Fri, 30 Dec 2022 11:16:22 +0800 Subject: [PATCH 4/8] provide default property values for context consumer --- src/components/ShowContextMenuContext.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/ShowContextMenuContext.js b/src/components/ShowContextMenuContext.js index 1a5ca0d0d18e..d063d8ff1eb7 100644 --- a/src/components/ShowContextMenuContext.js +++ b/src/components/ShowContextMenuContext.js @@ -2,15 +2,21 @@ import React from 'react'; import * as ReportActionContextMenu from '../pages/home/report/ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from '../pages/home/report/ContextMenu/ContextMenuActions'; -const ShowContextMenuContext = React.createContext(null); +const ShowContextMenuContext = React.createContext({ + anchor: null, + reportID: null, + action: undefined, + checkIfContextMenuActive: () => {}, +}); + ShowContextMenuContext.displayName = 'ShowContextMenuContext'; /** * Show the report action context menu. * - * @param {Object} [event] - A press event + * @param {Object} event - Press event object * @param {Element} anchor - Context menu anchor - * @param {String} reportID - Active Report Id + * @param {String} reportID - Active Report ID * @param {Object} action - ReportAction for ContextMenu * @param {Function} checkIfContextMenuActive Callback to update context menu active state */ From 12e1013b38b49b71da05e0acc5ee9bd6f89f97f9 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Fri, 30 Dec 2022 11:31:43 +0800 Subject: [PATCH 5/8] avoid 3D-Touch menu when long press on iPad --- src/components/AnchorForCommentsOnly/index.js | 16 +++++----------- .../HTMLRenderers/PreRenderer/index.js | 13 +++---------- src/components/ReportActionItem/IOUPreview.js | 5 +---- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js index c8c3b6a54321..5e93ef00b3bc 100644 --- a/src/components/AnchorForCommentsOnly/index.js +++ b/src/components/AnchorForCommentsOnly/index.js @@ -1,26 +1,20 @@ import React from 'react'; -import {propTypes as anchorForCommentsOnlyPropTypes, defaultProps} from './anchorForCommentsOnlyPropTypes'; +import * as anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes'; import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly'; import canUseTouchScreen from '../../libs/canUseTouchscreen'; import ControlSelection from '../../libs/ControlSelection'; -import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; - -const propTypes = { - ...anchorForCommentsOnlyPropTypes, - ...windowDimensionsPropTypes, -}; const AnchorForCommentsOnly = props => ( props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressIn={() => canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} /> ); -AnchorForCommentsOnly.propTypes = propTypes; -AnchorForCommentsOnly.defaultProps = defaultProps; +AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes.propTypes; +AnchorForCommentsOnly.defaultProps = anchorForCommentsOnlyPropTypes.defaultProps; AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly'; -export default withWindowDimensions(AnchorForCommentsOnly); +export default AnchorForCommentsOnly; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js index 3b2d50b0beda..b964b25cc574 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js @@ -3,16 +3,9 @@ import _ from 'underscore'; import withLocalize from '../../../withLocalize'; import htmlRendererPropTypes from '../htmlRendererPropTypes'; import BasePreRenderer from './BasePreRenderer'; -import compose from '../../../../libs/compose'; -import withWindowDimensions, {windowDimensionsPropTypes} from '../../../withWindowDimensions'; import canUseTouchScreen from '../../../../libs/canUseTouchscreen'; import ControlSelection from '../../../../libs/ControlSelection'; -const propTypes = { - ...htmlRendererPropTypes, - ...windowDimensionsPropTypes, -}; - class PreRenderer extends React.Component { constructor(props) { super(props); @@ -67,13 +60,13 @@ class PreRenderer extends React.Component { // eslint-disable-next-line react/jsx-props-no-spreading {...this.props} ref={el => this.ref = el} - onPressIn={() => this.props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressIn={() => canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} /> ); } } -PreRenderer.propTypes = propTypes; +PreRenderer.propTypes = htmlRendererPropTypes; -export default compose(withLocalize, withWindowDimensions)(PreRenderer); +export default withLocalize(PreRenderer); diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index bbf81151b744..5ab0e0a2a586 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -24,7 +24,6 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import walletTermsPropTypes from '../../pages/EnablePayments/walletTermsPropTypes'; import ControlSelection from '../../libs/ControlSelection'; import canUseTouchScreen from '../../libs/canUseTouchscreen'; -import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; import {showContextMenuForReport} from '../ShowContextMenuContext'; import * as ReportUtils from '../../libs/ReportUtils'; @@ -103,7 +102,6 @@ const propTypes = { pendingAction: PropTypes.oneOf(_.values(CONST.RED_BRICK_ROAD_PENDING_ACTION)), ...withLocalizePropTypes, - ...windowDimensionsPropTypes, }; const defaultProps = { @@ -167,7 +165,7 @@ const IOUPreview = (props) => { return ( props.isSmallScreenWidth && canUseTouchScreen() && ControlSelection.block()} + onPressIn={() => canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} onLongPress={showContextMenu} > @@ -245,7 +243,6 @@ IOUPreview.defaultProps = defaultProps; IOUPreview.displayName = 'IOUPreview'; export default compose( - withWindowDimensions, withLocalize, withOnyx({ personalDetails: { From 44be76dea43df879018ae44a27289eff0ea45189 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Fri, 30 Dec 2022 15:34:49 +0800 Subject: [PATCH 6/8] fix long press on IOU quote message shows IOU details modal issue --- src/components/ReportActionItem/IOUAction.js | 3 +++ src/components/ReportActionItem/IOUQuote.js | 23 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 9291739b6886..d74052fff0e9 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -64,8 +64,11 @@ const IOUAction = (props) => { <> {shouldShowIOUPreview && ( {}, + checkIfContextMenuActive: () => {}, }; const IOUQuote = props => ( @@ -37,6 +51,15 @@ const IOUQuote = props => ( onPress={props.shouldAllowViewDetails ? props.onViewDetailsPressed : () => {}} + onPressIn={() => canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} + onLongPress={event => showContextMenuForReport( + event, + props.contextMenuAnchor, + props.chatReportID, + props.action, + props.checkIfContextMenuActive, + )} style={[styles.flexRow, styles.justifyContentBetween, props.shouldAllowViewDetails ? undefined From 658adf7919a36f5f9ea6e235ce24febe3dc415bd Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Fri, 30 Dec 2022 15:38:14 +0800 Subject: [PATCH 7/8] avoid 3D-Touch menu when long press on IOU pay button on iOS Safari --- src/components/ReportActionItem/IOUPreview.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 5ab0e0a2a586..ad6c9191d10e 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -225,6 +225,8 @@ const IOUPreview = (props) => {