nx-react-native-cli 1.0.20 → 2.0.0
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 +69 -21
- package/lib/index.cjs +49 -39
- package/package.json +3 -3
- package/templates/.husky/pre-commit +0 -3
- package/templates/.husky/pre-push +0 -3
- package/templates/.vscode/settings.json +2 -5
- package/templates/apps/mobile/.eslintrc.json +4 -1
- package/templates/apps/mobile/Gemfile +5 -2
- package/templates/apps/mobile/android/app/build.gradle +5 -4
- package/templates/apps/mobile/android/app/src/main/java/com/appsmobile/MainActivity.kt +28 -0
- package/templates/apps/mobile/android/app/src/main/java/com/appsmobile/MainApplication.kt +44 -0
- package/templates/apps/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/templates/apps/mobile/android/build.gradle +6 -6
- package/templates/apps/mobile/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/templates/apps/mobile/android/gradle.properties +44 -0
- package/templates/apps/mobile/android/gradlew +251 -0
- package/templates/apps/mobile/android/gradlew.bat +94 -0
- package/templates/apps/mobile/android/settings.gradle +6 -0
- package/templates/apps/mobile/babel.config.json +23 -0
- package/templates/apps/mobile/fastlane/.env.template +7 -2
- package/templates/apps/mobile/fastlane/Fastfile +46 -5
- package/templates/apps/mobile/fastlane/Matchfile +3 -3
- package/templates/apps/mobile/ios/AppDelegate.mm +33 -0
- package/templates/apps/mobile/metro.config.js +42 -0
- package/templates/apps/mobile/package.json +2 -3
- package/templates/apps/mobile/project.json +2 -1
- package/templates/apps/mobile/src/app/index.tsx +22 -7
- package/templates/apps/mobile/src/components/atoms/BottomSheet/bottom-sheet.component.tsx +9 -4
- package/templates/apps/mobile/src/components/atoms/Button/button.component.tsx +6 -6
- package/templates/apps/mobile/src/components/atoms/Divider/divider-component.tsx +4 -4
- package/templates/apps/mobile/src/components/atoms/ExcludedEdges/excluded-edges.component.tsx +37 -0
- package/templates/apps/mobile/src/components/atoms/ExcludedEdges/index.ts +1 -0
- package/templates/apps/mobile/src/components/atoms/InputLayout/input-layout.component.tsx +8 -9
- package/templates/apps/mobile/src/components/atoms/KeyboardAwareScrollView/index.ts +1 -0
- package/templates/apps/mobile/src/components/atoms/KeyboardAwareScrollView/keyboard-aware-scroll-view.component.tsx +60 -0
- package/templates/apps/mobile/src/components/atoms/ListLoadingItem/list-loading-item.component.tsx +20 -20
- package/templates/apps/mobile/src/components/atoms/Modal/modal.component.tsx +4 -5
- package/templates/apps/mobile/src/components/atoms/ScreenLoader/screen-loader.component.tsx +5 -6
- package/templates/apps/mobile/src/components/atoms/Skeleton/skeleton.component.tsx +9 -8
- package/templates/apps/mobile/src/components/atoms/TextInput/text-input.component.tsx +9 -7
- package/templates/apps/mobile/src/components/atoms/Typography/typography.component.tsx +2 -2
- package/templates/apps/mobile/src/components/atoms/index.ts +2 -1
- package/templates/apps/mobile/src/components/molecules/BackButton/back-button.component.tsx +8 -8
- package/templates/apps/mobile/src/components/molecules/BottomActionsContainer/BottomActionsContainer.component.tsx +2 -2
- package/templates/apps/mobile/src/components/molecules/ScreenContainer/screen-container.component.tsx +19 -25
- package/templates/apps/mobile/src/components/molecules/ScreenHeader/screen-header.component.tsx +12 -13
- package/templates/apps/mobile/src/components/molecules/StorageManager/StorageManager.component.tsx +3 -1
- package/templates/apps/mobile/src/hooks/useGetLayoutHeight.hook.tsx +1 -1
- package/templates/apps/mobile/src/hooks/useGetLayoutWidth.hook.tsx +1 -1
- package/templates/apps/mobile/src/hooks/useNavigation.hook.tsx +1 -1
- package/templates/apps/mobile/src/hooks/useTextInputChangeFocus.hook.tsx +2 -2
- package/templates/apps/mobile/src/hooks/useToggleDarkMode.hook.tsx +1 -1
- package/templates/apps/mobile/src/main.tsx +1 -1
- package/templates/apps/mobile/src/routes/index.tsx +7 -7
- package/templates/apps/mobile/src/routes/privateRoutes.tsx +3 -4
- package/templates/apps/mobile/src/routes/publicRoutes.tsx +3 -4
- package/templates/apps/mobile/src/screens/HomeScreen/home.screen.tsx +3 -2
- package/templates/apps/mobile/src/screens/LandingScreen/landing.screen.tsx +21 -13
- package/templates/apps/mobile/src/stores/local-storage.store.ts +1 -1
- package/templates/apps/mobile/src/stores/mmkvStorage.ts +1 -1
- package/templates/apps/mobile/tsconfig.app.json +5 -1
- package/templates/clean-generated-outputs.sh +1 -1
- package/templates/apps/mobile/.env +0 -3
- package/templates/apps/mobile/src/components/atoms/Box/box.component.tsx +0 -21
- package/templates/apps/mobile/src/components/atoms/Box/index.ts +0 -1
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Fastlane ENV
|
|
2
2
|
IS_CI=false
|
|
3
3
|
|
|
4
|
+
# Match
|
|
5
|
+
GIT_URL=
|
|
6
|
+
GIT_BRANCH=
|
|
7
|
+
GIT_API_TOKEN=
|
|
8
|
+
|
|
4
9
|
# Firebase
|
|
10
|
+
FIREBASE_SERVICE_ACCOUNT=
|
|
5
11
|
FASTLANE_FIREBASE_APP_ID=
|
|
6
12
|
FASTLANE_FIREBASE_GROUP_TESTERS=
|
|
7
13
|
|
|
8
14
|
# AppStore
|
|
9
15
|
MATCH_PASSWORD=
|
|
10
|
-
GITHUB_API_TOKEN=
|
|
11
16
|
FASTLANE_APPSTORE_KEY_ID=
|
|
12
17
|
FASTLANE_APPSTORE_ISSUER_ID=
|
|
13
18
|
FASTLANE_APPSTORE_KEY_CONTENT=
|
|
@@ -18,7 +23,7 @@ FASTLANE_APPSTORE_EXTERNAL_DESTINATIONS=""
|
|
|
18
23
|
# MISC
|
|
19
24
|
FASTLANE_CHANGELOGS="Performance and Feature updates"
|
|
20
25
|
|
|
21
|
-
# Android (Production ONLY)
|
|
26
|
+
# Android (Production ONLY, Dev is already handled in build.gradle)
|
|
22
27
|
STORE_PASSWORD=
|
|
23
28
|
KEY_PASSWORD=
|
|
24
29
|
KEY_ALIAS=
|
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
|
|
2
2
|
require 'fileutils'
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'json'
|
|
3
5
|
|
|
4
6
|
def app_name = "AppsMobile"
|
|
7
|
+
def service_account_path = '/tmp/fbd-sa.json'
|
|
8
|
+
|
|
9
|
+
def decode_base64_to_json(encoded_string, output_path)
|
|
10
|
+
begin
|
|
11
|
+
# Decode the Base64 string
|
|
12
|
+
decoded_data = Base64.decode64(encoded_string)
|
|
13
|
+
|
|
14
|
+
# Parse JSON from the decoded data
|
|
15
|
+
json_data = JSON.parse(decoded_data)
|
|
16
|
+
|
|
17
|
+
# Write to the specified file
|
|
18
|
+
File.open(output_path, 'w') do |file|
|
|
19
|
+
file.write(JSON.pretty_generate(json_data))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
puts "JSON file successfully written to: #{output_path}"
|
|
23
|
+
rescue JSON::ParserError
|
|
24
|
+
puts "Error: Decoded data is not valid JSON."
|
|
25
|
+
rescue StandardError => e
|
|
26
|
+
puts "Error: #{e.message}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_service_account_credentials()
|
|
31
|
+
decode_base64_to_json(ENV['FIREBASE_SERVICE_ACCOUNT'], service_account_path)
|
|
32
|
+
end
|
|
5
33
|
|
|
6
34
|
def delete_gradle_temp()
|
|
7
35
|
UI.message("Deleting Gradle Temp...")
|
|
@@ -136,6 +164,10 @@ def setup_android()
|
|
|
136
164
|
gradle_file_path: "./android/app/build.gradle",
|
|
137
165
|
version_code: build_number
|
|
138
166
|
)
|
|
167
|
+
|
|
168
|
+
# Retrieving Service Account Credentials
|
|
169
|
+
UI.message("Retrieving Service Account Credentials...")
|
|
170
|
+
get_service_account_credentials()
|
|
139
171
|
end
|
|
140
172
|
|
|
141
173
|
def ios_build_ipa(configuration, scheme)
|
|
@@ -216,7 +248,7 @@ end
|
|
|
216
248
|
def publish_bundle(flavor)
|
|
217
249
|
UI.message("Uploading aab build to Firebase...")
|
|
218
250
|
release = firebase_app_distribution(
|
|
219
|
-
service_credentials_file:
|
|
251
|
+
service_credentials_file: service_account_path,
|
|
220
252
|
app: ENV['FASTLANE_FIREBASE_APP_ID'],
|
|
221
253
|
android_artifact_type: "AAB",
|
|
222
254
|
android_artifact_path: "./android/app/build/outputs/bundle/#{flavor}Release/app-#{flavor}-release.aab",
|
|
@@ -228,7 +260,7 @@ end
|
|
|
228
260
|
def publish_apk(flavor)
|
|
229
261
|
UI.message("Uploading apk build to Firebase...")
|
|
230
262
|
release = firebase_app_distribution(
|
|
231
|
-
service_credentials_file:
|
|
263
|
+
service_credentials_file: service_account_path,
|
|
232
264
|
app: ENV['FASTLANE_FIREBASE_APP_ID'],
|
|
233
265
|
android_artifact_type: "APK",
|
|
234
266
|
android_artifact_path: "./android/app/build/outputs/apk/#{flavor}/release/app-#{flavor}-release.apk",
|
|
@@ -238,6 +270,11 @@ def publish_apk(flavor)
|
|
|
238
270
|
end
|
|
239
271
|
|
|
240
272
|
platform :android do
|
|
273
|
+
desc "Get Service Account Credentials"
|
|
274
|
+
lane :get_service_account_credentials do
|
|
275
|
+
get_service_account_credentials()
|
|
276
|
+
end
|
|
277
|
+
|
|
241
278
|
desc "Build Android (Dev Server)"
|
|
242
279
|
lane :dev do
|
|
243
280
|
begin
|
|
@@ -253,10 +290,14 @@ platform :android do
|
|
|
253
290
|
desc "Build Android (Production Server)"
|
|
254
291
|
lane :prod do
|
|
255
292
|
begin
|
|
256
|
-
flavor = '
|
|
293
|
+
flavor = 'prod'
|
|
257
294
|
setup_android()
|
|
258
|
-
|
|
259
|
-
|
|
295
|
+
# TODO: COMMENT IF FIREBASE PROD IS LINKED TO GOOGLE PLAY
|
|
296
|
+
android_build_apk(flavor)
|
|
297
|
+
publish_apk(flavor)
|
|
298
|
+
# TODO: UNCOMMENT IF FIREBASE PROD IS LINKED TO GOOGLE PLAY
|
|
299
|
+
# android_build_bundle(flavor)
|
|
300
|
+
# publish_bundle(flavor)
|
|
260
301
|
rescue => exception
|
|
261
302
|
UI.error(exception)
|
|
262
303
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#import "AppDelegate.h"
|
|
2
|
+
|
|
3
|
+
#import <React/RCTBundleURLProvider.h>
|
|
4
|
+
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
|
5
|
+
|
|
6
|
+
@implementation AppDelegate
|
|
7
|
+
|
|
8
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
9
|
+
{
|
|
10
|
+
self.moduleName = @"AppsMobile";
|
|
11
|
+
self.dependencyProvider = [RCTAppDependencyProvider new];
|
|
12
|
+
// You can add your custom initial props in the dictionary below.
|
|
13
|
+
// They will be passed down to the ViewController used by React Native.
|
|
14
|
+
self.initialProps = @{};
|
|
15
|
+
|
|
16
|
+
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
|
20
|
+
{
|
|
21
|
+
return [self bundleURL];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
- (NSURL *)bundleURL
|
|
25
|
+
{
|
|
26
|
+
#if DEBUG
|
|
27
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"src/main"];
|
|
28
|
+
#else
|
|
29
|
+
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
|
30
|
+
#endif
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { withNxMetro } = require('@nx/react-native');
|
|
3
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
4
|
+
|
|
5
|
+
const defaultConfig = getDefaultConfig(__dirname);
|
|
6
|
+
const { assetExts, sourceExts } = defaultConfig.resolver;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Metro configuration
|
|
10
|
+
* https://reactnative.dev/docs/metro
|
|
11
|
+
*
|
|
12
|
+
* @type {import('metro-config').MetroConfig}
|
|
13
|
+
*/
|
|
14
|
+
const customConfig = {
|
|
15
|
+
cacheVersion: 'mobile',
|
|
16
|
+
transformer: {
|
|
17
|
+
babelTransformerPath: require.resolve('react-native-svg-transformer'),
|
|
18
|
+
getTransformOptions: async () => ({
|
|
19
|
+
transform: {
|
|
20
|
+
experimentalImportSupport: false,
|
|
21
|
+
inlineRequires: true,
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
resolver: {
|
|
26
|
+
extraNodeModules: {
|
|
27
|
+
'@': path.resolve(__dirname, 'src'),
|
|
28
|
+
},
|
|
29
|
+
assetExts: assetExts.filter((ext) => ext !== 'svg'),
|
|
30
|
+
sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
|
|
35
|
+
// Change this to true to see debugging info.
|
|
36
|
+
// Useful if you have issues resolving modules
|
|
37
|
+
debug: false,
|
|
38
|
+
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
|
|
39
|
+
extensions: [],
|
|
40
|
+
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
|
|
41
|
+
watchFolders: [],
|
|
42
|
+
});
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"pre-build": "npm run ensure-symlink && npm run sync-deps && npm run pod-install",
|
|
16
16
|
"list:ios-configurations": "cd ios && xcodebuild -list",
|
|
17
17
|
"list:ios-devices": "xcrun xctrace list devices",
|
|
18
|
-
"xcode": "open ios/AppsMobile.xcworkspace",
|
|
18
|
+
"xcode": "open -a Xcode ios/AppsMobile.xcworkspace",
|
|
19
19
|
"touch-xcode": "cd ios && touch .xcode.env",
|
|
20
20
|
"check-env:mobile": "cd ../.. && npm run check-env:mobile",
|
|
21
21
|
"setup-fastlane": "rbenv local && bundle install && bundle update",
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@gorhom/bottom-sheet": "*",
|
|
28
28
|
"@hookform/resolvers": "*",
|
|
29
|
-
"@react-native-async-storage/async-storage": "*",
|
|
30
29
|
"@react-native-community/datetimepicker": "*",
|
|
31
30
|
"@react-native-community/hooks": "*",
|
|
32
31
|
"@react-native/metro-config": "*",
|
|
@@ -54,7 +53,6 @@
|
|
|
54
53
|
"metro-config": "*",
|
|
55
54
|
"react-hook-form": "*",
|
|
56
55
|
"react-native-dotenv": "*",
|
|
57
|
-
"react-native-fast-image": "*",
|
|
58
56
|
"react-native-gesture-handler": "*",
|
|
59
57
|
"react-native-get-random-values": "*",
|
|
60
58
|
"react-native-haptic-feedback": "*",
|
|
@@ -69,6 +67,7 @@
|
|
|
69
67
|
"react-native-simple-toast": "*",
|
|
70
68
|
"react-native-svg-transformer": "*",
|
|
71
69
|
"react-native-svg": "*",
|
|
70
|
+
"react-native-turbo-image": "*",
|
|
72
71
|
"react-native-url-polyfill": "*",
|
|
73
72
|
"react-native": "*",
|
|
74
73
|
"react": "*",
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
1
|
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
|
3
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
|
3
|
+
import { AsyncStorage, PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
|
5
4
|
import React from 'react';
|
|
6
5
|
import { LogBox } from 'react-native';
|
|
7
6
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
8
7
|
import 'react-native-get-random-values';
|
|
8
|
+
import { MMKV } from 'react-native-mmkv';
|
|
9
9
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
10
10
|
import { enableFreeze } from 'react-native-screens';
|
|
11
11
|
import { useDeviceContext } from 'twrnc';
|
|
12
12
|
|
|
13
|
+
import { StorageManager } from '@/components';
|
|
14
|
+
import CONFIG from '@/config';
|
|
15
|
+
import ApplicationRoutes from '@/routes';
|
|
16
|
+
import { tw } from '@/tailwind';
|
|
13
17
|
import 'react-native-url-polyfill/auto';
|
|
14
18
|
|
|
15
|
-
import { StorageManager } from '../components';
|
|
16
|
-
import ApplicationRoutes from '../routes';
|
|
17
|
-
import { tw } from '../tailwind';
|
|
18
|
-
|
|
19
19
|
LogBox.ignoreLogs(['VirtualizedLists', 'onAnimatedValueUpdate']);
|
|
20
20
|
|
|
21
21
|
enableFreeze(true);
|
|
@@ -31,8 +31,23 @@ const queryClient = new QueryClient({
|
|
|
31
31
|
},
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
const storage = new MMKV({
|
|
35
|
+
encryptionKey: CONFIG.STORAGE_KEY,
|
|
36
|
+
id: 'react-query-persist',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const MmkvStorage: AsyncStorage = {
|
|
40
|
+
getItem: (name) => {
|
|
41
|
+
const value = storage.getString(name);
|
|
42
|
+
|
|
43
|
+
return value ?? null;
|
|
44
|
+
},
|
|
45
|
+
removeItem: (name) => storage.delete(name),
|
|
46
|
+
setItem: (name, value) => storage.set(name, value),
|
|
47
|
+
};
|
|
48
|
+
|
|
34
49
|
const persister = createAsyncStoragePersister({
|
|
35
|
-
storage: AsyncStorage,
|
|
50
|
+
storage: MmkvStorage as AsyncStorage,
|
|
36
51
|
});
|
|
37
52
|
|
|
38
53
|
const persistOptions = { maxAge: CACHE_TIME, persister };
|
|
@@ -13,8 +13,8 @@ import { Keyboard, StyleProp, ViewStyle } from 'react-native';
|
|
|
13
13
|
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
|
|
14
14
|
import Animated, { Extrapolation, interpolate, useAnimatedStyle } from 'react-native-reanimated';
|
|
15
15
|
|
|
16
|
-
import { tw } from '
|
|
17
|
-
import { DefaultComponentProps } from '
|
|
16
|
+
import { tw } from '@/tailwind';
|
|
17
|
+
import { DefaultComponentProps } from '@/types';
|
|
18
18
|
|
|
19
19
|
export type BottomSheetProps = DefaultComponentProps & {
|
|
20
20
|
backgroundStyle?: StyleProp<Omit<ViewStyle, 'left' | 'right' | 'position' | 'top' | 'bottom'>>;
|
|
@@ -127,7 +127,12 @@ export function BottomSheet(props: BottomSheetProps) {
|
|
|
127
127
|
);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
export function useBottomSheet() {
|
|
130
|
+
export function useBottomSheet(): {
|
|
131
|
+
closeSheet: () => void;
|
|
132
|
+
expandSheet: () => void;
|
|
133
|
+
isVisible: boolean;
|
|
134
|
+
sheetRef: RefObject<BottomSheetModal>;
|
|
135
|
+
} {
|
|
131
136
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
132
137
|
const sheetRef = useRef<BottomSheetModal>(null);
|
|
133
138
|
|
|
@@ -143,5 +148,5 @@ export function useBottomSheet() {
|
|
|
143
148
|
setIsVisible(false);
|
|
144
149
|
}, []);
|
|
145
150
|
|
|
146
|
-
return { closeSheet, expandSheet, isVisible, sheetRef };
|
|
151
|
+
return { closeSheet, expandSheet, isVisible, sheetRef: sheetRef as RefObject<BottomSheetModal> };
|
|
147
152
|
}
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
TextStyle,
|
|
6
6
|
TouchableOpacity,
|
|
7
7
|
TouchableOpacityProps,
|
|
8
|
+
View,
|
|
8
9
|
ViewStyle,
|
|
9
10
|
} from 'react-native';
|
|
10
11
|
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { Typography } from '../Typography';
|
|
12
|
+
import { Typography } from '@/components/atoms/Typography';
|
|
13
|
+
import { colors, disabledInputStyle, tw } from '@/tailwind';
|
|
14
|
+
import { DefaultComponentProps } from '@/types';
|
|
15
15
|
|
|
16
16
|
type Props = DefaultComponentProps &
|
|
17
17
|
TouchableOpacityProps & {
|
|
@@ -45,7 +45,7 @@ export function Button(props: Props) {
|
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
47
|
<TouchableOpacity activeOpacity={activeOpacity} disabled={disabled} style={[style]} {...rest}>
|
|
48
|
-
<
|
|
48
|
+
<View
|
|
49
49
|
style={[
|
|
50
50
|
tw`bg-primary-700 items-center justify-center rounded-xl p-3`,
|
|
51
51
|
buttonStyle,
|
|
@@ -53,7 +53,7 @@ export function Button(props: Props) {
|
|
|
53
53
|
]}
|
|
54
54
|
>
|
|
55
55
|
{isLoading ? <ActivityIndicator color={activityIndicatorColor} /> : display}
|
|
56
|
-
</
|
|
56
|
+
</View>
|
|
57
57
|
</TouchableOpacity>
|
|
58
58
|
);
|
|
59
59
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
2
3
|
|
|
3
|
-
import { tw } from '
|
|
4
|
-
import { DefaultComponentProps } from '
|
|
5
|
-
import { Box } from '../Box';
|
|
4
|
+
import { tw } from '@/tailwind';
|
|
5
|
+
import { DefaultComponentProps } from '@/types';
|
|
6
6
|
|
|
7
7
|
type Props = DefaultComponentProps & {};
|
|
8
8
|
|
|
9
9
|
export function Divider(props: Props) {
|
|
10
10
|
const { style } = props;
|
|
11
11
|
|
|
12
|
-
return <
|
|
12
|
+
return <View style={[tw`h-[1px] w-full bg-gray-200`, style]}></View>;
|
|
13
13
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
|
|
5
|
+
import { tw } from '@/tailwind';
|
|
6
|
+
import { DefaultComponentProps } from '@/types';
|
|
7
|
+
|
|
8
|
+
type Props = DefaultComponentProps & {
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
excludedEdges?: Edge[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const safeAreaViewEdges: Edge[] = Platform.select({
|
|
14
|
+
android: ['left', 'right', 'bottom'],
|
|
15
|
+
default: [],
|
|
16
|
+
ios: ['left', 'right', 'bottom', 'top'],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export function ExcludedEdges(props: Props) {
|
|
20
|
+
const { children, excludedEdges = [] } = props;
|
|
21
|
+
const insets = useSafeAreaInsets();
|
|
22
|
+
const { style } = props;
|
|
23
|
+
const edges =
|
|
24
|
+
excludedEdges.length > 0
|
|
25
|
+
? safeAreaViewEdges.filter((edge) => !excludedEdges.includes(edge))
|
|
26
|
+
: safeAreaViewEdges;
|
|
27
|
+
|
|
28
|
+
function getExcludedEdgesStyles() {
|
|
29
|
+
return excludedEdges.map((edge) => tw`-${edge}-[${insets[edge]}px]`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<SafeAreaView edges={edges} style={[getExcludedEdgesStyles(), style]}>
|
|
34
|
+
{children}
|
|
35
|
+
</SafeAreaView>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './excluded-edges.component';
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { StyleProp, TextStyle } from 'react-native';
|
|
2
|
+
import { StyleProp, TextStyle, View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { Typography } from '../Typography';
|
|
4
|
+
import { Typography } from '@/components/atoms/Typography';
|
|
5
|
+
import { tw } from '@/tailwind';
|
|
6
|
+
import { DefaultComponentProps } from '@/types';
|
|
8
7
|
|
|
9
8
|
type Props = DefaultComponentProps & {
|
|
10
9
|
children?: React.ReactNode;
|
|
@@ -17,7 +16,7 @@ export function InputLayout(props: Props) {
|
|
|
17
16
|
const { children, error, isRequired, label, style, textStyle } = props;
|
|
18
17
|
|
|
19
18
|
return (
|
|
20
|
-
<
|
|
19
|
+
<View style={[style]}>
|
|
21
20
|
{label && (
|
|
22
21
|
<Typography style={[tw`mb-2 text-gray-600`, textStyle]}>
|
|
23
22
|
{label}
|
|
@@ -26,10 +25,10 @@ export function InputLayout(props: Props) {
|
|
|
26
25
|
)}
|
|
27
26
|
{children}
|
|
28
27
|
{!!error && (
|
|
29
|
-
<
|
|
28
|
+
<View style={tw`items-end`}>
|
|
30
29
|
<Typography style={tw`text-right text-red-500`}>{error}</Typography>
|
|
31
|
-
</
|
|
30
|
+
</View>
|
|
32
31
|
)}
|
|
33
|
-
</
|
|
32
|
+
</View>
|
|
34
33
|
);
|
|
35
34
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './keyboard-aware-scroll-view.component';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
NativeScrollEvent,
|
|
4
|
+
NativeSyntheticEvent,
|
|
5
|
+
RefreshControlProps,
|
|
6
|
+
StyleProp,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { KeyboardAwareScrollView as RNKeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
|
10
|
+
import Animated from 'react-native-reanimated';
|
|
11
|
+
|
|
12
|
+
import { tw } from '@/tailwind';
|
|
13
|
+
import { DefaultComponentProps } from '@/types';
|
|
14
|
+
|
|
15
|
+
type Props = DefaultComponentProps & {
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
scrollViewRef?: React.RefObject<RNKeyboardAwareScrollView>;
|
|
18
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
19
|
+
extraBottomPadding?: number;
|
|
20
|
+
refreshControl?: React.ReactElement<RefreshControlProps> | undefined;
|
|
21
|
+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const defaultStyle = tw`grow`;
|
|
25
|
+
|
|
26
|
+
const AnimatedKeyboardAwareScrollView = Animated.createAnimatedComponent(RNKeyboardAwareScrollView);
|
|
27
|
+
|
|
28
|
+
export function KeyboardAwareScrollView(props: Props) {
|
|
29
|
+
const {
|
|
30
|
+
children,
|
|
31
|
+
containerStyle,
|
|
32
|
+
extraBottomPadding,
|
|
33
|
+
onScroll,
|
|
34
|
+
refreshControl,
|
|
35
|
+
scrollViewRef,
|
|
36
|
+
style,
|
|
37
|
+
} = props;
|
|
38
|
+
|
|
39
|
+
const defaultContainerStyle = [
|
|
40
|
+
defaultStyle,
|
|
41
|
+
containerStyle,
|
|
42
|
+
// eslint-disable-next-line no-magic-numbers
|
|
43
|
+
extraBottomPadding && tw`pb-[${extraBottomPadding + 50}px]`,
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<AnimatedKeyboardAwareScrollView
|
|
48
|
+
ref={scrollViewRef}
|
|
49
|
+
contentContainerStyle={[defaultContainerStyle, containerStyle]}
|
|
50
|
+
enableResetScrollToCoords={false}
|
|
51
|
+
keyboardShouldPersistTaps="handled"
|
|
52
|
+
refreshControl={refreshControl}
|
|
53
|
+
scrollEventThrottle={16}
|
|
54
|
+
style={style}
|
|
55
|
+
onScroll={onScroll}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
</AnimatedKeyboardAwareScrollView>
|
|
59
|
+
);
|
|
60
|
+
}
|
package/templates/apps/mobile/src/components/atoms/ListLoadingItem/list-loading-item.component.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Skeleton } from '../Skeleton';
|
|
4
|
+
import { Skeleton } from '@/components/atoms/Skeleton';
|
|
5
|
+
import { tw } from '@/tailwind';
|
|
6
|
+
import { DefaultComponentProps } from '@/types';
|
|
7
7
|
|
|
8
8
|
type Props = DefaultComponentProps & {
|
|
9
9
|
isLoading: boolean;
|
|
@@ -13,19 +13,19 @@ export function ListLoadingItemComponent(props: Props) {
|
|
|
13
13
|
const { isLoading, style } = props;
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
|
-
<
|
|
17
|
-
<
|
|
16
|
+
<View style={[style]}>
|
|
17
|
+
<View style={[tw`gap-2`, style]}>
|
|
18
18
|
<Skeleton isLoading={isLoading}>
|
|
19
|
-
{isLoading && <
|
|
19
|
+
{isLoading && <View style={tw`h-[100px] w-full`} />}
|
|
20
20
|
</Skeleton>
|
|
21
21
|
<Skeleton isLoading={isLoading}>
|
|
22
|
-
{isLoading && <
|
|
22
|
+
{isLoading && <View style={tw`h-[100px] w-full`} />}
|
|
23
23
|
</Skeleton>
|
|
24
24
|
<Skeleton isLoading={isLoading}>
|
|
25
|
-
{isLoading && <
|
|
25
|
+
{isLoading && <View style={tw`h-[100px] w-full`} />}
|
|
26
26
|
</Skeleton>
|
|
27
|
-
</
|
|
28
|
-
</
|
|
27
|
+
</View>
|
|
28
|
+
</View>
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -33,24 +33,24 @@ export function ListLoadingHorizontalItemComponent(props: Props) {
|
|
|
33
33
|
const { isLoading, style } = props;
|
|
34
34
|
|
|
35
35
|
return (
|
|
36
|
-
<
|
|
37
|
-
<
|
|
36
|
+
<View style={[style]}>
|
|
37
|
+
<View style={[tw`flex-row gap-2`, style]}>
|
|
38
38
|
<Skeleton isLoading={isLoading}>
|
|
39
|
-
{isLoading && <
|
|
39
|
+
{isLoading && <View style={tw`h-[200px] w-[100px]`} />}
|
|
40
40
|
</Skeleton>
|
|
41
41
|
<Skeleton isLoading={isLoading}>
|
|
42
|
-
{isLoading && <
|
|
42
|
+
{isLoading && <View style={tw`h-[200px] w-[100px]`} />}
|
|
43
43
|
</Skeleton>
|
|
44
44
|
<Skeleton isLoading={isLoading}>
|
|
45
|
-
{isLoading && <
|
|
45
|
+
{isLoading && <View style={tw`h-[200px] w-[100px]`} />}
|
|
46
46
|
</Skeleton>
|
|
47
47
|
<Skeleton isLoading={isLoading}>
|
|
48
|
-
{isLoading && <
|
|
48
|
+
{isLoading && <View style={tw`h-[200px] w-[100px]`} />}
|
|
49
49
|
</Skeleton>
|
|
50
50
|
<Skeleton isLoading={isLoading}>
|
|
51
|
-
{isLoading && <
|
|
51
|
+
{isLoading && <View style={tw`h-[200px] w-[100px]`} />}
|
|
52
52
|
</Skeleton>
|
|
53
|
-
</
|
|
54
|
-
</
|
|
53
|
+
</View>
|
|
54
|
+
</View>
|
|
55
55
|
);
|
|
56
56
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-magic-numbers */
|
|
2
2
|
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
3
3
|
import React, { useCallback, useState } from 'react';
|
|
4
|
-
import { Keyboard, ModalBaseProps, StyleProp, ViewStyle } from 'react-native';
|
|
4
|
+
import { Keyboard, ModalBaseProps, StyleProp, View, ViewStyle } from 'react-native';
|
|
5
5
|
import RNModal from 'react-native-modal';
|
|
6
6
|
|
|
7
|
-
import { tw } from '
|
|
8
|
-
import { DefaultComponentProps } from '
|
|
9
|
-
import { Box } from '../Box';
|
|
7
|
+
import { tw } from '@/tailwind';
|
|
8
|
+
import { DefaultComponentProps } from '@/types';
|
|
10
9
|
|
|
11
10
|
export type ModalProps = DefaultComponentProps &
|
|
12
11
|
ModalBaseProps & {
|
|
@@ -32,7 +31,7 @@ export function Modal(props: ModalProps) {
|
|
|
32
31
|
onBackdropPress={onBackdropPress}
|
|
33
32
|
>
|
|
34
33
|
<BottomSheetModalProvider>
|
|
35
|
-
<
|
|
34
|
+
<View style={[tw`px-4`, containerStyle]}>{children}</View>
|
|
36
35
|
</BottomSheetModalProvider>
|
|
37
36
|
</RNModal>
|
|
38
37
|
);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ActivityIndicator } from 'react-native';
|
|
2
|
+
import { ActivityIndicator, View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import { colors, tw } from '
|
|
5
|
-
import { DefaultComponentProps } from '
|
|
6
|
-
import { Box } from '../Box';
|
|
4
|
+
import { colors, tw } from '@/tailwind';
|
|
5
|
+
import { DefaultComponentProps } from '@/types';
|
|
7
6
|
|
|
8
7
|
type Props = DefaultComponentProps;
|
|
9
8
|
|
|
@@ -11,8 +10,8 @@ export function ScreenLoader(props: Props) {
|
|
|
11
10
|
const { style } = props;
|
|
12
11
|
|
|
13
12
|
return (
|
|
14
|
-
<
|
|
13
|
+
<View style={[tw`h-full w-full items-center justify-center bg-gray-50 p-8`, style]}>
|
|
15
14
|
<ActivityIndicator color={colors.primary[400]} />
|
|
16
|
-
</
|
|
15
|
+
</View>
|
|
17
16
|
);
|
|
18
17
|
}
|