nx-react-native-cli 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/lib/index.cjs +3 -3
- package/package.json +11 -11
- package/templates/.eslintrc.json +2 -8
- package/templates/.nvmrc +1 -1
- package/templates/apps/mobile/android/build.gradle +4 -4
- package/templates/apps/mobile/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/templates/apps/mobile/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/templates/apps/mobile/android/gradle.properties +4 -0
- package/templates/apps/mobile/android/gradlew +4 -4
- package/templates/apps/mobile/android/gradlew.bat +7 -2
- package/templates/apps/mobile/babel.config.json +1 -1
- package/templates/apps/mobile/package.json +3 -2
- package/templates/apps/mobile/src/app/index.tsx +13 -8
- package/templates/apps/mobile/src/components/atoms/KeyboardAccessory/index.ts +1 -0
- package/templates/apps/mobile/src/components/atoms/KeyboardAccessory/keyboard-accessory.component.tsx +25 -0
- package/templates/apps/mobile/src/components/atoms/KeyboardAwareScrollView/keyboard-aware-scroll-view.component.tsx +7 -8
- package/templates/apps/mobile/src/components/atoms/TextInput/bottom-sheet-text-input.component.tsx +52 -8
- package/templates/apps/mobile/src/components/atoms/TextInput/constants.ts +13 -7
- package/templates/apps/mobile/src/components/atoms/TextInput/text-input-area.component.tsx +13 -12
- package/templates/apps/mobile/src/components/atoms/TextInput/text-input.component.tsx +42 -4
- package/templates/apps/mobile/src/components/atoms/index.ts +1 -0
- package/templates/apps/mobile/src/components/molecules/ScreenContainer/screen-container.component.tsx +3 -3
- package/templates/apps/mobile/src/hooks/useDebounce.hook.ts +1 -1
- package/templates/apps/mobile/src/hooks/useThrottle.hook.ts +1 -1
- package/templates/apps/mobile/src/icons/cross.svg +4 -0
- package/templates/apps/mobile/src/icons/index.ts +3 -1
- package/templates/apps/mobile/src/icons/keyboard-hide.svg +1 -0
- package/templates/apps/mobile/src/stores/mmkvStorage.ts +3 -3
- package/templates/apps/mobile/src/tailwind/index.ts +4 -4
- package/templates/apps/mobile/tsconfig.app.json +2 -2
- package/templates/clean-generated-outputs.sh +22 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx-react-native-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "A react native starter (with NX) cli script",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"start": "./src/index.js",
|
|
25
25
|
"build": "rm -rf lib && esbuild src/index.js --format=cjs --platform=node --bundle --outfile=lib/index.cjs --minify --analyze",
|
|
26
26
|
"prepublishOnly": "npm run build",
|
|
27
|
-
"example": "rm -rf example && npm run relink && npx
|
|
28
|
-
"example-fresh": "rm -rf example && npm run relink && npx
|
|
27
|
+
"example": "rm -rf example && npm run relink && npx nx-react-native-cli create example com.jeemercado.example",
|
|
28
|
+
"example-fresh": "rm -rf example && npm run relink && npx nx-react-native-cli create example-fresh --fresh",
|
|
29
29
|
"generate-diff": "./generate-diff.sh",
|
|
30
30
|
"show-diff": "npx diff2html -s side --sc --hc --cs light -i file -o preview -F diff.html -- diff.diff && open diff.html",
|
|
31
|
-
"relink": "npm unlink
|
|
31
|
+
"relink": "npm unlink nx-react-native-cli && npm run prepublishOnly && npm link",
|
|
32
32
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
33
33
|
},
|
|
34
34
|
"author": {
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
},
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"chalk": "
|
|
41
|
-
"commander": "
|
|
42
|
-
"inquirer": "
|
|
43
|
-
"ora": "
|
|
44
|
-
"prettier": "
|
|
40
|
+
"chalk": "5.3.0",
|
|
41
|
+
"commander": "12.1.0",
|
|
42
|
+
"inquirer": "10.0.2",
|
|
43
|
+
"ora": "8.0.1",
|
|
44
|
+
"prettier": "3.3.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"diff2html-cli": "
|
|
48
|
-
"esbuild": "
|
|
47
|
+
"diff2html-cli": "5.2.15",
|
|
48
|
+
"esbuild": "0.23.0"
|
|
49
49
|
}
|
|
50
50
|
}
|
package/templates/.eslintrc.json
CHANGED
|
@@ -110,14 +110,7 @@
|
|
|
110
110
|
"alphabetize": {
|
|
111
111
|
"order": "asc"
|
|
112
112
|
},
|
|
113
|
-
"groups": [
|
|
114
|
-
"builtin",
|
|
115
|
-
"external",
|
|
116
|
-
"internal",
|
|
117
|
-
"parent",
|
|
118
|
-
"sibling",
|
|
119
|
-
"index"
|
|
120
|
-
],
|
|
113
|
+
"groups": ["builtin", "external", "internal", "parent", "sibling", "index"],
|
|
121
114
|
"newlines-between": "always"
|
|
122
115
|
}
|
|
123
116
|
],
|
|
@@ -144,6 +137,7 @@
|
|
|
144
137
|
"no-duplicate-imports": "error",
|
|
145
138
|
"no-empty-function": "warn",
|
|
146
139
|
"no-extra-boolean-cast": "warn",
|
|
140
|
+
"sonarjs/no-use-of-empty-return-value": "off",
|
|
147
141
|
"no-extra-semi": "warn",
|
|
148
142
|
"no-magic-numbers": [
|
|
149
143
|
"error",
|
package/templates/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
v22.14.0
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
buildscript {
|
|
2
2
|
ext {
|
|
3
|
-
buildToolsVersion = "
|
|
3
|
+
buildToolsVersion = "36.0.0"
|
|
4
4
|
minSdkVersion = 24
|
|
5
|
-
compileSdkVersion =
|
|
6
|
-
targetSdkVersion =
|
|
5
|
+
compileSdkVersion = 36
|
|
6
|
+
targetSdkVersion = 36
|
|
7
7
|
ndkVersion = "27.1.12297006"
|
|
8
|
-
kotlinVersion = "2.
|
|
8
|
+
kotlinVersion = "2.1.20"
|
|
9
9
|
}
|
|
10
10
|
repositories {
|
|
11
11
|
google()
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
distributionBase=GRADLE_USER_HOME
|
|
2
2
|
distributionPath=wrapper/dists
|
|
3
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-
|
|
3
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
|
4
4
|
networkTimeout=10000
|
|
5
5
|
validateDistributionUrl=true
|
|
6
6
|
zipStoreBase=GRADLE_USER_HOME
|
|
@@ -42,3 +42,7 @@ hermesEnabled=true
|
|
|
42
42
|
|
|
43
43
|
VisionCamera_enableCodeScanner=true
|
|
44
44
|
|
|
45
|
+
# Use this property to enable edge-to-edge display support.
|
|
46
|
+
# This allows your app to draw behind system bars for an immersive UI.
|
|
47
|
+
# Note: Only works with ReactActivity and should not be used with custom Activity.
|
|
48
|
+
edgeToEdgeEnabled=false
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Copyright © 2015
|
|
4
|
+
# Copyright © 2015 the original authors.
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
# you may not use this file except in compliance with the License.
|
|
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|
|
114
114
|
NONSTOP* ) nonstop=true ;;
|
|
115
115
|
esac
|
|
116
116
|
|
|
117
|
-
CLASSPATH
|
|
117
|
+
CLASSPATH="\\\"\\\""
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
# Determine the Java command to use to start the JVM.
|
|
@@ -205,7 +205,7 @@ fi
|
|
|
205
205
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
206
206
|
|
|
207
207
|
# Collect all arguments for the java command:
|
|
208
|
-
# * DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
208
|
+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
209
209
|
# and any embedded shellness will be escaped.
|
|
210
210
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
211
211
|
# treated as '${Hostname}' itself on the command line.
|
|
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
|
213
213
|
set -- \
|
|
214
214
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
|
215
215
|
-classpath "$CLASSPATH" \
|
|
216
|
-
|
|
216
|
+
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
|
217
217
|
"$@"
|
|
218
218
|
|
|
219
219
|
# Stop when "xargs" is not available.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
@REM Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
@REM
|
|
3
|
+
@REM This source code is licensed under the MIT license found in the
|
|
4
|
+
@REM LICENSE file in the root directory of this source tree.
|
|
5
|
+
|
|
1
6
|
@rem
|
|
2
7
|
@rem Copyright 2015 the original author or authors.
|
|
3
8
|
@rem
|
|
@@ -70,11 +75,11 @@ goto fail
|
|
|
70
75
|
:execute
|
|
71
76
|
@rem Setup the command line
|
|
72
77
|
|
|
73
|
-
set CLASSPATH
|
|
78
|
+
set CLASSPATH=
|
|
74
79
|
|
|
75
80
|
|
|
76
81
|
@rem Execute Gradle
|
|
77
|
-
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%"
|
|
82
|
+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
|
78
83
|
|
|
79
84
|
:end
|
|
80
85
|
@rem End local scope for the variables with windows NT shell
|
|
@@ -49,17 +49,17 @@
|
|
|
49
49
|
"jotai-optics": "*",
|
|
50
50
|
"jotai": "*",
|
|
51
51
|
"lodash": "*",
|
|
52
|
-
"lottie-react-native": "*",
|
|
53
52
|
"metro-config": "*",
|
|
54
53
|
"react-hook-form": "*",
|
|
55
54
|
"react-native-dotenv": "*",
|
|
56
55
|
"react-native-gesture-handler": "*",
|
|
57
56
|
"react-native-get-random-values": "*",
|
|
58
57
|
"react-native-haptic-feedback": "*",
|
|
59
|
-
"react-native-keyboard-
|
|
58
|
+
"react-native-keyboard-controller": "*",
|
|
60
59
|
"react-native-mmkv": "*",
|
|
61
60
|
"react-native-modal-datetime-picker": "*",
|
|
62
61
|
"react-native-modal": "*",
|
|
62
|
+
"react-native-nitro-modules": "*",
|
|
63
63
|
"react-native-pager-view": "*",
|
|
64
64
|
"react-native-reanimated": "*",
|
|
65
65
|
"react-native-safe-area-context": "*",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"react-native-svg": "*",
|
|
70
70
|
"react-native-turbo-image": "*",
|
|
71
71
|
"react-native-url-polyfill": "*",
|
|
72
|
+
"react-native-worklets": "*",
|
|
72
73
|
"react-native": "*",
|
|
73
74
|
"react": "*",
|
|
74
75
|
"tailwindcss": "*",
|
|
@@ -5,7 +5,8 @@ import React from 'react';
|
|
|
5
5
|
import { LogBox } from 'react-native';
|
|
6
6
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
7
7
|
import 'react-native-get-random-values';
|
|
8
|
-
import {
|
|
8
|
+
import { KeyboardProvider } from 'react-native-keyboard-controller';
|
|
9
|
+
import { createMMKV } from 'react-native-mmkv';
|
|
9
10
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
10
11
|
import { useDeviceContext } from 'twrnc';
|
|
11
12
|
|
|
@@ -28,7 +29,7 @@ const queryClient = new QueryClient({
|
|
|
28
29
|
},
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
const storage =
|
|
32
|
+
const storage = createMMKV({
|
|
32
33
|
encryptionKey: CONFIG.STORAGE_KEY,
|
|
33
34
|
id: 'react-query-persist',
|
|
34
35
|
});
|
|
@@ -39,7 +40,9 @@ export const MmkvStorage: AsyncStorage = {
|
|
|
39
40
|
|
|
40
41
|
return value ?? null;
|
|
41
42
|
},
|
|
42
|
-
removeItem: (name) =>
|
|
43
|
+
removeItem: (name) => {
|
|
44
|
+
storage.remove(name);
|
|
45
|
+
},
|
|
43
46
|
setItem: (name, value) => storage.set(name, value),
|
|
44
47
|
};
|
|
45
48
|
|
|
@@ -57,11 +60,13 @@ function Application() {
|
|
|
57
60
|
return (
|
|
58
61
|
<GestureHandlerRootView style={tw`flex-1`}>
|
|
59
62
|
<SafeAreaProvider>
|
|
60
|
-
<
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
<KeyboardProvider>
|
|
64
|
+
<PersistQueryClientProvider client={queryClient} persistOptions={persistOptions}>
|
|
65
|
+
<StorageManager>
|
|
66
|
+
<ApplicationRoutes />
|
|
67
|
+
</StorageManager>
|
|
68
|
+
</PersistQueryClientProvider>
|
|
69
|
+
</KeyboardProvider>
|
|
65
70
|
</SafeAreaProvider>
|
|
66
71
|
</GestureHandlerRootView>
|
|
67
72
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './keyboard-accessory.component';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { InputAccessoryView, Keyboard, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Button } from '@/components/atoms/Button';
|
|
5
|
+
import { KeyboardHideIcon } from '@/icons';
|
|
6
|
+
import { tw } from '@/tailwind';
|
|
7
|
+
import { DefaultComponentProps } from '@/types/component.type';
|
|
8
|
+
|
|
9
|
+
type Props = DefaultComponentProps & {
|
|
10
|
+
nativeID: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function KeyboardAccessory(props: Props) {
|
|
14
|
+
const { nativeID } = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<InputAccessoryView nativeID={nativeID}>
|
|
18
|
+
<View style={tw`flex-row items-center justify-end bg-[#313132] px-2`}>
|
|
19
|
+
<Button buttonStyle={tw`my-2 rounded-lg bg-[#717172]`} onPress={() => Keyboard.dismiss()}>
|
|
20
|
+
<KeyboardHideIcon style={tw`text-white`} />
|
|
21
|
+
</Button>
|
|
22
|
+
</View>
|
|
23
|
+
</InputAccessoryView>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -7,15 +7,15 @@ import {
|
|
|
7
7
|
StyleProp,
|
|
8
8
|
ViewStyle,
|
|
9
9
|
} from 'react-native';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
10
|
+
import { ScrollView as RNScrollView } from 'react-native-gesture-handler';
|
|
11
|
+
import { KeyboardAwareScrollView as RNKeyboardAwareScrollView } from 'react-native-keyboard-controller';
|
|
12
12
|
|
|
13
13
|
import { tw } from '@/tailwind';
|
|
14
14
|
import { DefaultComponentProps } from '@/types';
|
|
15
15
|
|
|
16
16
|
type Props = DefaultComponentProps & {
|
|
17
17
|
children?: React.ReactNode;
|
|
18
|
-
scrollViewRef?: React.RefObject<
|
|
18
|
+
scrollViewRef?: React.RefObject<RNScrollView | null>;
|
|
19
19
|
containerStyle?: StyleProp<ViewStyle>;
|
|
20
20
|
extraBottomPadding?: number;
|
|
21
21
|
refreshControl?: React.ReactElement<RefreshControlProps> | undefined;
|
|
@@ -24,8 +24,6 @@ type Props = DefaultComponentProps & {
|
|
|
24
24
|
|
|
25
25
|
const defaultStyle = tw`grow`;
|
|
26
26
|
|
|
27
|
-
const AnimatedKeyboardAwareScrollView = Animated.createAnimatedComponent(RNKeyboardAwareScrollView);
|
|
28
|
-
|
|
29
27
|
export function KeyboardAwareScrollView(props: Props) {
|
|
30
28
|
const {
|
|
31
29
|
children,
|
|
@@ -44,17 +42,18 @@ export function KeyboardAwareScrollView(props: Props) {
|
|
|
44
42
|
];
|
|
45
43
|
|
|
46
44
|
return (
|
|
47
|
-
<
|
|
45
|
+
<RNKeyboardAwareScrollView
|
|
48
46
|
ref={scrollViewRef}
|
|
47
|
+
bottomOffset={100}
|
|
49
48
|
contentContainerStyle={[defaultContainerStyle, containerStyle]}
|
|
50
|
-
enableResetScrollToCoords={false}
|
|
51
49
|
keyboardShouldPersistTaps="handled"
|
|
52
50
|
refreshControl={refreshControl}
|
|
53
51
|
scrollEventThrottle={16}
|
|
52
|
+
ScrollViewComponent={RNScrollView}
|
|
54
53
|
style={style}
|
|
55
54
|
onScroll={onScroll}
|
|
56
55
|
>
|
|
57
56
|
{children}
|
|
58
|
-
</
|
|
57
|
+
</RNKeyboardAwareScrollView>
|
|
59
58
|
);
|
|
60
59
|
}
|
package/templates/apps/mobile/src/components/atoms/TextInput/bottom-sheet-text-input.component.tsx
CHANGED
|
@@ -1,53 +1,87 @@
|
|
|
1
1
|
import { BottomSheetTextInput as RNBottomSheetTextInput } from '@gorhom/bottom-sheet';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import {
|
|
4
|
+
NativeSyntheticEvent,
|
|
5
|
+
Pressable,
|
|
4
6
|
TextInput as RNTextInput,
|
|
5
7
|
TextInputProps as RNTextInputProps,
|
|
6
8
|
StyleProp,
|
|
9
|
+
TextInputFocusEventData,
|
|
7
10
|
TextStyle,
|
|
8
11
|
View,
|
|
9
12
|
} from 'react-native';
|
|
10
13
|
|
|
11
|
-
import { DefaultNameInputProps } from '
|
|
14
|
+
import { DefaultNameInputProps } from './constants';
|
|
15
|
+
|
|
16
|
+
import { CrossIcon } from '@/icons';
|
|
12
17
|
import {
|
|
13
18
|
colors,
|
|
14
19
|
defaultInputContainerStyle,
|
|
15
20
|
defaultInputTextStyle,
|
|
16
21
|
disabledInputStyle,
|
|
17
22
|
focusedInputStyle,
|
|
23
|
+
tw,
|
|
18
24
|
} from '@/tailwind';
|
|
19
|
-
import { DefaultComponentProps } from '@/types';
|
|
25
|
+
import { DefaultComponentProps } from '@/types/component.type';
|
|
20
26
|
|
|
21
27
|
export type BottomSheetTextInputProps = DefaultComponentProps &
|
|
22
28
|
RNTextInputProps & {
|
|
23
29
|
textInputRef?: React.RefObject<RNTextInput>;
|
|
24
30
|
textStyle?: StyleProp<TextStyle>;
|
|
31
|
+
showClearButton?: boolean;
|
|
32
|
+
onClearButtonPress?: () => void;
|
|
25
33
|
};
|
|
26
34
|
|
|
27
35
|
export function BottomSheetTextInput(props: BottomSheetTextInputProps) {
|
|
28
36
|
const {
|
|
29
37
|
isDisabled = false,
|
|
30
38
|
multiline = false,
|
|
39
|
+
onBlur,
|
|
31
40
|
onChangeText,
|
|
41
|
+
onClearButtonPress,
|
|
42
|
+
onFocus,
|
|
32
43
|
placeholder,
|
|
44
|
+
showClearButton = true,
|
|
33
45
|
style,
|
|
34
46
|
textInputRef,
|
|
35
47
|
textStyle,
|
|
36
48
|
value,
|
|
37
49
|
...extraProps
|
|
38
50
|
} = props;
|
|
51
|
+
const [isClearButtonVisible, setIsClearButtonVisible] = useState<boolean>(false);
|
|
39
52
|
const [isFocused, setFocused] = useState<boolean>(false);
|
|
40
53
|
|
|
41
54
|
function handleOnChangeText(text: string) {
|
|
42
55
|
onChangeText?.(text);
|
|
56
|
+
|
|
57
|
+
if (showClearButton) {
|
|
58
|
+
setIsClearButtonVisible(text.length > 0);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function handleOnClearPress() {
|
|
63
|
+
handleOnChangeText?.('');
|
|
64
|
+
onClearButtonPress?.();
|
|
43
65
|
}
|
|
44
66
|
|
|
45
|
-
function handleOnFocus() {
|
|
67
|
+
function handleOnFocus(e: NativeSyntheticEvent<TextInputFocusEventData>) {
|
|
46
68
|
setFocused(true);
|
|
69
|
+
|
|
70
|
+
const shouldShowClearButton = showClearButton && value?.length;
|
|
71
|
+
if (shouldShowClearButton) {
|
|
72
|
+
setIsClearButtonVisible(true);
|
|
73
|
+
}
|
|
74
|
+
onFocus?.(e);
|
|
47
75
|
}
|
|
48
76
|
|
|
49
|
-
function handleOnBlur() {
|
|
77
|
+
function handleOnBlur(e: NativeSyntheticEvent<TextInputFocusEventData>) {
|
|
50
78
|
setFocused(false);
|
|
79
|
+
|
|
80
|
+
const shouldShowClearButton = showClearButton && value?.length;
|
|
81
|
+
if (shouldShowClearButton) {
|
|
82
|
+
setIsClearButtonVisible(false);
|
|
83
|
+
}
|
|
84
|
+
onBlur?.(e);
|
|
51
85
|
}
|
|
52
86
|
|
|
53
87
|
return (
|
|
@@ -65,15 +99,25 @@ export function BottomSheetTextInput(props: BottomSheetTextInputProps) {
|
|
|
65
99
|
editable={!isDisabled}
|
|
66
100
|
multiline={multiline}
|
|
67
101
|
placeholder={placeholder}
|
|
68
|
-
placeholderTextColor={colors.gray[
|
|
69
|
-
selectionColor={colors.primary
|
|
102
|
+
placeholderTextColor={colors.gray[500]}
|
|
103
|
+
selectionColor={colors.primary}
|
|
70
104
|
style={[defaultInputTextStyle, textStyle]}
|
|
71
105
|
value={value}
|
|
72
|
-
onBlur={handleOnBlur}
|
|
106
|
+
onBlur={(e) => handleOnBlur(e as NativeSyntheticEvent<TextInputFocusEventData>)}
|
|
73
107
|
onChangeText={handleOnChangeText}
|
|
74
|
-
onFocus={handleOnFocus}
|
|
108
|
+
onFocus={(e) => handleOnFocus(e as NativeSyntheticEvent<TextInputFocusEventData>)}
|
|
75
109
|
{...extraProps}
|
|
76
110
|
/>
|
|
111
|
+
{isClearButtonVisible && (
|
|
112
|
+
<Pressable
|
|
113
|
+
hitSlop={30}
|
|
114
|
+
style={tw`items-center justify-center`}
|
|
115
|
+
testID="clear-button"
|
|
116
|
+
onPress={handleOnClearPress}
|
|
117
|
+
>
|
|
118
|
+
<CrossIcon />
|
|
119
|
+
</Pressable>
|
|
120
|
+
)}
|
|
77
121
|
</View>
|
|
78
122
|
);
|
|
79
123
|
}
|
|
@@ -1,46 +1,52 @@
|
|
|
1
1
|
import { TextInputProps } from 'react-native';
|
|
2
2
|
|
|
3
|
-
export const TEXT_INPUT_MIN_HEIGHT =
|
|
3
|
+
export const TEXT_INPUT_MIN_HEIGHT = 56;
|
|
4
4
|
export const TEXT_INPUT_LINE_HEIGHT = 21;
|
|
5
5
|
|
|
6
6
|
export const DefaultPhonePadInputProps: TextInputProps = {
|
|
7
7
|
autoCapitalize: 'none',
|
|
8
|
-
autoCorrect:
|
|
8
|
+
autoCorrect: true,
|
|
9
|
+
keyboardAppearance: 'dark',
|
|
9
10
|
keyboardType: 'phone-pad',
|
|
10
11
|
numberOfLines: 1,
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export const DefaultNumberPadInputProps: TextInputProps = {
|
|
14
15
|
autoCapitalize: 'none',
|
|
15
|
-
autoCorrect:
|
|
16
|
+
autoCorrect: true,
|
|
17
|
+
keyboardAppearance: 'dark',
|
|
16
18
|
keyboardType: 'number-pad',
|
|
17
19
|
numberOfLines: 1,
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export const DefaultNumericInputProps: TextInputProps = {
|
|
21
23
|
autoCapitalize: 'none',
|
|
22
|
-
autoCorrect:
|
|
24
|
+
autoCorrect: true,
|
|
25
|
+
keyboardAppearance: 'dark',
|
|
23
26
|
keyboardType: 'numeric',
|
|
24
27
|
numberOfLines: 1,
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
export const DefaultNameInputProps: TextInputProps = {
|
|
28
31
|
autoCapitalize: 'words',
|
|
29
|
-
autoCorrect:
|
|
32
|
+
autoCorrect: true,
|
|
33
|
+
keyboardAppearance: 'dark',
|
|
30
34
|
keyboardType: 'default',
|
|
31
35
|
numberOfLines: 1,
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
export const DefaultEmailInputProps: TextInputProps = {
|
|
35
39
|
autoCapitalize: 'none',
|
|
36
|
-
autoCorrect:
|
|
40
|
+
autoCorrect: true,
|
|
41
|
+
keyboardAppearance: 'dark',
|
|
37
42
|
keyboardType: 'email-address',
|
|
38
43
|
numberOfLines: 1,
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
export const DefaultTextAreaInputProps: TextInputProps = {
|
|
42
47
|
autoCapitalize: 'sentences',
|
|
43
|
-
autoCorrect:
|
|
48
|
+
autoCorrect: true,
|
|
49
|
+
keyboardAppearance: 'dark',
|
|
44
50
|
keyboardType: 'default',
|
|
45
51
|
numberOfLines: 3,
|
|
46
52
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
TextInput as RNTextInput,
|
|
4
4
|
TextInputProps as RNTextInputProps,
|
|
@@ -6,22 +6,22 @@ import {
|
|
|
6
6
|
TextStyle,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from '@/
|
|
14
|
-
import { getTextInputHeightAdjustment } from '@/components/atoms/TextInput/util';
|
|
15
|
-
import { DefaultComponentProps } from '@/types';
|
|
9
|
+
import { DefaultTextAreaInputProps, TEXT_INPUT_MIN_HEIGHT } from './constants';
|
|
10
|
+
import { TextInput } from './text-input.component';
|
|
11
|
+
import { getTextInputHeightAdjustment } from './util';
|
|
12
|
+
|
|
13
|
+
import { DefaultComponentProps } from '@/types/component.type';
|
|
16
14
|
|
|
17
15
|
export type TextInputAreaProps = DefaultComponentProps &
|
|
18
16
|
RNTextInputProps & {
|
|
19
17
|
textInputRef?: React.RefObject<RNTextInput>;
|
|
20
18
|
textStyle?: StyleProp<TextStyle>;
|
|
19
|
+
autoAdjustHeight?: boolean;
|
|
21
20
|
};
|
|
22
21
|
|
|
23
22
|
export function TextInputArea(props: TextInputAreaProps) {
|
|
24
23
|
const {
|
|
24
|
+
autoAdjustHeight = false,
|
|
25
25
|
numberOfLines = DefaultTextAreaInputProps.numberOfLines as number,
|
|
26
26
|
onChangeText,
|
|
27
27
|
textStyle,
|
|
@@ -33,25 +33,26 @@ export function TextInputArea(props: TextInputAreaProps) {
|
|
|
33
33
|
function handleOnChangeText(text: string) {
|
|
34
34
|
onChangeText?.(text);
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
useEffect(() => {
|
|
37
|
-
if (!value) {
|
|
38
|
+
if (!value || !autoAdjustHeight) {
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const newLines = value.split(
|
|
42
|
+
const newLines = value.split(/[\r\n]+/).length;
|
|
42
43
|
|
|
43
44
|
if (numberOfNewLines !== newLines) {
|
|
44
45
|
setNumberOfNewLines(newLines);
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
48
47
|
}, [value]);
|
|
49
48
|
|
|
50
49
|
return (
|
|
51
50
|
<TextInput
|
|
51
|
+
testID="text-input-area"
|
|
52
52
|
{...DefaultTextAreaInputProps}
|
|
53
53
|
multiline
|
|
54
54
|
numberOfLines={numberOfLines}
|
|
55
|
+
showClearButton={false}
|
|
55
56
|
textStyle={[
|
|
56
57
|
textStyle,
|
|
57
58
|
{
|