Skip to content
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

Inline auto suggestion #42630

Merged
merged 46 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ce4dfa5
Merge branch 'main' of https://github.com/margelo/expensify-app-fork
perunt May 13, 2024
4908044
Merge branch 'main' of https://github.com/Expensify/App
perunt May 13, 2024
0ef223d
Merge branch 'main' of https://github.com/Expensify/App
perunt May 13, 2024
f213cd1
Merge branch 'main' of https://github.com/Expensify/App
perunt May 13, 2024
3092630
init react-native-keyboard-controller
perunt May 13, 2024
aa6498c
patch
perunt May 13, 2024
bc2819a
patch
perunt May 14, 2024
a40f63f
wrap KeyboardProvider
perunt May 14, 2024
62a085f
CONST
perunt May 15, 2024
e3968e6
AutoCompleteSuggestionsPortal
perunt May 15, 2024
3ad8445
getScrollPosition
perunt May 15, 2024
e29f1d0
move PortalHost
perunt May 15, 2024
a0aa72c
MentionSuggestions
perunt May 15, 2024
6c12336
EmojiSuggestions
perunt May 15, 2024
91d447c
AutoCompleteSuggestions, use measureParentContainerAndReportCursor
perunt May 15, 2024
47f31b5
getBottomSuggestionPadding
perunt May 15, 2024
44877f4
BaseAutoCompleteSuggestions
perunt May 15, 2024
74a13d1
add suggestion to ComposerWithSuggestions
perunt May 15, 2024
2781efe
update Suggestions
perunt May 15, 2024
bf3878b
update SuggestionMention
perunt May 15, 2024
9df7a24
remove onSelectionChange form SuggestionEmoji
perunt May 16, 2024
bd9785d
getCursorPosition
perunt May 16, 2024
0a914d0
add types for selection
perunt May 16, 2024
88beb37
fix types
perunt May 16, 2024
13fad61
adjust the left position
perunt May 16, 2024
704688d
fix animation
perunt May 16, 2024
bf21210
update isAdjustmentNeeded
perunt May 27, 2024
511507c
Merge branch 'main' of https://github.com/Expensify/App into perunt/i…
perunt May 27, 2024
2101813
Merge branch 'main' of https://github.com/Expensify/App into perunt/i…
perunt Jun 4, 2024
bdd584e
remove weird styles
perunt Jun 6, 2024
4e5f726
adjust getBottomSuggestionPadding
perunt Jun 6, 2024
4d05e36
iOS: Fixes textinput onscroll event payload
perunt Jun 6, 2024
a852882
remove old patch
perunt Jun 6, 2024
d8dfad4
bring back
perunt Jun 6, 2024
7ae98a8
lint
perunt Jun 6, 2024
aedb9b0
ts
perunt Jun 6, 2024
1f6eaa4
safe selectionEnd
perunt Jun 6, 2024
96064d7
fix scroll error
perunt Jun 7, 2024
260f036
clean
perunt Jun 7, 2024
b5be090
Merge branch 'main' of https://github.com/Expensify/App into perunt/i…
perunt Jun 7, 2024
2ad390c
rename patch
perunt Jun 7, 2024
9d7dca8
fix test
perunt Jun 7, 2024
3cd1866
remove waitFor
perunt Jun 7, 2024
34984ef
jest mock
perunt Jun 7, 2024
5674443
Merge branch 'main' of https://github.com/Expensify/App into perunt/i…
perunt Jun 10, 2024
305eebb
clean
perunt Jun 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,25 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-keyboard-controller (1.12.2):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
- RCTRequired
- RCTTypeSafety
- React-Codegen
- React-Core
- React-debug
- React-Fabric
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-launch-arguments (4.0.2):
- React
- react-native-netinfo (11.2.1):
Expand Down Expand Up @@ -2137,6 +2156,7 @@ DEPENDENCIES:
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-key-command (from `../node_modules/react-native-key-command`)
- react-native-keyboard-controller (from `../node_modules/react-native-keyboard-controller`)
- react-native-launch-arguments (from `../node_modules/react-native-launch-arguments`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
Expand Down Expand Up @@ -2335,6 +2355,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-image-picker"
react-native-key-command:
:path: "../node_modules/react-native-key-command"
react-native-keyboard-controller:
:path: "../node_modules/react-native-keyboard-controller"
react-native-launch-arguments:
:path: "../node_modules/react-native-launch-arguments"
react-native-netinfo:
Expand Down Expand Up @@ -2541,6 +2563,7 @@ SPEC CHECKSUMS:
react-native-geolocation: f9e92eb774cb30ac1e099f34b3a94f03b4db7eb3
react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440
react-native-key-command: 28ccfa09520e7d7e30739480dea4df003493bfe8
react-native-keyboard-controller: 47c01b0741ae5fc84e53cf282e61cfa5c2edb19b
react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d
react-native-netinfo: 02d31de0e08ab043d48f2a1a8baade109d7b6ca5
react-native-pager-view: ccd4bbf9fc7effaf8f91f8dae43389844d9ef9fa
Expand Down Expand Up @@ -2606,7 +2629,7 @@ SPEC CHECKSUMS:
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2
VisionCamera: 1394a316c7add37e619c48d7aa40b38b954bf055
Yoga: 64cd2a583ead952b0315d5135bf39e053ae9be70
Yoga: 1b901a6d6eeba4e8a2e8f308f708691cdb5db312

PODFILE CHECKSUM: 66a5c97ae1059e4da1993a4ad95abe5d819f555b

Expand Down
3 changes: 3 additions & 0 deletions jest/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ jest.mock('react-native-sound', () => {
jest.mock('react-native-share', () => ({
default: jest.fn(),
}));

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
jest.mock('react-native-keyboard-controller', () => require('react-native-keyboard-controller/jest'));
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
"react-native-image-picker": "^7.0.3",
"react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#bf3ad41a61c4f6f80ed4d497599ef5247a2dd002",
"react-native-key-command": "^1.0.8",
"react-native-keyboard-controller": "^1.12.2",
"react-native-launch-arguments": "^4.0.2",
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
index 88ae3f3..497569a 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
@@ -36,6 +36,54 @@ static jsi::Value textInputMetricsPayload(
return payload;
};

+static jsi::Value textInputMetricsScrollPayload(
+ jsi::Runtime& runtime,
+ const TextInputMetrics& textInputMetrics) {
+ auto payload = jsi::Object(runtime);
+
+ {
+ auto contentOffset = jsi::Object(runtime);
+ contentOffset.setProperty(runtime, "x", textInputMetrics.contentOffset.x);
+ contentOffset.setProperty(runtime, "y", textInputMetrics.contentOffset.y);
+ payload.setProperty(runtime, "contentOffset", contentOffset);
+ }
+
+ {
+ auto contentInset = jsi::Object(runtime);
+ contentInset.setProperty(runtime, "top", textInputMetrics.contentInset.top);
+ contentInset.setProperty(
+ runtime, "left", textInputMetrics.contentInset.left);
+ contentInset.setProperty(
+ runtime, "bottom", textInputMetrics.contentInset.bottom);
+ contentInset.setProperty(
+ runtime, "right", textInputMetrics.contentInset.right);
+ payload.setProperty(runtime, "contentInset", contentInset);
+ }
+
+ {
+ auto contentSize = jsi::Object(runtime);
+ contentSize.setProperty(
+ runtime, "width", textInputMetrics.contentSize.width);
+ contentSize.setProperty(
+ runtime, "height", textInputMetrics.contentSize.height);
+ payload.setProperty(runtime, "contentSize", contentSize);
+ }
+
+ {
+ auto layoutMeasurement = jsi::Object(runtime);
+ layoutMeasurement.setProperty(
+ runtime, "width", textInputMetrics.layoutMeasurement.width);
+ layoutMeasurement.setProperty(
+ runtime, "height", textInputMetrics.layoutMeasurement.height);
+ payload.setProperty(runtime, "layoutMeasurement", layoutMeasurement);
+ }
+
+ payload.setProperty(runtime, "zoomScale", textInputMetrics.zoomScale ?: 1);
+
+
+ return payload;
+ };
+
static jsi::Value textInputMetricsContentSizePayload(
jsi::Runtime& runtime,
const TextInputMetrics& textInputMetrics) {
@@ -140,7 +188,9 @@ void TextInputEventEmitter::onKeyPressSync(

void TextInputEventEmitter::onScroll(
const TextInputMetrics& textInputMetrics) const {
- dispatchTextInputEvent("scroll", textInputMetrics);
+ dispatchEvent("scroll", [textInputMetrics](jsi::Runtime& runtime) {
+ return textInputMetricsScrollPayload(runtime, textInputMetrics);
+ });
}

void TextInputEventEmitter::dispatchTextInputEvent(
39 changes: 39 additions & 0 deletions patches/react-native-keyboard-controller+1.12.2.patch.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
diff --git a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
index 83884d8..5d9e989 100644
--- a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
+++ b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
@@ -99,12 +99,12 @@ class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : R
}

private fun goToEdgeToEdge(edgeToEdge: Boolean) {
- reactContext.currentActivity?.let {
- WindowCompat.setDecorFitsSystemWindows(
- it.window,
- !edgeToEdge,
- )
- }
+ // reactContext.currentActivity?.let {
+ // WindowCompat.setDecorFitsSystemWindows(
+ // it.window,
+ // !edgeToEdge,
+ // )
+ // }
}

private fun setupKeyboardCallbacks() {
@@ -158,13 +158,13 @@ class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : R
// region State managers
private fun enable() {
this.goToEdgeToEdge(true)
- this.setupWindowInsets()
+ // this.setupWindowInsets()
this.setupKeyboardCallbacks()
}

private fun disable() {
this.goToEdgeToEdge(false)
- this.setupWindowInsets()
+ // this.setupWindowInsets()
this.removeKeyboardCallbacks()
}
// endregion
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {PortalProvider} from '@gorhom/portal';
import React from 'react';
import {LogBox} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {KeyboardProvider} from 'react-native-keyboard-controller';
import {PickerStateProvider} from 'react-native-picker-select';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import '../wdyr';
Expand Down Expand Up @@ -84,6 +85,7 @@ function App({url}: AppProps) {
FullScreenContextProvider,
VolumeContextProvider,
VideoPopoverMenuContextProvider,
KeyboardProvider,
]}
>
<CustomStatusBarAndBackground />
Expand Down
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,8 @@ const CONST = {
MAX_AMOUNT_OF_SUGGESTIONS: 20,
MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER: 5,
HERE_TEXT: '@here',
SUGGESTION_BOX_MAX_SAFE_DISTANCE: 38,
BIG_SCREEN_SUGGESTION_WIDTH: 300,
},
COMPOSER_MAX_HEIGHT: 125,
CHAT_FOOTER_SECONDARY_ROW_HEIGHT: 15,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function getBottomSuggestionPadding(): number {
return 16;
}

export default getBottomSuggestionPadding;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function getBottomSuggestionPadding(): number {
return 0;
}

export default getBottomSuggestionPadding;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {Portal} from '@gorhom/portal';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import BaseAutoCompleteSuggestions from '@components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions';
import useStyleUtils from '@hooks/useStyleUtils';
import getBottomSuggestionPadding from './getBottomSuggestionPadding';
import type {AutoCompleteSuggestionsPortalProps} from './types';

function AutoCompleteSuggestionsPortal<TSuggestion>({left = 0, width = 0, bottom = 0, ...props}: AutoCompleteSuggestionsPortalProps<TSuggestion>) {
const StyleUtils = useStyleUtils();
const styles = useMemo(() => StyleUtils.getBaseAutoCompleteSuggestionContainerStyle({left, width, bottom: bottom + getBottomSuggestionPadding()}), [StyleUtils, left, width, bottom]);
// const styles = useMemo(() => StyleUtils.getBaseAutoCompleteSuggestionContainerStyle({left, width, bottom: bottom + 0}), [StyleUtils, left, width, bottom]);
perunt marked this conversation as resolved.
Show resolved Hide resolved

if (!width) {
return null;
}

return (
<Portal hostName="suggestions">
<View style={styles}>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<BaseAutoCompleteSuggestions<TSuggestion>
width={width}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
</View>
</Portal>
);
}

AutoCompleteSuggestionsPortal.displayName = 'AutoCompleteSuggestionsPortal';

export default AutoCompleteSuggestionsPortal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import type {ReactElement} from 'react';
import ReactDOM from 'react-dom';
import {View} from 'react-native';
import BaseAutoCompleteSuggestions from '@components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions';
import useStyleUtils from '@hooks/useStyleUtils';
import getBottomSuggestionPadding from './getBottomSuggestionPadding';
import type {AutoCompleteSuggestionsPortalProps} from './types';

/**
* On the mobile-web platform, when long-pressing on auto-complete suggestions,
* we need to prevent focus shifting to avoid blurring the main input (which makes the suggestions picker close and fires the onSelect callback).
* The desired pattern for all platforms is to do nothing on long-press.
* On the native platform, tapping on auto-complete suggestions will not blur the main input.
*/

function AutoCompleteSuggestionsPortal<TSuggestion>({left = 0, width = 0, bottom = 0, ...props}: AutoCompleteSuggestionsPortalProps<TSuggestion>): ReactElement | null | false {
const StyleUtils = useStyleUtils();

const bodyElement = document.querySelector('body');

const componentToRender = (
<BaseAutoCompleteSuggestions<TSuggestion>
width={width}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
);

return (
!!width &&
bodyElement &&
ReactDOM.createPortal(
<View style={StyleUtils.getBaseAutoCompleteSuggestionContainerStyle({left, width, bottom: bottom - getBottomSuggestionPadding()})}>{componentToRender}</View>,
bodyElement,
)
);
}

AutoCompleteSuggestionsPortal.displayName = 'AutoCompleteSuggestionsPortal';

export default AutoCompleteSuggestionsPortal;
export type {AutoCompleteSuggestionsPortalProps};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type {AutoCompleteSuggestionsProps} from '@components/AutoCompleteSuggestions/types';

type ExternalProps<TSuggestion> = Omit<AutoCompleteSuggestionsProps<TSuggestion>, 'measureParentContainerAndReportCursor'>;

type AutoCompleteSuggestionsPortalProps<TSuggestion> = ExternalProps<TSuggestion> & {
left: number;
width: number;
bottom: number;
measuredHeightOfSuggestionRows: number;
};

// eslint-disable-next-line import/prefer-default-export
export type {AutoCompleteSuggestionsPortalProps};
Loading
Loading