(null);
- const {
- animatedHandleHeight,
- animatedSnapPoints,
- animatedContentHeight,
- handleContentLayout,
- } = useBottomSheetDynamicSnapPoints(initialSnapPoints);
-
- // callbacks
- const handleIncreaseContentPress = useCallback(() => {
- setCount(state => state + 1);
- }, []);
- const handleDecreaseContentPress = useCallback(() => {
- setCount(state => Math.max(state - 1, 0));
- }, []);
-
- const handlePresentPress = useCallback(() => {
- bottomSheetRef.current?.present();
- }, []);
- const handleDismissPress = useCallback(() => {
- bottomSheetRef.current?.dismiss();
- }, []);
-
- // styles
- const contentContainerStyle = useMemo(
- () => ({
- ...styles.contentContainerStyle,
- paddingBottom: safeBottomArea || 6,
- }),
- [safeBottomArea]
- );
- const emojiContainerStyle = useMemo(
- () => ({
- ...styles.emojiContainer,
- height: 50 * count,
- }),
- [count]
- );
-
- // renders
- return (
-
-
-
-
-
-
- Could this sheet modal resize to its content height ?
-
-
- 😍
-
-
-
-
-
-
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- padding: 24,
- },
- contentContainerStyle: {
- paddingTop: 12,
- paddingHorizontal: 24,
- backgroundColor: 'white',
- },
- message: {
- fontSize: 24,
- fontWeight: '600',
- marginBottom: 12,
- color: 'black',
- },
- emoji: {
- fontSize: 156,
- textAlign: 'center',
- alignSelf: 'center',
- },
- emojiContainer: {
- overflow: 'hidden',
- justifyContent: 'center',
- },
-});
-
-export default withModalProvider(DynamicSnapPointExample);
diff --git a/example/app/tsconfig.json b/example/app/tsconfig.json
deleted file mode 100644
index fe28c76bf..000000000
--- a/example/app/tsconfig.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@gorhom/bottom-sheet": ["../../src/index"],
- "@gorhom/showcase-template": [
- "../bare/node_modules/@gorhom/showcase-template"
- ],
- "react-native-safe-area-context": [
- "../bare/node_modules/react-native-safe-area-context"
- ],
- "@react-navigation/native": [
- "../bare/node_modules/@react-navigation/native"
- ]
- },
- "allowUnreachableCode": false,
- "allowUnusedLabels": false,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "jsx": "react",
- "lib": ["esnext"],
- "module": "esnext",
- "moduleResolution": "node",
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "noImplicitUseStrict": false,
- "noStrictGenericChecks": false,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "strict": true,
- "target": "esnext"
- },
- "include": ["src"]
-}
diff --git a/example/assets/adaptive-icon.png b/example/assets/adaptive-icon.png
new file mode 100644
index 000000000..a3a02eb1d
Binary files /dev/null and b/example/assets/adaptive-icon.png differ
diff --git a/example/assets/comment.png b/example/assets/comment.png
new file mode 100644
index 000000000..7a1cb7f77
Binary files /dev/null and b/example/assets/comment.png differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/50.png b/example/assets/favicon.png
similarity index 100%
rename from example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/50.png
rename to example/assets/favicon.png
diff --git a/example/assets/icon.png b/example/assets/icon.png
new file mode 100644
index 000000000..ec785685b
Binary files /dev/null and b/example/assets/icon.png differ
diff --git a/example/assets/like.png b/example/assets/like.png
new file mode 100644
index 000000000..25ef332d5
Binary files /dev/null and b/example/assets/like.png differ
diff --git a/example/assets/retweet.png b/example/assets/retweet.png
new file mode 100644
index 000000000..117f92d9d
Binary files /dev/null and b/example/assets/retweet.png differ
diff --git a/example/assets/share.png b/example/assets/share.png
new file mode 100644
index 000000000..471e13f3e
Binary files /dev/null and b/example/assets/share.png differ
diff --git a/example/assets/splash.png b/example/assets/splash.png
new file mode 100644
index 000000000..e05dc271e
Binary files /dev/null and b/example/assets/splash.png differ
diff --git a/example/babel.config.js b/example/babel.config.js
new file mode 100644
index 000000000..ce75f8de3
--- /dev/null
+++ b/example/babel.config.js
@@ -0,0 +1,22 @@
+const path = require('path');
+const pak = require('../package.json');
+
+module.exports = function (api) {
+ api.cache(true);
+ return {
+ presets: ['babel-preset-expo'],
+ plugins: [
+ [
+ 'module-resolver',
+ {
+ extensions: ['.tsx', '.ts', '.js', '.json'],
+ alias: {
+ [pak.name]: path.join(__dirname, '..', pak.source),
+ },
+ },
+ ],
+ '@babel/plugin-proposal-export-namespace-from',
+ 'react-native-reanimated/plugin',
+ ],
+ };
+};
diff --git a/example/bare/android/.project b/example/bare/android/.project
deleted file mode 100644
index 3964dd3f5..000000000
--- a/example/bare/android/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- android
- Project android created by Buildship.
-
-
-
-
- org.eclipse.buildship.core.gradleprojectbuilder
-
-
-
-
-
- org.eclipse.buildship.core.gradleprojectnature
-
-
diff --git a/example/bare/android/.settings/org.eclipse.buildship.core.prefs b/example/bare/android/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index e8895216f..000000000
--- a/example/bare/android/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,2 +0,0 @@
-connection.project.dir=
-eclipse.preferences.version=1
diff --git a/example/bare/android/app/build.gradle b/example/bare/android/app/build.gradle
deleted file mode 100644
index 604e0db44..000000000
--- a/example/bare/android/app/build.gradle
+++ /dev/null
@@ -1,307 +0,0 @@
-apply plugin: "com.android.application"
-
-import com.android.build.OutputFile
-import org.apache.tools.ant.taskdefs.condition.Os
-
-/**
- * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
- * and bundleReleaseJsAndAssets).
- * These basically call `react-native bundle` with the correct arguments during the Android build
- * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
- * bundle directly from the development server. Below you can see all the possible configurations
- * and their defaults. If you decide to add a configuration block, make sure to add it before the
- * `apply from: "../../node_modules/react-native/react.gradle"` line.
- *
- * project.ext.react = [
- * // the name of the generated asset file containing your JS bundle
- * bundleAssetName: "index.android.bundle",
- *
- * // the entry file for bundle generation
- * entryFile: "index.android.js",
- *
- * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
- * bundleCommand: "ram-bundle",
- *
- * // whether to bundle JS and assets in debug mode
- * bundleInDebug: false,
- *
- * // whether to bundle JS and assets in release mode
- * bundleInRelease: true,
- *
- * // whether to bundle JS and assets in another build variant (if configured).
- * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
- * // The configuration property can be in the following formats
- * // 'bundleIn${productFlavor}${buildType}'
- * // 'bundleIn${buildType}'
- * // bundleInFreeDebug: true,
- * // bundleInPaidRelease: true,
- * // bundleInBeta: true,
- *
- * // whether to disable dev mode in custom build variants (by default only disabled in release)
- * // for BottomSheetExample: to disable dev mode in the staging build type (if configured)
- * devDisabledInStaging: true,
- * // The configuration property can be in the following formats
- * // 'devDisabledIn${productFlavor}${buildType}'
- * // 'devDisabledIn${buildType}'
- *
- * // the root of your project, i.e. where "package.json" lives
- * root: "../../",
- *
- * // where to put the JS bundle asset in debug mode
- * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
- *
- * // where to put the JS bundle asset in release mode
- * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
- *
- * // where to put drawable resources / React Native assets, e.g. the ones you use via
- * // require('./image.png')), in debug mode
- * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
- *
- * // where to put drawable resources / React Native assets, e.g. the ones you use via
- * // require('./image.png')), in release mode
- * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
- *
- * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
- * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
- * // date; if you have any other folders that you want to ignore for performance reasons (gradle
- * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
- * // for BottomSheetExample, you might want to remove it from here.
- * inputExcludes: ["android/**", "ios/**"],
- *
- * // override which node gets called and with what additional arguments
- * nodeExecutableAndArgs: ["node"],
- *
- * // supply additional arguments to the packager
- * extraPackagerArgs: []
- * ]
- */
-
-project.ext.react = [
- enableHermes: true,
- entryFile: "index.ts",
-]
-
-apply from: "../../node_modules/react-native/react.gradle"
-
-/**
- * Set this to true to create two separate APKs instead of one:
- * - An APK that only works on ARM devices
- * - An APK that only works on x86 devices
- * The advantage is the size of the APK is reduced by about 4MB.
- * Upload all the APKs to the Play Store and people will download
- * the correct one based on the CPU architecture of their device.
- */
-def enableSeparateBuildPerCPUArchitecture = false
-
-/**
- * Run Proguard to shrink the Java bytecode in release builds.
- */
-def enableProguardInReleaseBuilds = false
-
-/**
- * The preferred build flavor of JavaScriptCore.
- *
- * For BottomSheetExample, to use the international variant, you can use:
- * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
- *
- * The international variant includes ICU i18n library and necessary data
- * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
- * give correct results when using with locales other than en-US. Note that
- * this variant is about 6MiB larger per architecture than default.
- */
-def jscFlavor = 'org.webkit:android-jsc:+'
-
-/**
- * Whether to enable the Hermes VM.
- *
- * This should be set on project.ext.react and that value will be read here. If it is not set
- * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
- * and the benefits of using Hermes will therefore be sharply reduced.
- */
-def enableHermes = project.ext.react.get("enableHermes", false);
-
-/**
- * Architectures to build native code for in debug.
- */
-def reactNativeArchitectures() {
- def value = project.getProperties().get("reactNativeArchitectures")
- return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
-}
-
-android {
- compileSdkVersion rootProject.ext.compileSdkVersion
-
- defaultConfig {
- applicationId "dev.gorhom.bottomsheet"
- minSdkVersion rootProject.ext.minSdkVersion
- targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 1
- versionName "1.0"
- buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
- if (isNewArchitectureEnabled()) {
- // We configure the NDK build only if you decide to opt-in for the New Architecture.
- externalNativeBuild {
- ndkBuild {
- arguments "APP_PLATFORM=android-21",
- "APP_STL=c++_shared",
- "NDK_TOOLCHAIN_VERSION=clang",
- "GENERATED_SRC_DIR=$buildDir/generated/source",
- "PROJECT_BUILD_DIR=$buildDir",
- "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
- "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
- "NODE_MODULES_DIR=$rootDir/../node_modules"
- cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
- cppFlags "-std=c++17"
- }
- }
- if (!enableSeparateBuildPerCPUArchitecture) {
- ndk {
- abiFilters (*reactNativeArchitectures())
- }
- }
- }
- }
- if (isNewArchitectureEnabled()) {
- // We configure the NDK build only if you decide to opt-in for the New Architecture.
- externalNativeBuild {
- ndkBuild {
- path "$projectDir/src/main/jni/Android.mk"
- }
- }
- def reactAndroidProjectDir = project(':ReactAndroid').projectDir
- def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
- dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
- from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
- into("$buildDir/react-ndk/exported")
- }
- def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
- dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
- from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
- into("$buildDir/react-ndk/exported")
- }
- afterEvaluate {
- // If you wish to add a custom TurboModule or component locally,
- // you should uncomment this line.
- // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
- preDebugBuild.dependsOn(packageReactNdkDebugLibs)
- preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
- // Due to a bug inside AGP, we have to explicitly set a dependency
- // between configureNdkBuild* tasks and the preBuild tasks.
- // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
- configureNdkBuildRelease.dependsOn(preReleaseBuild)
- configureNdkBuildDebug.dependsOn(preDebugBuild)
- reactNativeArchitectures().each { architecture ->
- tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
- dependsOn("preDebugBuild")
- }
- tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
- dependsOn("preReleaseBuild")
- }
- }
- }
- }
- splits {
- abi {
- reset()
- enable enableSeparateBuildPerCPUArchitecture
- universalApk false // If true, also generate a universal APK
- include (*reactNativeArchitectures())
- }
- }
- signingConfigs {
- debug {
- storeFile file('debug.keystore')
- storePassword 'android'
- keyAlias 'androiddebugkey'
- keyPassword 'android'
- }
- }
- buildTypes {
- debug {
- signingConfig signingConfigs.debug
- }
- release {
- // Caution! In production, you need to generate your own keystore file.
- // see https://facebook.github.io/react-native/docs/signed-apk-android.
- signingConfig signingConfigs.debug
- minifyEnabled enableProguardInReleaseBuilds
- proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
- }
- }
- // applicationVariants are e.g. debug, release
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- // For each separate APK per architecture, set a unique version code as described here:
- // https://developer.android.com/studio/build/configure-apk-splits.html
- def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
- def abi = output.getFilter(OutputFile.ABI)
- if (abi != null) { // null for the universal-debug, universal-release variants
- output.versionCodeOverride =
- defaultConfig.versionCode * 1000 + versionCodes.get(abi)
- }
-
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- //noinspection GradleDynamicVersion
- implementation "com.facebook.react:react-native:+" // From node_modules
- implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
- implementation 'androidx.work:work-runtime-ktx:2.7.1'
-
- debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.fbjni'
- }
- debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.flipper'
- exclude group:'com.squareup.okhttp3', module:'okhttp'
- }
- debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.flipper'
- }
-
- if (enableHermes) {
- //noinspection GradleDynamicVersion
- implementation("com.facebook.react:hermes-engine:+") { // From node_modules
- exclude group:'com.facebook.fbjni'
- }
- } else {
- implementation jscFlavor
- }
-
-}
-
-if (isNewArchitectureEnabled()) {
- // If new architecture is enabled, we let you build RN from source
- // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
- // This will be applied to all the imported transtitive dependency.
- configurations.all {
- resolutionStrategy.dependencySubstitution {
- substitute(module("com.facebook.react:react-native"))
- .using(project(":ReactAndroid"))
- .because("On New Architecture we're building React Native from source")
- substitute(module("com.facebook.react:hermes-engine"))
- .using(project(":ReactAndroid:hermes-engine"))
- .because("On New Architecture we're building Hermes from source")
- }
- }
-}
-
-// Run this once to be able to run the application with BUCK
-// puts all compile dependencies into folder libs for BUCK to use
-task copyDownloadableDepsToLibs(type: Copy) {
- from configurations.implementation
- into 'libs'
-}
-
-apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
-
-def isNewArchitectureEnabled() {
- // To opt-in for the New Architecture, you can either:
- // - Set `newArchEnabled` to true inside the `gradle.properties` file
- // - Invoke gradle with `-newArchEnabled=true`
- // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
- return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
-}
diff --git a/example/bare/android/app/debug.keystore b/example/bare/android/app/debug.keystore
deleted file mode 100644
index 364e105ed..000000000
Binary files a/example/bare/android/app/debug.keystore and /dev/null differ
diff --git a/example/bare/android/app/proguard-rules.pro b/example/bare/android/app/proguard-rules.pro
deleted file mode 100644
index 2059464ad..000000000
--- a/example/bare/android/app/proguard-rules.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
--keep class com.facebook.react.turbomodule.** { *; }
diff --git a/example/bare/android/app/src/debug/AndroidManifest.xml b/example/bare/android/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 85182f0d7..000000000
--- a/example/bare/android/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/example/bare/android/app/src/debug/java/dev/gorhom/bottomsheet/ReactNativeFlipper.java b/example/bare/android/app/src/debug/java/dev/gorhom/bottomsheet/ReactNativeFlipper.java
deleted file mode 100644
index f1bb0a128..000000000
--- a/example/bare/android/app/src/debug/java/dev/gorhom/bottomsheet/ReactNativeFlipper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the LICENSE file in the root
- * directory of this source tree.
- */
-package dev.gorhom.bottomsheet;
-
-import android.content.Context;
-import com.facebook.flipper.android.AndroidFlipperClient;
-import com.facebook.flipper.android.utils.FlipperUtils;
-import com.facebook.flipper.core.FlipperClient;
-import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
-import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
-import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
-import com.facebook.flipper.plugins.inspector.DescriptorMapping;
-import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
-import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
-import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
-import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
-import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
-import com.facebook.react.ReactInstanceEventListener;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.modules.network.NetworkingModule;
-import okhttp3.OkHttpClient;
-
-public class ReactNativeFlipper {
- public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
- if (FlipperUtils.shouldEnableFlipper(context)) {
- final FlipperClient client = AndroidFlipperClient.getInstance(context);
- client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
- client.addPlugin(new ReactFlipperPlugin());
- client.addPlugin(new DatabasesFlipperPlugin(context));
- client.addPlugin(new SharedPreferencesFlipperPlugin(context));
- client.addPlugin(CrashReporterPlugin.getInstance());
- NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
- NetworkingModule.setCustomClientBuilder(
- new NetworkingModule.CustomClientBuilder() {
- @Override
- public void apply(OkHttpClient.Builder builder) {
- builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
- }
- });
- client.addPlugin(networkFlipperPlugin);
- client.start();
- // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
- // Hence we run if after all native modules have been initialized
- ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
- if (reactContext == null) {
- reactInstanceManager.addReactInstanceEventListener(
- new ReactInstanceEventListener() {
- @Override
- public void onReactContextInitialized(ReactContext reactContext) {
- reactInstanceManager.removeReactInstanceEventListener(this);
- reactContext.runOnNativeModulesQueueThread(
- new Runnable() {
- @Override
- public void run() {
- client.addPlugin(new FrescoFlipperPlugin());
- }
- });
- }
- });
- } else {
- client.addPlugin(new FrescoFlipperPlugin());
- }
- }
- }
-}
diff --git a/example/bare/android/app/src/main/AndroidManifest.xml b/example/bare/android/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 53fd748bd..000000000
--- a/example/bare/android/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/example/bare/android/app/src/main/ic_launcher-playstore.png b/example/bare/android/app/src/main/ic_launcher-playstore.png
deleted file mode 100644
index 4367b20da..000000000
Binary files a/example/bare/android/app/src/main/ic_launcher-playstore.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainActivity.java b/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainActivity.java
deleted file mode 100644
index ee34d1363..000000000
--- a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainActivity.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package dev.gorhom.bottomsheet;
-
-import android.os.Bundle;
-
-import com.facebook.react.ReactActivity;
-import com.facebook.react.ReactActivityDelegate;
-import com.facebook.react.ReactRootView;
-
-public class MainActivity extends ReactActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(null);
- }
-
- /**
- * Returns the name of the main component registered from JavaScript. This is used to schedule
- * rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "BottomSheetExample";
- }
-
- @Override
- protected ReactActivityDelegate createReactActivityDelegate() {
- return new MainActivityDelegate(this, getMainComponentName());
- }
-
- public static class MainActivityDelegate extends ReactActivityDelegate {
- public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
- super(activity, mainComponentName);
- }
-
- @Override
- protected ReactRootView createRootView() {
- ReactRootView reactRootView = new ReactRootView(getContext());
- // If you opted-in for the New Architecture, we enable the Fabric Renderer.
- reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
- return reactRootView;
- }
-
- @Override
- protected boolean isConcurrentRootEnabled() {
- // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
- // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
- return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
- }
- }
-}
diff --git a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplication.java b/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplication.java
deleted file mode 100644
index 4dfe31d6e..000000000
--- a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplication.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package dev.gorhom.bottomsheet;
-
-import android.app.Application;
-import android.content.Context;
-
-import com.facebook.react.PackageList;
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactNativeHost;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.config.ReactFeatureFlags;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.JSIModulePackage;
-import com.facebook.soloader.SoLoader;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-
-import com.swmansion.reanimated.ReanimatedJSIModulePackage;
-
-public class MainApplication extends Application implements ReactApplication {
-
- private final ReactNativeHost mNewArchitectureNativeHost =
- new MainApplicationReactNativeHost(this);
-
- private final ReactNativeHost mReactNativeHost =
- new ReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- @Override
- protected List getPackages() {
- @SuppressWarnings("UnnecessaryLocalVariable")
- List packages = new PackageList(this).getPackages();
- // Packages that cannot be autolinked yet can be added manually here, for BottomSheetExample:
- // packages.add(new MyReactNativePackage());
- return packages;
- }
-
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
-
- @Override
- protected JSIModulePackage getJSIModulePackage() {
- return new ReanimatedJSIModulePackage();
- }
- };
-
- @Override
- public ReactNativeHost getReactNativeHost() {
- if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
- return mNewArchitectureNativeHost;
- } else {
- return mReactNativeHost;
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- // If you opted-in for the New Architecture, we enable the TurboModule system
- ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
- SoLoader.init(this, /* native exopackage */ false);
- initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); // Remove this line if you don't want Flipper enabled
- }
-
- /**
- * Loads Flipper in React Native templates.
- *
- * @param context
- */
- private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
- if (BuildConfig.DEBUG) {
- try {
- /*
- We use reflection here to pick up the class that initializes Flipper,
- since Flipper library is not available in release mode
- */
- Class> aClass = Class.forName("dev.gorhom.bottomsheet.ReactNativeFlipper");
- aClass
- .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
- .invoke(null, context, reactInstanceManager);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplicationReactNativeHost.java b/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplicationReactNativeHost.java
deleted file mode 100644
index 4866392b1..000000000
--- a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/MainApplicationReactNativeHost.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package dev.gorhom.bottomsheet;
-
-import android.app.Application;
-
-import androidx.annotation.NonNull;
-
-import com.facebook.react.PackageList;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactNativeHost;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
-import com.facebook.react.bridge.JSIModulePackage;
-import com.facebook.react.bridge.JSIModuleProvider;
-import com.facebook.react.bridge.JSIModuleSpec;
-import com.facebook.react.bridge.JSIModuleType;
-import com.facebook.react.bridge.JavaScriptContextHolder;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.UIManager;
-import com.facebook.react.fabric.ComponentFactory;
-import com.facebook.react.fabric.CoreComponentsRegistry;
-import com.facebook.react.fabric.ReactNativeConfig;
-import com.facebook.react.fabric.FabricJSIModuleProvider;
-import com.facebook.react.uimanager.ViewManagerRegistry;
-
-import dev.gorhom.bottomsheet.components.MainComponentsRegistry;
-import dev.gorhom.bottomsheet.modules.MainApplicationTurboModuleManagerDelegate;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
- * TurboModule delegates and the Fabric Renderer.
- *
- * Please note that this class is used ONLY if you opt-in for the New Architecture (see the
- * `newArchEnabled` property). Is ignored otherwise.
- */
-public class MainApplicationReactNativeHost extends ReactNativeHost {
- public MainApplicationReactNativeHost(Application application) {
- super(application);
- }
-
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- @Override
- protected List getPackages() {
- List packages = new PackageList(this).getPackages();
- // Packages that cannot be autolinked yet can be added manually here, for example:
- // packages.add(new MyReactNativePackage());
- // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
- // packages.add(new TurboReactPackage() { ... });
- // If you have custom Fabric Components, their ViewManagers should also be loaded here
- // inside a ReactPackage.
- return packages;
- }
-
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
-
- @NonNull
- @Override
- protected ReactPackageTurboModuleManagerDelegate.Builder
- getReactPackageTurboModuleManagerDelegateBuilder() {
- // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
- // for the new architecture and to use TurboModules correctly.
- return new MainApplicationTurboModuleManagerDelegate.Builder();
- }
-
- @Override
- protected JSIModulePackage getJSIModulePackage() {
- return new JSIModulePackage() {
- @Override
- public List getJSIModules(
- final ReactApplicationContext reactApplicationContext,
- final JavaScriptContextHolder jsContext) {
- final List specs = new ArrayList<>();
-
- // Here we provide a new JSIModuleSpec that will be responsible of providing the
- // custom Fabric Components.
- specs.add(
- new JSIModuleSpec() {
- @Override
- public JSIModuleType getJSIModuleType() {
- return JSIModuleType.UIManager;
- }
-
- @Override
- public JSIModuleProvider getJSIModuleProvider() {
- final ComponentFactory componentFactory = new ComponentFactory();
- CoreComponentsRegistry.register(componentFactory);
-
- // Here we register a Components Registry.
- // The one that is generated with the template contains no components
- // and just provides you the one from React Native core.
- MainComponentsRegistry.register(componentFactory);
-
- final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
-
- ViewManagerRegistry viewManagerRegistry =
- new ViewManagerRegistry(
- reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
-
- return new FabricJSIModuleProvider(
- reactApplicationContext,
- componentFactory,
- ReactNativeConfig.DEFAULT_CONFIG,
- viewManagerRegistry);
- }
- });
- return specs;
- }
- };
- }
-}
diff --git a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/components/MainComponentsRegistry.java b/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/components/MainComponentsRegistry.java
deleted file mode 100644
index 297a3168b..000000000
--- a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/components/MainComponentsRegistry.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package dev.gorhom.bottomsheet.components;
-
-import com.facebook.jni.HybridData;
-import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.fabric.ComponentFactory;
-import com.facebook.soloader.SoLoader;
-
-/**
- * Class responsible to load the custom Fabric Components. This class has native methods and needs a
- * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
- * folder for you).
- *
- * Please note that this class is used ONLY if you opt-in for the New Architecture (see the
- * `newArchEnabled` property). Is ignored otherwise.
- */
-@DoNotStrip
-public class MainComponentsRegistry {
- static {
- SoLoader.loadLibrary("fabricjni");
- }
-
- @DoNotStrip
- private final HybridData mHybridData;
-
- @DoNotStrip
- private native HybridData initHybrid(ComponentFactory componentFactory);
-
- @DoNotStrip
- private MainComponentsRegistry(ComponentFactory componentFactory) {
- mHybridData = initHybrid(componentFactory);
- }
-
- @DoNotStrip
- public static MainComponentsRegistry register(ComponentFactory componentFactory) {
- return new MainComponentsRegistry(componentFactory);
- }
-}
diff --git a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/modules/MainApplicationTurboModuleManagerDelegate.java b/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/modules/MainApplicationTurboModuleManagerDelegate.java
deleted file mode 100644
index 101bf2785..000000000
--- a/example/bare/android/app/src/main/java/dev/gorhom/bottomsheet/modules/MainApplicationTurboModuleManagerDelegate.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package dev.gorhom.bottomsheet.modules;
-
-import com.facebook.jni.HybridData;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.soloader.SoLoader;
-
-import java.util.List;
-
-/**
- * Class responsible to load the TurboModules. This class has native methods and needs a
- * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
- * folder for you).
- *
- *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
- * `newArchEnabled` property). Is ignored otherwise.
- */
-public class MainApplicationTurboModuleManagerDelegate
- extends ReactPackageTurboModuleManagerDelegate {
-
- private static volatile boolean sIsSoLibraryLoaded;
-
- protected MainApplicationTurboModuleManagerDelegate(
- ReactApplicationContext reactApplicationContext, List packages) {
- super(reactApplicationContext, packages);
- }
-
- protected native HybridData initHybrid();
-
- native boolean canCreateTurboModule(String moduleName);
-
- public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
- protected MainApplicationTurboModuleManagerDelegate build(
- ReactApplicationContext context, List packages) {
- return new MainApplicationTurboModuleManagerDelegate(context, packages);
- }
- }
-
- @Override
- protected synchronized void maybeLoadOtherSoLibraries() {
- if (!sIsSoLibraryLoaded) {
- // If you change the name of your application .so file in the Android.mk file,
- // make sure you update the name here as well.
- SoLoader.loadLibrary("bottomsheet_appmodules");
- sIsSoLibraryLoaded = true;
- }
- }
-}
diff --git a/example/bare/android/app/src/main/jni/Android.mk b/example/bare/android/app/src/main/jni/Android.mk
deleted file mode 100644
index 161c5ece4..000000000
--- a/example/bare/android/app/src/main/jni/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-THIS_DIR := $(call my-dir)
-
-include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
-
-# If you wish to add a custom TurboModule or Fabric component in your app you
-# will have to include the following autogenerated makefile.
-# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(THIS_DIR)
-
-# You can customize the name of your application .so file here.
-LOCAL_MODULE := bottomsheet_appmodules
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
-
-# If you wish to add a custom TurboModule or Fabric component in your app you
-# will have to uncomment those lines to include the generated source
-# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
-#
-# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
-# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
-# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
-
-# Here you should add any native library you wish to depend on.
-LOCAL_SHARED_LIBRARIES := \
- libfabricjni \
- libfbjni \
- libfolly_runtime \
- libglog \
- libjsi \
- libreact_codegen_rncore \
- libreact_debug \
- libreact_nativemodule_core \
- libreact_render_componentregistry \
- libreact_render_core \
- libreact_render_debug \
- libreact_render_graphics \
- librrc_view \
- libruntimeexecutor \
- libturbomodulejsijni \
- libyoga
-
-LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
-
-include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.cpp
deleted file mode 100644
index 39de093d1..000000000
--- a/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "MainApplicationModuleProvider.h"
-
-#include
-
-namespace facebook {
-namespace react {
-
-std::shared_ptr MainApplicationModuleProvider(
- const std::string moduleName,
- const JavaTurboModule::InitParams ¶ms) {
- // Here you can provide your own module provider for TurboModules coming from
- // either your application or from external libraries. The approach to follow
- // is similar to the following (for a library called `samplelibrary`:
- //
- // auto module = samplelibrary_ModuleProvider(moduleName, params);
- // if (module != nullptr) {
- // return module;
- // }
- // return rncore_ModuleProvider(moduleName, params);
- return rncore_ModuleProvider(moduleName, params);
-}
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.h b/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.h
deleted file mode 100644
index 2f2fb24a3..000000000
--- a/example/bare/android/app/src/main/jni/MainApplicationModuleProvider.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include
-#include
-
-#include
-
-namespace facebook {
-namespace react {
-
-std::shared_ptr MainApplicationModuleProvider(
- const std::string moduleName,
- const JavaTurboModule::InitParams ¶ms);
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp
deleted file mode 100644
index f2e4714dc..000000000
--- a/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "MainApplicationTurboModuleManagerDelegate.h"
-#include "MainApplicationModuleProvider.h"
-
-namespace facebook {
-namespace react {
-
-jni::local_ref
-MainApplicationTurboModuleManagerDelegate::initHybrid(
- jni::alias_ref) {
- return makeCxxInstance();
-}
-
-void MainApplicationTurboModuleManagerDelegate::registerNatives() {
- registerHybrid({
- makeNativeMethod(
- "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
- makeNativeMethod(
- "canCreateTurboModule",
- MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
- });
-}
-
-std::shared_ptr
-MainApplicationTurboModuleManagerDelegate::getTurboModule(
- const std::string name,
- const std::shared_ptr jsInvoker) {
- // Not implemented yet: provide pure-C++ NativeModules here.
- return nullptr;
-}
-
-std::shared_ptr
-MainApplicationTurboModuleManagerDelegate::getTurboModule(
- const std::string name,
- const JavaTurboModule::InitParams ¶ms) {
- return MainApplicationModuleProvider(name, params);
-}
-
-bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
- std::string name) {
- return getTurboModule(name, nullptr) != nullptr ||
- getTurboModule(name, {.moduleName = name}) != nullptr;
-}
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h
deleted file mode 100644
index 79c7634d9..000000000
--- a/example/bare/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#include
-#include
-
-#include
-#include
-
-namespace facebook {
-namespace react {
-
-class MainApplicationTurboModuleManagerDelegate
- : public jni::HybridClass<
- MainApplicationTurboModuleManagerDelegate,
- TurboModuleManagerDelegate> {
- public:
- // Adapt it to the package you used for your Java class.
- static constexpr auto kJavaDescriptor =
- "Ldev/gorhom/bottomsheet/modules/MainApplicationTurboModuleManagerDelegate;";
-
- static jni::local_ref initHybrid(jni::alias_ref);
-
- static void registerNatives();
-
- std::shared_ptr getTurboModule(
- const std::string name,
- const std::shared_ptr jsInvoker) override;
- std::shared_ptr getTurboModule(
- const std::string name,
- const JavaTurboModule::InitParams ¶ms) override;
-
- /**
- * Test-only method. Allows user to verify whether a TurboModule can be
- * created by instances of this class.
- */
- bool canCreateTurboModule(std::string name);
-};
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainComponentsRegistry.cpp b/example/bare/android/app/src/main/jni/MainComponentsRegistry.cpp
deleted file mode 100644
index c5188f4dc..000000000
--- a/example/bare/android/app/src/main/jni/MainComponentsRegistry.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "MainComponentsRegistry.h"
-
-#include
-#include
-#include
-#include
-
-namespace facebook {
-namespace react {
-
-MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
-
-std::shared_ptr
-MainComponentsRegistry::sharedProviderRegistry() {
- auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
-
- // Custom Fabric Components go here. You can register custom
- // components coming from your App or from 3rd party libraries here.
- //
- // providerRegistry->add(concreteComponentDescriptorProvider<
- // AocViewerComponentDescriptor>());
- return providerRegistry;
-}
-
-jni::local_ref
-MainComponentsRegistry::initHybrid(
- jni::alias_ref,
- ComponentFactory *delegate) {
- auto instance = makeCxxInstance(delegate);
-
- auto buildRegistryFunction =
- [](EventDispatcher::Weak const &eventDispatcher,
- ContextContainer::Shared const &contextContainer)
- -> ComponentDescriptorRegistry::Shared {
- auto registry = MainComponentsRegistry::sharedProviderRegistry()
- ->createComponentDescriptorRegistry(
- {eventDispatcher, contextContainer});
-
- auto mutableRegistry =
- std::const_pointer_cast(registry);
-
- mutableRegistry->setFallbackComponentDescriptor(
- std::make_shared(
- ComponentDescriptorParameters{
- eventDispatcher, contextContainer, nullptr}));
-
- return registry;
- };
-
- delegate->buildRegistryFunction = buildRegistryFunction;
- return instance;
-}
-
-void MainComponentsRegistry::registerNatives() {
- registerHybrid({
- makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
- });
-}
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/MainComponentsRegistry.h b/example/bare/android/app/src/main/jni/MainComponentsRegistry.h
deleted file mode 100644
index b4a366335..000000000
--- a/example/bare/android/app/src/main/jni/MainComponentsRegistry.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include
-
-namespace facebook {
-namespace react {
-
-class MainComponentsRegistry
- : public facebook::jni::HybridClass {
- public:
- // Adapt it to the package you used for your Java class.
- constexpr static auto kJavaDescriptor =
- "Ldev/gorhom/bottomsheet/components/MainComponentsRegistry;";
-
- static void registerNatives();
-
- MainComponentsRegistry(ComponentFactory *delegate);
-
- private:
- static std::shared_ptr
- sharedProviderRegistry();
-
- static jni::local_ref initHybrid(
- jni::alias_ref,
- ComponentFactory *delegate);
-};
-
-} // namespace react
-} // namespace facebook
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/jni/OnLoad.cpp b/example/bare/android/app/src/main/jni/OnLoad.cpp
deleted file mode 100644
index ae1ef007d..000000000
--- a/example/bare/android/app/src/main/jni/OnLoad.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include
-#include "MainApplicationTurboModuleManagerDelegate.h"
-#include "MainComponentsRegistry.h"
-
-JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
- return facebook::jni::initialize(vm, [] {
- facebook::react::MainApplicationTurboModuleManagerDelegate::
- registerNatives();
- facebook::react::MainComponentsRegistry::registerNatives();
- });
-}
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/res/drawable/rn_edit_text_material.xml b/example/bare/android/app/src/main/res/drawable/rn_edit_text_material.xml
deleted file mode 100644
index 986188ce0..000000000
--- a/example/bare/android/app/src/main/res/drawable/rn_edit_text_material.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index 036d09bc5..000000000
--- a/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index 036d09bc5..000000000
--- a/example/bare/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 4fbbc6092..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
deleted file mode 100644
index f8f98270d..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 4fbbc6092..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index be0816689..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
deleted file mode 100644
index 8d934b5b2..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index be0816689..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 959aa628b..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 541e5f0a1..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 959aa628b..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 8edb8579e..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index acdd88baa..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index 8edb8579e..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index ef702a83b..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 4ddf1922d..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index ef702a83b..000000000
Binary files a/example/bare/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/example/bare/android/app/src/main/res/values/ic_launcher_background.xml b/example/bare/android/app/src/main/res/values/ic_launcher_background.xml
deleted file mode 100644
index beab31f75..000000000
--- a/example/bare/android/app/src/main/res/values/ic_launcher_background.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- #000000
-
\ No newline at end of file
diff --git a/example/bare/android/app/src/main/res/values/strings.xml b/example/bare/android/app/src/main/res/values/strings.xml
deleted file mode 100644
index 16508bfa2..000000000
--- a/example/bare/android/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- BottomSheet Example
-
diff --git a/example/bare/android/app/src/main/res/values/styles.xml b/example/bare/android/app/src/main/res/values/styles.xml
deleted file mode 100644
index 7ba83a2ad..000000000
--- a/example/bare/android/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
diff --git a/example/bare/android/build.gradle b/example/bare/android/build.gradle
deleted file mode 100644
index 9ab5b1350..000000000
--- a/example/bare/android/build.gradle
+++ /dev/null
@@ -1,53 +0,0 @@
-import org.apache.tools.ant.taskdefs.condition.Os
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- ext {
- buildToolsVersion = "31.0.0"
- minSdkVersion = 21
- compileSdkVersion = 31
- targetSdkVersion = 31
-
- if (System.properties['os.arch'] == "aarch64") {
- // For M1 Users we need to use the NDK 24 which added support for aarch64
- ndkVersion = "24.0.8215888"
- } else {
- // Otherwise we default to the side-by-side NDK version from AGP.
- ndkVersion = "21.4.7075529"
- }
- }
- repositories {
- google()
- mavenCentral()
- }
- dependencies {
- classpath("com.android.tools.build:gradle:7.1.1")
- classpath("com.facebook.react:react-native-gradle-plugin")
- classpath("de.undercouch:gradle-download-task:5.0.1")
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- maven {
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url("$rootDir/../node_modules/react-native/android")
- }
- maven {
- // Android JSC is installed from npm
- url("$rootDir/../node_modules/jsc-android/dist")
- }
- mavenCentral {
- // We don't want to fetch react-native from Maven Central as there are
- // older versions over there.
- content {
- excludeGroup "com.facebook.react"
- }
- }
- google()
- maven { url 'https://www.jitpack.io' }
- }
-}
diff --git a/example/bare/android/gradle.properties b/example/bare/android/gradle.properties
deleted file mode 100644
index d7712a486..000000000
--- a/example/bare/android/gradle.properties
+++ /dev/null
@@ -1,35 +0,0 @@
-# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-
-android.useAndroidX=true
-android.enableJetifier=true
-
-FLIPPER_VERSION=0.125.0
-
-# Use this property to specify which architecture you want to build.
-# You can also override it from the CLI using
-# ./gradlew -PreactNativeArchitectures=x86_64
-reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
-# Use this property to enable support to the new architecture.
-# This will allow you to use TurboModules and the Fabric render in
-# your application. You should enable this flag either if you want
-# to write custom TurboModules/Fabric components OR use libraries that
-# are providing them.
-newArchEnabled=false
\ No newline at end of file
diff --git a/example/bare/android/gradle/wrapper/gradle-wrapper.jar b/example/bare/android/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf01..000000000
Binary files a/example/bare/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/example/bare/android/gradle/wrapper/gradle-wrapper.properties b/example/bare/android/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 669386b87..000000000
--- a/example/bare/android/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/example/bare/android/gradlew b/example/bare/android/gradlew
deleted file mode 100755
index a58591e97..000000000
--- a/example/bare/android/gradlew
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
-APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD=$JAVA_HOME/jre/sh/java
- else
- JAVACMD=$JAVA_HOME/bin/java
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
\ No newline at end of file
diff --git a/example/bare/android/gradlew.bat b/example/bare/android/gradlew.bat
deleted file mode 100644
index 15e1ee37a..000000000
--- a/example/bare/android/gradlew.bat
+++ /dev/null
@@ -1,100 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/example/bare/android/settings.gradle b/example/bare/android/settings.gradle
deleted file mode 100644
index d673f13c6..000000000
--- a/example/bare/android/settings.gradle
+++ /dev/null
@@ -1,12 +0,0 @@
-rootProject.name = 'BottomSheetExample'
-apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
-include ':app'
-
-includeBuild('../node_modules/react-native-gradle-plugin')
-if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
- include(":ReactAndroid")
- project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
-
- include(":ReactAndroid:hermes-engine")
- project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
-}
diff --git a/example/bare/app.json b/example/bare/app.json
deleted file mode 100644
index d5dce6acb..000000000
--- a/example/bare/app.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "BottomSheetExample",
- "displayName": "BottomSheet Example"
-}
diff --git a/example/bare/babel.config.js b/example/bare/babel.config.js
deleted file mode 100644
index 983e075de..000000000
--- a/example/bare/babel.config.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- presets: ['module:metro-react-native-babel-preset'],
- plugins: ['react-native-reanimated/plugin'],
-};
diff --git a/example/bare/index.ts b/example/bare/index.ts
deleted file mode 100644
index fc6f4f5e8..000000000
--- a/example/bare/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import 'react-native-gesture-handler';
-
-import { enableScreens } from 'react-native-screens';
-enableScreens(true);
-
-// @ts-ignore
-import { enableLogging } from '@gorhom/bottom-sheet';
-enableLogging();
-
-import { AppRegistry, LogBox } from 'react-native';
-import App from './src/App';
-import { name as appName } from './app.json';
-
-LogBox.ignoreLogs(['react-native-maps']);
-
-AppRegistry.registerComponent(appName, () => App);
diff --git a/example/bare/ios/.xcode.env b/example/bare/ios/.xcode.env
deleted file mode 100644
index bef731e8e..000000000
--- a/example/bare/ios/.xcode.env
+++ /dev/null
@@ -1,11 +0,0 @@
-
-# This `.xcode.env` file is versioned and is used to source the environment
-# used when running script phases inside Xcode.
-# To customize your local environment, you can create an `.xcode.env.local`
-# file that is not versioned.
-# NODE_BINARY variable contains the PATH to the node executable.
-#
-# Customize the NODE_BINARY variable here.
-# For example, to use nvm with brew, add the following line
-# . "$(brew --prefix nvm)/nvm.sh" --no-use
-export NODE_BINARY=$(command -v node)
\ No newline at end of file
diff --git a/example/bare/ios/BottomSheetExample.xcodeproj/project.pbxproj b/example/bare/ios/BottomSheetExample.xcodeproj/project.pbxproj
deleted file mode 100644
index e6482e6b1..000000000
--- a/example/bare/ios/BottomSheetExample.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,499 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 54;
- objects = {
-
-/* Begin PBXBuildFile section */
- 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
- 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
- 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
- B99DDCC792BE04A3C1A46B64 /* libPods-BottomSheetExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C86C72B8E0C97C4125E76CF7 /* libPods-BottomSheetExample.a */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 13B07F961A680F5B00A75B9A /* BottomSheetExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BottomSheetExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BottomSheetExample/AppDelegate.h; sourceTree = ""; };
- 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = BottomSheetExample/AppDelegate.mm; sourceTree = ""; };
- 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = BottomSheetExample/Images.xcassets; sourceTree = ""; };
- 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BottomSheetExample/Info.plist; sourceTree = ""; };
- 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BottomSheetExample/main.m; sourceTree = ""; };
- 4993DB3E6C68D3AE31536CF5 /* Pods-BottomSheetExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BottomSheetExample.release.xcconfig"; path = "Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample.release.xcconfig"; sourceTree = ""; };
- 804B0CFA9353A107A9363C53 /* Pods-BottomSheetExample-BottomSheetExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BottomSheetExample-BottomSheetExampleTests.release.xcconfig"; path = "Target Support Files/Pods-BottomSheetExample-BottomSheetExampleTests/Pods-BottomSheetExample-BottomSheetExampleTests.release.xcconfig"; sourceTree = ""; };
- 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = BottomSheetExample/LaunchScreen.storyboard; sourceTree = ""; };
- 93BEE2BE80FA89E95F560E80 /* libPods-BottomSheetExample-BottomSheetExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BottomSheetExample-BottomSheetExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- AAADD12EFF6DFF5056590488 /* Pods-BottomSheetExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BottomSheetExample.debug.xcconfig"; path = "Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample.debug.xcconfig"; sourceTree = ""; };
- C86C72B8E0C97C4125E76CF7 /* libPods-BottomSheetExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BottomSheetExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
- F85071B73518743431AC2015 /* Pods-BottomSheetExample-BottomSheetExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BottomSheetExample-BottomSheetExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-BottomSheetExample-BottomSheetExampleTests/Pods-BottomSheetExample-BottomSheetExampleTests.debug.xcconfig"; sourceTree = ""; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- B99DDCC792BE04A3C1A46B64 /* libPods-BottomSheetExample.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 13B07FAE1A68108700A75B9A /* BottomSheetExample */ = {
- isa = PBXGroup;
- children = (
- 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
- 13B07FB01A68108700A75B9A /* AppDelegate.mm */,
- 13B07FB51A68108700A75B9A /* Images.xcassets */,
- 13B07FB61A68108700A75B9A /* Info.plist */,
- 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
- 13B07FB71A68108700A75B9A /* main.m */,
- );
- name = BottomSheetExample;
- sourceTree = "";
- };
- 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
- C86C72B8E0C97C4125E76CF7 /* libPods-BottomSheetExample.a */,
- 93BEE2BE80FA89E95F560E80 /* libPods-BottomSheetExample-BottomSheetExampleTests.a */,
- );
- name = Frameworks;
- sourceTree = "";
- };
- 7D312223C2AA7A795BB45C72 /* Pods */ = {
- isa = PBXGroup;
- children = (
- AAADD12EFF6DFF5056590488 /* Pods-BottomSheetExample.debug.xcconfig */,
- 4993DB3E6C68D3AE31536CF5 /* Pods-BottomSheetExample.release.xcconfig */,
- F85071B73518743431AC2015 /* Pods-BottomSheetExample-BottomSheetExampleTests.debug.xcconfig */,
- 804B0CFA9353A107A9363C53 /* Pods-BottomSheetExample-BottomSheetExampleTests.release.xcconfig */,
- );
- path = Pods;
- sourceTree = "";
- };
- 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
- isa = PBXGroup;
- children = (
- );
- name = Libraries;
- sourceTree = "";
- };
- 83CBB9F61A601CBA00E9B192 = {
- isa = PBXGroup;
- children = (
- 13B07FAE1A68108700A75B9A /* BottomSheetExample */,
- 832341AE1AAA6A7D00B99B32 /* Libraries */,
- 83CBBA001A601CBA00E9B192 /* Products */,
- 2D16E6871FA4F8E400B85C8A /* Frameworks */,
- 7D312223C2AA7A795BB45C72 /* Pods */,
- );
- indentWidth = 2;
- sourceTree = "";
- tabWidth = 2;
- usesTabs = 0;
- };
- 83CBBA001A601CBA00E9B192 /* Products */ = {
- isa = PBXGroup;
- children = (
- 13B07F961A680F5B00A75B9A /* BottomSheetExample.app */,
- );
- name = Products;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 13B07F861A680F5B00A75B9A /* BottomSheetExample */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "BottomSheetExample" */;
- buildPhases = (
- 88FC0B89EA592A0022EEDFF4 /* [CP] Check Pods Manifest.lock */,
- FD10A7F022414F080027D42C /* Start Packager */,
- 13B07F871A680F5B00A75B9A /* Sources */,
- 13B07F8C1A680F5B00A75B9A /* Frameworks */,
- 13B07F8E1A680F5B00A75B9A /* Resources */,
- 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
- 1E6867724AAAA56E75E4851B /* [CP] Embed Pods Frameworks */,
- AC376B9D467CEDF0C9608A3C /* [CP] Copy Pods Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = BottomSheetExample;
- productName = BottomSheetExample;
- productReference = 13B07F961A680F5B00A75B9A /* BottomSheetExample.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 83CBB9F71A601CBA00E9B192 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 1210;
- TargetAttributes = {
- 13B07F861A680F5B00A75B9A = {
- LastSwiftMigration = 1120;
- };
- };
- };
- buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "BottomSheetExample" */;
- compatibilityVersion = "Xcode 12.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 83CBB9F61A601CBA00E9B192;
- productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 13B07F861A680F5B00A75B9A /* BottomSheetExample */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 13B07F8E1A680F5B00A75B9A /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
- 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/.xcode.env.local",
- "$(SRCROOT)/.xcode.env",
- );
- name = "Bundle React Native code and images";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
- };
- 1E6867724AAAA56E75E4851B /* [CP] Embed Pods Frameworks */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
- );
- name = "[CP] Embed Pods Frameworks";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
- };
- 88FC0B89EA592A0022EEDFF4 /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-BottomSheetExample-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
- AC376B9D467CEDF0C9608A3C /* [CP] Copy Pods Resources */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-resources-${CONFIGURATION}-input-files.xcfilelist",
- );
- name = "[CP] Copy Pods Resources";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-resources-${CONFIGURATION}-output-files.xcfilelist",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BottomSheetExample/Pods-BottomSheetExample-resources.sh\"\n";
- showEnvVarsInLog = 0;
- };
- FD10A7F022414F080027D42C /* Start Packager */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- );
- name = "Start Packager";
- outputFileListPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
- showEnvVarsInLog = 0;
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 13B07F871A680F5B00A75B9A /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
- 13B07FC11A68108700A75B9A /* main.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 13B07F941A680F5B00A75B9A /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = AAADD12EFF6DFF5056590488 /* Pods-BottomSheetExample.debug.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = "";
- ENABLE_BITCODE = NO;
- INFOPLIST_FILE = BottomSheetExample/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "dev.gorhom.bottom-sheet";
- PRODUCT_NAME = BottomSheetExample;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Debug;
- };
- 13B07F951A680F5B00A75B9A /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 4993DB3E6C68D3AE31536CF5 /* Pods-BottomSheetExample.release.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = "";
- INFOPLIST_FILE = BottomSheetExample/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-ObjC",
- "-lc++",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "dev.gorhom.bottom-sheet";
- PRODUCT_NAME = BottomSheetExample;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Release;
- };
- 83CBBA201A601CBA00E9B192 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++17";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.4;
- LD_RUNPATH_SEARCH_PATHS = (
- /usr/lib/swift,
- "$(inherited)",
- );
- LIBRARY_SEARCH_PATHS = (
- "\"$(SDKROOT)/usr/lib/swift\"",
- "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
- "\"$(inherited)\"",
- );
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- OTHER_CPLUSPLUSFLAGS = (
- "$(OTHER_CFLAGS)",
- "-DFOLLY_NO_CONFIG",
- "-DFOLLY_MOBILE=1",
- "-DFOLLY_USE_LIBCPP=1",
- );
- REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
- SDKROOT = iphoneos;
- };
- name = Debug;
- };
- 83CBBA211A601CBA00E9B192 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++17";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = YES;
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.4;
- LD_RUNPATH_SEARCH_PATHS = (
- /usr/lib/swift,
- "$(inherited)",
- );
- LIBRARY_SEARCH_PATHS = (
- "\"$(SDKROOT)/usr/lib/swift\"",
- "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
- "\"$(inherited)\"",
- );
- MTL_ENABLE_DEBUG_INFO = NO;
- OTHER_CPLUSPLUSFLAGS = (
- "$(OTHER_CFLAGS)",
- "-DFOLLY_NO_CONFIG",
- "-DFOLLY_MOBILE=1",
- "-DFOLLY_USE_LIBCPP=1",
- );
- REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
- SDKROOT = iphoneos;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "BottomSheetExample" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 13B07F941A680F5B00A75B9A /* Debug */,
- 13B07F951A680F5B00A75B9A /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "BottomSheetExample" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 83CBBA201A601CBA00E9B192 /* Debug */,
- 83CBBA211A601CBA00E9B192 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
-}
diff --git a/example/bare/ios/BottomSheetExample.xcodeproj/xcshareddata/xcschemes/BottomSheetExample.xcscheme b/example/bare/ios/BottomSheetExample.xcodeproj/xcshareddata/xcschemes/BottomSheetExample.xcscheme
deleted file mode 100644
index ae963b87c..000000000
--- a/example/bare/ios/BottomSheetExample.xcodeproj/xcshareddata/xcschemes/BottomSheetExample.xcscheme
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/example/bare/ios/BottomSheetExample.xcworkspace/contents.xcworkspacedata b/example/bare/ios/BottomSheetExample.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 615c4aac0..000000000
--- a/example/bare/ios/BottomSheetExample.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
diff --git a/example/bare/ios/BottomSheetExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/bare/ios/BottomSheetExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d981003..000000000
--- a/example/bare/ios/BottomSheetExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- IDEDidComputeMac32BitWarning
-
-
-
diff --git a/example/bare/ios/BottomSheetExample/AppDelegate.h b/example/bare/ios/BottomSheetExample/AppDelegate.h
deleted file mode 100644
index ef1de86a2..000000000
--- a/example/bare/ios/BottomSheetExample/AppDelegate.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#import
-#import
-
-@interface AppDelegate : UIResponder
-
-@property (nonatomic, strong) UIWindow *window;
-
-@end
diff --git a/example/bare/ios/BottomSheetExample/AppDelegate.mm b/example/bare/ios/BottomSheetExample/AppDelegate.mm
deleted file mode 100644
index 480bc79fe..000000000
--- a/example/bare/ios/BottomSheetExample/AppDelegate.mm
+++ /dev/null
@@ -1,130 +0,0 @@
-#import "AppDelegate.h"
-
-#import
-#import
-#import
-
-#import
-
-#if RCT_NEW_ARCH_ENABLED
-#import
-#import
-#import
-#import
-#import
-#import
-
-#import
-
-static NSString *const kRNConcurrentRoot = @"concurrentRoot";
-
-@interface AppDelegate () {
- RCTTurboModuleManager *_turboModuleManager;
- RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
- std::shared_ptr _reactNativeConfig;
- facebook::react::ContextContainer::Shared _contextContainer;
-}
-@end
-#endif
-
-@implementation AppDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- RCTAppSetupPrepareApp(application);
-
- RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
-
-#if RCT_NEW_ARCH_ENABLED
- _contextContainer = std::make_shared();
- _reactNativeConfig = std::make_shared();
- _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
- _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
- bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
-#endif
-
- NSDictionary *initProps = [self prepareInitialProps];
- UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"BottomSheetExample", initProps);
-
- if (@available(iOS 13.0, *)) {
- rootView.backgroundColor = [UIColor systemBackgroundColor];
- } else {
- rootView.backgroundColor = [UIColor whiteColor];
- }
-
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- UIViewController *rootViewController = [UIViewController new];
- rootViewController.view = rootView;
- self.window.rootViewController = rootViewController;
- [self.window makeKeyAndVisible];
- return YES;
-}
-
-/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
-///
-/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
-/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
-/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
-- (BOOL)concurrentRootEnabled
-{
- // Switch this bool to turn on and off the concurrent root
- return true;
-}
-- (NSDictionary *)prepareInitialProps
-{
- NSMutableDictionary *initProps = [NSMutableDictionary new];
-#ifdef RCT_NEW_ARCH_ENABLED
- initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
-#endif
- return initProps;
-}
-
-- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
-{
-#if DEBUG
- return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
-#else
- return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
-#endif
-}
-
-#if RCT_NEW_ARCH_ENABLED
-
-#pragma mark - RCTCxxBridgeDelegate
-
-- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge
-{
- _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
- delegate:self
- jsInvoker:bridge.jsCallInvoker];
- return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
-}
-
-#pragma mark RCTTurboModuleManagerDelegate
-
-- (Class)getModuleClassFromName:(const char *)name
-{
- return RCTCoreModulesClassProvider(name);
-}
-
-- (std::shared_ptr)getTurboModule:(const std::string &)name
- jsInvoker:(std::shared_ptr)jsInvoker
-{
- return nullptr;
-}
-
-- (std::shared_ptr)getTurboModule:(const std::string &)name
- initParams:
- (const facebook::react::ObjCTurboModule::InitParams &)params
-{
- return nullptr;
-}
-
-- (id)getModuleInstanceFromClass:(Class)moduleClass
-{
- return RCTAppSetupDefaultModuleFromClass(moduleClass);
-}
-
-#endif
-
-@end
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/100.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/100.png
deleted file mode 100644
index 9d09b2964..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/100.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/1024.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/1024.png
deleted file mode 100644
index 21b184fe3..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/1024.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/114.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/114.png
deleted file mode 100644
index 5a8bc8fac..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/114.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/120.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/120.png
deleted file mode 100644
index 651271304..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/120.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/144.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/144.png
deleted file mode 100644
index 65a9bb960..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/144.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/152.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/152.png
deleted file mode 100644
index 8952528eb..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/152.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/167.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/167.png
deleted file mode 100644
index 0a775a4d8..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/167.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/180.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/180.png
deleted file mode 100644
index 50874630a..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/180.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/20.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/20.png
deleted file mode 100644
index 6b20674cc..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/20.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/29.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/29.png
deleted file mode 100644
index dcc6d0fe5..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/29.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/40.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/40.png
deleted file mode 100644
index 661fc108e..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/40.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/57.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/57.png
deleted file mode 100644
index 87252e3b4..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/57.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/58.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/58.png
deleted file mode 100644
index 3ae0843a9..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/58.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/60.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/60.png
deleted file mode 100644
index 6a6900c8c..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/60.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/72.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/72.png
deleted file mode 100644
index 665280675..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/72.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/76.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/76.png
deleted file mode 100644
index a7ce0f047..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/76.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/80.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/80.png
deleted file mode 100644
index afa17f979..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/80.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/87.png b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/87.png
deleted file mode 100644
index 3c86cd51f..000000000
Binary files a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/87.png and /dev/null differ
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/Contents.json b/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index 4fdf88263..000000000
--- a/example/bare/ios/BottomSheetExample/Images.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,158 +0,0 @@
-{
- "images" : [
- {
- "filename" : "40.png",
- "idiom" : "iphone",
- "scale" : "2x",
- "size" : "20x20"
- },
- {
- "filename" : "60.png",
- "idiom" : "iphone",
- "scale" : "3x",
- "size" : "20x20"
- },
- {
- "filename" : "29.png",
- "idiom" : "iphone",
- "scale" : "1x",
- "size" : "29x29"
- },
- {
- "filename" : "58.png",
- "idiom" : "iphone",
- "scale" : "2x",
- "size" : "29x29"
- },
- {
- "filename" : "87.png",
- "idiom" : "iphone",
- "scale" : "3x",
- "size" : "29x29"
- },
- {
- "filename" : "80.png",
- "idiom" : "iphone",
- "scale" : "2x",
- "size" : "40x40"
- },
- {
- "filename" : "120.png",
- "idiom" : "iphone",
- "scale" : "3x",
- "size" : "40x40"
- },
- {
- "filename" : "57.png",
- "idiom" : "iphone",
- "scale" : "1x",
- "size" : "57x57"
- },
- {
- "filename" : "114.png",
- "idiom" : "iphone",
- "scale" : "2x",
- "size" : "57x57"
- },
- {
- "filename" : "120.png",
- "idiom" : "iphone",
- "scale" : "2x",
- "size" : "60x60"
- },
- {
- "filename" : "180.png",
- "idiom" : "iphone",
- "scale" : "3x",
- "size" : "60x60"
- },
- {
- "filename" : "20.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "20x20"
- },
- {
- "filename" : "40.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "20x20"
- },
- {
- "filename" : "29.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "29x29"
- },
- {
- "filename" : "58.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "29x29"
- },
- {
- "filename" : "40.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "40x40"
- },
- {
- "filename" : "80.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "40x40"
- },
- {
- "filename" : "50.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "50x50"
- },
- {
- "filename" : "100.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "50x50"
- },
- {
- "filename" : "72.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "72x72"
- },
- {
- "filename" : "144.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "72x72"
- },
- {
- "filename" : "76.png",
- "idiom" : "ipad",
- "scale" : "1x",
- "size" : "76x76"
- },
- {
- "filename" : "152.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "76x76"
- },
- {
- "filename" : "167.png",
- "idiom" : "ipad",
- "scale" : "2x",
- "size" : "83.5x83.5"
- },
- {
- "filename" : "1024.png",
- "idiom" : "ios-marketing",
- "scale" : "1x",
- "size" : "1024x1024"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/example/bare/ios/BottomSheetExample/Images.xcassets/Contents.json b/example/bare/ios/BottomSheetExample/Images.xcassets/Contents.json
deleted file mode 100644
index 73c00596a..000000000
--- a/example/bare/ios/BottomSheetExample/Images.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/example/bare/ios/BottomSheetExample/Info.plist b/example/bare/ios/BottomSheetExample/Info.plist
deleted file mode 100644
index 0ed3a502d..000000000
--- a/example/bare/ios/BottomSheetExample/Info.plist
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleDisplayName
- BottomSheet Example
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 1
- LSRequiresIPhoneOS
-
- NSAppTransportSecurity
-
- NSExceptionDomains
-
- localhost
-
- NSExceptionAllowsInsecureHTTPLoads
-
-
-
-
- NSLocationWhenInUseUsageDescription
-
- UILaunchStoryboardName
- LaunchScreen
- UIRequiredDeviceCapabilities
-
- armv7
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeRight
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
-
- UIViewControllerBasedStatusBarAppearance
-
-
-
diff --git a/example/bare/ios/BottomSheetExample/LaunchScreen.storyboard b/example/bare/ios/BottomSheetExample/LaunchScreen.storyboard
deleted file mode 100644
index 8f5954a5a..000000000
--- a/example/bare/ios/BottomSheetExample/LaunchScreen.storyboard
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/example/bare/ios/BottomSheetExample/main.m b/example/bare/ios/BottomSheetExample/main.m
deleted file mode 100644
index b1df44b95..000000000
--- a/example/bare/ios/BottomSheetExample/main.m
+++ /dev/null
@@ -1,9 +0,0 @@
-#import
-
-#import "AppDelegate.h"
-
-int main(int argc, char * argv[]) {
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- }
-}
diff --git a/example/bare/ios/Podfile b/example/bare/ios/Podfile
deleted file mode 100644
index a8c20b709..000000000
--- a/example/bare/ios/Podfile
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../node_modules/react-native/scripts/react_native_pods'
-require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
-
-platform :ios, '12.4'
-install! 'cocoapods', :deterministic_uuids => false
-
-production = ENV["PRODUCTION"] == "1"
-
-target 'BottomSheetExample' do
- config = use_native_modules!
-
- # Flags change depending on the env values.
- flags = get_default_flags()
-
- use_react_native!(
- :path => config[:reactNativePath],
- # to enable hermes on iOS, change `false` to `true` and then install pods
- :production => production,
- :hermes_enabled => true,
- :fabric_enabled => flags[:fabric_enabled],
- :flipper_configuration => FlipperConfiguration.enabled,
- # An absolute path to your application root.
- :app_path => "#{Pod::Config.instance.installation_root}/.."
- )
-
- post_install do |installer|
- react_native_post_install(installer)
- __apply_Xcode_12_5_M1_post_install_workaround(installer)
- end
-end
diff --git a/example/bare/ios/Podfile.lock b/example/bare/ios/Podfile.lock
deleted file mode 100644
index 05c4758de..000000000
--- a/example/bare/ios/Podfile.lock
+++ /dev/null
@@ -1,656 +0,0 @@
-PODS:
- - boost (1.76.0)
- - CocoaAsyncSocket (7.6.5)
- - DoubleConversion (1.1.6)
- - FBLazyVector (0.69.4)
- - FBReactNativeSpec (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTRequired (= 0.69.4)
- - RCTTypeSafety (= 0.69.4)
- - React-Core (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - Flipper (0.125.0):
- - Flipper-Folly (~> 2.6)
- - Flipper-RSocket (~> 1.4)
- - Flipper-Boost-iOSX (1.76.0.1.11)
- - Flipper-DoubleConversion (3.2.0.1)
- - Flipper-Fmt (7.1.7)
- - Flipper-Folly (2.6.10):
- - Flipper-Boost-iOSX
- - Flipper-DoubleConversion
- - Flipper-Fmt (= 7.1.7)
- - Flipper-Glog
- - libevent (~> 2.1.12)
- - OpenSSL-Universal (= 1.1.1100)
- - Flipper-Glog (0.5.0.5)
- - Flipper-PeerTalk (0.0.4)
- - Flipper-RSocket (1.4.3):
- - Flipper-Folly (~> 2.6)
- - FlipperKit (0.125.0):
- - FlipperKit/Core (= 0.125.0)
- - FlipperKit/Core (0.125.0):
- - Flipper (~> 0.125.0)
- - FlipperKit/CppBridge
- - FlipperKit/FBCxxFollyDynamicConvert
- - FlipperKit/FBDefines
- - FlipperKit/FKPortForwarding
- - SocketRocket (~> 0.6.0)
- - FlipperKit/CppBridge (0.125.0):
- - Flipper (~> 0.125.0)
- - FlipperKit/FBCxxFollyDynamicConvert (0.125.0):
- - Flipper-Folly (~> 2.6)
- - FlipperKit/FBDefines (0.125.0)
- - FlipperKit/FKPortForwarding (0.125.0):
- - CocoaAsyncSocket (~> 7.6)
- - Flipper-PeerTalk (~> 0.0.4)
- - FlipperKit/FlipperKitHighlightOverlay (0.125.0)
- - FlipperKit/FlipperKitLayoutHelpers (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitHighlightOverlay
- - FlipperKit/FlipperKitLayoutTextSearchable
- - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitHighlightOverlay
- - FlipperKit/FlipperKitLayoutHelpers
- - YogaKit (~> 1.18)
- - FlipperKit/FlipperKitLayoutPlugin (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitHighlightOverlay
- - FlipperKit/FlipperKitLayoutHelpers
- - FlipperKit/FlipperKitLayoutIOSDescriptors
- - FlipperKit/FlipperKitLayoutTextSearchable
- - YogaKit (~> 1.18)
- - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0)
- - FlipperKit/FlipperKitNetworkPlugin (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitReactPlugin (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0):
- - FlipperKit/Core
- - FlipperKit/SKIOSNetworkPlugin (0.125.0):
- - FlipperKit/Core
- - FlipperKit/FlipperKitNetworkPlugin
- - fmt (6.2.1)
- - glog (0.3.5)
- - hermes-engine (0.69.4)
- - libevent (2.1.12)
- - OpenSSL-Universal (1.1.1100)
- - RCT-Folly (2021.06.28.00-v2):
- - boost
- - DoubleConversion
- - fmt (~> 6.2.1)
- - glog
- - RCT-Folly/Default (= 2021.06.28.00-v2)
- - RCT-Folly/Default (2021.06.28.00-v2):
- - boost
- - DoubleConversion
- - fmt (~> 6.2.1)
- - glog
- - RCT-Folly/Futures (2021.06.28.00-v2):
- - boost
- - DoubleConversion
- - fmt (~> 6.2.1)
- - glog
- - libevent
- - RCTRequired (0.69.4)
- - RCTTypeSafety (0.69.4):
- - FBLazyVector (= 0.69.4)
- - RCTRequired (= 0.69.4)
- - React-Core (= 0.69.4)
- - React (0.69.4):
- - React-Core (= 0.69.4)
- - React-Core/DevSupport (= 0.69.4)
- - React-Core/RCTWebSocket (= 0.69.4)
- - React-RCTActionSheet (= 0.69.4)
- - React-RCTAnimation (= 0.69.4)
- - React-RCTBlob (= 0.69.4)
- - React-RCTImage (= 0.69.4)
- - React-RCTLinking (= 0.69.4)
- - React-RCTNetwork (= 0.69.4)
- - React-RCTSettings (= 0.69.4)
- - React-RCTText (= 0.69.4)
- - React-RCTVibration (= 0.69.4)
- - React-bridging (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-jsi (= 0.69.4)
- - React-callinvoker (0.69.4)
- - React-Codegen (0.69.4):
- - FBReactNativeSpec (= 0.69.4)
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTRequired (= 0.69.4)
- - RCTTypeSafety (= 0.69.4)
- - React-Core (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-Core (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default (= 0.69.4)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/CoreModulesHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/Default (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/DevSupport (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default (= 0.69.4)
- - React-Core/RCTWebSocket (= 0.69.4)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-jsinspector (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTActionSheetHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTAnimationHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTBlobHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTImageHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTLinkingHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTNetworkHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTSettingsHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTTextHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTVibrationHeaders (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-Core/RCTWebSocket (0.69.4):
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Core/Default (= 0.69.4)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - Yoga
- - React-CoreModules (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTTypeSafety (= 0.69.4)
- - React-Codegen (= 0.69.4)
- - React-Core/CoreModulesHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-RCTImage (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-cxxreact (0.69.4):
- - boost (= 1.76.0)
- - DoubleConversion
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-callinvoker (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsinspector (= 0.69.4)
- - React-logger (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - React-runtimeexecutor (= 0.69.4)
- - React-hermes (0.69.4):
- - DoubleConversion
- - glog
- - hermes-engine
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCT-Folly/Futures (= 2021.06.28.00-v2)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-jsiexecutor (= 0.69.4)
- - React-jsinspector (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - React-jsi (0.69.4):
- - boost (= 1.76.0)
- - DoubleConversion
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-jsi/Default (= 0.69.4)
- - React-jsi/Default (0.69.4):
- - boost (= 1.76.0)
- - DoubleConversion
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-jsiexecutor (0.69.4):
- - DoubleConversion
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - React-jsinspector (0.69.4)
- - React-logger (0.69.4):
- - glog
- - react-native-blur (0.8.0):
- - React
- - react-native-maps (0.30.2):
- - React-Core
- - react-native-pager-view (5.4.24):
- - React-Core
- - react-native-safe-area-context (4.2.4):
- - RCT-Folly
- - RCTRequired
- - RCTTypeSafety
- - React
- - ReactCommon/turbomodule/core
- - React-perflogger (0.69.4)
- - React-RCTActionSheet (0.69.4):
- - React-Core/RCTActionSheetHeaders (= 0.69.4)
- - React-RCTAnimation (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTTypeSafety (= 0.69.4)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTAnimationHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTBlob (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTBlobHeaders (= 0.69.4)
- - React-Core/RCTWebSocket (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-RCTNetwork (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTImage (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTTypeSafety (= 0.69.4)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTImageHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-RCTNetwork (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTLinking (0.69.4):
- - React-Codegen (= 0.69.4)
- - React-Core/RCTLinkingHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTNetwork (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTTypeSafety (= 0.69.4)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTNetworkHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTSettings (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - RCTTypeSafety (= 0.69.4)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTSettingsHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-RCTText (0.69.4):
- - React-Core/RCTTextHeaders (= 0.69.4)
- - React-RCTVibration (0.69.4):
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-Codegen (= 0.69.4)
- - React-Core/RCTVibrationHeaders (= 0.69.4)
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (= 0.69.4)
- - React-runtimeexecutor (0.69.4):
- - React-jsi (= 0.69.4)
- - ReactCommon/turbomodule/core (0.69.4):
- - DoubleConversion
- - glog
- - RCT-Folly (= 2021.06.28.00-v2)
- - React-bridging (= 0.69.4)
- - React-callinvoker (= 0.69.4)
- - React-Core (= 0.69.4)
- - React-cxxreact (= 0.69.4)
- - React-jsi (= 0.69.4)
- - React-logger (= 0.69.4)
- - React-perflogger (= 0.69.4)
- - RNCMaskedView (0.1.11):
- - React
- - RNGestureHandler (2.5.0):
- - React-Core
- - RNReanimated (2.9.1):
- - DoubleConversion
- - FBLazyVector
- - FBReactNativeSpec
- - glog
- - RCT-Folly
- - RCTRequired
- - RCTTypeSafety
- - React-callinvoker
- - React-Core
- - React-Core/DevSupport
- - React-Core/RCTWebSocket
- - React-CoreModules
- - React-cxxreact
- - React-jsi
- - React-jsiexecutor
- - React-jsinspector
- - React-RCTActionSheet
- - React-RCTAnimation
- - React-RCTBlob
- - React-RCTImage
- - React-RCTLinking
- - React-RCTNetwork
- - React-RCTSettings
- - React-RCTText
- - ReactCommon/turbomodule/core
- - Yoga
- - RNScreens (3.15.0):
- - React-Core
- - React-RCTImage
- - SocketRocket (0.6.0)
- - Yoga (1.14.0)
- - YogaKit (1.18.1):
- - Yoga (~> 1.14)
-
-DEPENDENCIES:
- - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- - Flipper (= 0.125.0)
- - Flipper-Boost-iOSX (= 1.76.0.1.11)
- - Flipper-DoubleConversion (= 3.2.0.1)
- - Flipper-Fmt (= 7.1.7)
- - Flipper-Folly (= 2.6.10)
- - Flipper-Glog (= 0.5.0.5)
- - Flipper-PeerTalk (= 0.0.4)
- - Flipper-RSocket (= 1.4.3)
- - FlipperKit (= 0.125.0)
- - FlipperKit/Core (= 0.125.0)
- - FlipperKit/CppBridge (= 0.125.0)
- - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0)
- - FlipperKit/FBDefines (= 0.125.0)
- - FlipperKit/FKPortForwarding (= 0.125.0)
- - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0)
- - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0)
- - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0)
- - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0)
- - FlipperKit/FlipperKitReactPlugin (= 0.125.0)
- - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0)
- - FlipperKit/SKIOSNetworkPlugin (= 0.125.0)
- - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- - hermes-engine (from `../node_modules/react-native/sdks/hermes/hermes-engine.podspec`)
- - libevent (~> 2.1.12)
- - OpenSSL-Universal (= 1.1.1100)
- - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- - React (from `../node_modules/react-native/`)
- - React-bridging (from `../node_modules/react-native/ReactCommon`)
- - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- - React-Codegen (from `build/generated/ios`)
- - React-Core (from `../node_modules/react-native/`)
- - React-Core/DevSupport (from `../node_modules/react-native/`)
- - React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- - React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`)
- - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- - React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- - "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- - react-native-maps (from `../node_modules/react-native-maps`)
- - react-native-pager-view (from `../node_modules/react-native-pager-view`)
- - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- - "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- - RNReanimated (from `../node_modules/react-native-reanimated`)
- - RNScreens (from `../node_modules/react-native-screens`)
- - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
-
-SPEC REPOS:
- trunk:
- - CocoaAsyncSocket
- - Flipper
- - Flipper-Boost-iOSX
- - Flipper-DoubleConversion
- - Flipper-Fmt
- - Flipper-Folly
- - Flipper-Glog
- - Flipper-PeerTalk
- - Flipper-RSocket
- - FlipperKit
- - fmt
- - libevent
- - OpenSSL-Universal
- - SocketRocket
- - YogaKit
-
-EXTERNAL SOURCES:
- boost:
- :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
- DoubleConversion:
- :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
- FBLazyVector:
- :path: "../node_modules/react-native/Libraries/FBLazyVector"
- FBReactNativeSpec:
- :path: "../node_modules/react-native/React/FBReactNativeSpec"
- glog:
- :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
- hermes-engine:
- :podspec: "../node_modules/react-native/sdks/hermes/hermes-engine.podspec"
- RCT-Folly:
- :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
- RCTRequired:
- :path: "../node_modules/react-native/Libraries/RCTRequired"
- RCTTypeSafety:
- :path: "../node_modules/react-native/Libraries/TypeSafety"
- React:
- :path: "../node_modules/react-native/"
- React-bridging:
- :path: "../node_modules/react-native/ReactCommon"
- React-callinvoker:
- :path: "../node_modules/react-native/ReactCommon/callinvoker"
- React-Codegen:
- :path: build/generated/ios
- React-Core:
- :path: "../node_modules/react-native/"
- React-CoreModules:
- :path: "../node_modules/react-native/React/CoreModules"
- React-cxxreact:
- :path: "../node_modules/react-native/ReactCommon/cxxreact"
- React-hermes:
- :path: "../node_modules/react-native/ReactCommon/hermes"
- React-jsi:
- :path: "../node_modules/react-native/ReactCommon/jsi"
- React-jsiexecutor:
- :path: "../node_modules/react-native/ReactCommon/jsiexecutor"
- React-jsinspector:
- :path: "../node_modules/react-native/ReactCommon/jsinspector"
- React-logger:
- :path: "../node_modules/react-native/ReactCommon/logger"
- react-native-blur:
- :path: "../node_modules/@react-native-community/blur"
- react-native-maps:
- :path: "../node_modules/react-native-maps"
- react-native-pager-view:
- :path: "../node_modules/react-native-pager-view"
- react-native-safe-area-context:
- :path: "../node_modules/react-native-safe-area-context"
- React-perflogger:
- :path: "../node_modules/react-native/ReactCommon/reactperflogger"
- React-RCTActionSheet:
- :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
- React-RCTAnimation:
- :path: "../node_modules/react-native/Libraries/NativeAnimation"
- React-RCTBlob:
- :path: "../node_modules/react-native/Libraries/Blob"
- React-RCTImage:
- :path: "../node_modules/react-native/Libraries/Image"
- React-RCTLinking:
- :path: "../node_modules/react-native/Libraries/LinkingIOS"
- React-RCTNetwork:
- :path: "../node_modules/react-native/Libraries/Network"
- React-RCTSettings:
- :path: "../node_modules/react-native/Libraries/Settings"
- React-RCTText:
- :path: "../node_modules/react-native/Libraries/Text"
- React-RCTVibration:
- :path: "../node_modules/react-native/Libraries/Vibration"
- React-runtimeexecutor:
- :path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
- ReactCommon:
- :path: "../node_modules/react-native/ReactCommon"
- RNCMaskedView:
- :path: "../node_modules/@react-native-community/masked-view"
- RNGestureHandler:
- :path: "../node_modules/react-native-gesture-handler"
- RNReanimated:
- :path: "../node_modules/react-native-reanimated"
- RNScreens:
- :path: "../node_modules/react-native-screens"
- Yoga:
- :path: "../node_modules/react-native/ReactCommon/yoga"
-
-SPEC CHECKSUMS:
- boost: a7c83b31436843459a1961bfd74b96033dc77234
- CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
- DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
- FBLazyVector: c71b8c429a8af2aff1013934a7152e9d9d0c937d
- FBReactNativeSpec: cb0df4f0084281b394f76bb9b4d1d9540f35963f
- Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
- Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
- Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
- Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
- Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
- Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446
- Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
- Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
- FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
- fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
- glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
- hermes-engine: 761a544537e62df2a37189389b9d2654dc1f75af
- libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
- OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
- RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
- RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4
- RCTTypeSafety: e44e139bf6ec8042db396201834fc2372f6a21cd
- React: 482cd1ba23c471be1aed3800180be2427418d7be
- React-bridging: c2ea4fed6fe4ed27c12fd71e88b5d5d3da107fde
- React-callinvoker: d4d1f98163fb5e35545e910415ef6c04796bb188
- React-Codegen: ff35fb9c7f6ec2ed34fb6de2e1099d88dfb25f2f
- React-Core: 4d3443a45b67c71d74d7243ddde9569d1e4f4fad
- React-CoreModules: 70be25399366b5632ab18ecf6fe444a8165a7bea
- React-cxxreact: 822d3794fc0bf206f4691592f90e086dd4f92228
- React-hermes: 7f67b8363288258c3b0cd4aef5975cb7f0b9549a
- React-jsi: ffa51cbc9a78cc156cf61f79ed52ecb76dc6013b
- React-jsiexecutor: a27badbbdbc0ff781813370736a2d1c7261181d4
- React-jsinspector: 8a3d3f5dcd23a91e8c80b1bf0e96902cd1dca999
- React-logger: 1088859f145b8f6dd0d3ed051a647ef0e3e80fad
- react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
- react-native-maps: df7b9fca1b1c8d356fadbf5b8a63a5f8cf32fc73
- react-native-pager-view: 95d0418c3c74279840abec6926653d32447bafb6
- react-native-safe-area-context: f98b0b16d1546d208fc293b4661e3f81a895afd9
- React-perflogger: cb386fd44c97ec7f8199c04c12b22066b0f2e1e0
- React-RCTActionSheet: f803a85e46cf5b4066c2ac5e122447f918e9c6e5
- React-RCTAnimation: 19c80fa950ccce7f4db76a2a7f2cf79baae07fc7
- React-RCTBlob: f36ab97e2d515c36df14a1571e50056be80413d5
- React-RCTImage: 2c8f0a329a116248e82f8972ffe806e47c6d1cfa
- React-RCTLinking: 670f0223075aff33be3b89714f1da4f5343fc4af
- React-RCTNetwork: 09385b73f4ff1f46bd5d749540fb33f69a7e5908
- React-RCTSettings: 33b12d3ac7a1f2eba069ec7bd1b84345263b3bbe
- React-RCTText: a1a3ea902403bd9ae4cf6f7960551dc1d25711b5
- React-RCTVibration: 9adb4a3cbb598d1bbd46a05256f445e4b8c70603
- React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196
- ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83
- RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
- RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50
- RNReanimated: 2cf7451318bb9cc430abeec8d67693f9cf4e039c
- RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
- SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
- Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74
- YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
-
-PODFILE CHECKSUM: dbde815ade4cf26d43484f189e9bc934f65a6c92
-
-COCOAPODS: 1.11.3
diff --git a/example/bare/metro.config.js b/example/bare/metro.config.js
deleted file mode 100644
index 2c18e2602..000000000
--- a/example/bare/metro.config.js
+++ /dev/null
@@ -1,50 +0,0 @@
-const path = require('path');
-const fs = require('fs');
-const exclusionList = require('metro-config/src/defaults/exclusionList');
-const escape = require('escape-string-regexp');
-
-const root = path.resolve(__dirname, '../..');
-const rootPak = JSON.parse(
- fs.readFileSync(path.join(root, 'package.json'), 'utf8')
-);
-
-const app = path.join(__dirname, '../app');
-const appPak = JSON.parse(
- fs.readFileSync(path.join(app, 'package.json'), 'utf8')
-);
-
-const modules = [
- '@babel/runtime',
- ...Object.keys({
- ...rootPak.dependencies,
- ...rootPak.peerDependencies,
- ...appPak.devDependencies,
- ...appPak.peerDependencies,
- }),
-];
-
-module.exports = {
- projectRoot: __dirname,
- watchFolders: [root],
-
- resolver: {
- blacklistRE: exclusionList([
- new RegExp(`^${escape(path.join(root, 'node_modules'))}\\/.*$`),
- new RegExp(`^${escape(path.join(app, 'node_modules'))}\\/.*$`),
- ]),
-
- extraNodeModules: modules.reduce((acc, name) => {
- acc[name] = path.join(__dirname, 'node_modules', name);
- return acc;
- }, {}),
- },
-
- transformer: {
- getTransformOptions: async () => ({
- transform: {
- experimentalImportSupport: false,
- inlineRequires: true,
- },
- }),
- },
-};
diff --git a/example/bare/package.json b/example/bare/package.json
deleted file mode 100644
index 183945ee2..000000000
--- a/example/bare/package.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "name": "@gorhom/bottom-sheet-example",
- "description": "Example app for @gorhom/bottom-sheet",
- "version": "0.0.1",
- "private": true,
- "scripts": {
- "android": "react-native run-android",
- "ios": "react-native run-ios",
- "start": "react-native start",
- "postinstall": "npx patch-package"
- },
- "dependencies": {
- "@gorhom/portal": "^1.0.13",
- "@gorhom/showcase-template": "^2.1.0",
- "@react-native-community/blur": "^3.6.0",
- "@react-native-community/masked-view": "0.1.11",
- "@react-navigation/bottom-tabs": "^6.0.9",
- "@react-navigation/elements": "^1.2.1",
- "@react-navigation/material-top-tabs": "^6.0.6",
- "@react-navigation/native": "^6.0.6",
- "@react-navigation/native-stack": "^6.2.5",
- "@react-navigation/stack": "^6.0.11",
- "faker": "^4.1.0",
- "nanoid": "^3.3.3",
- "react": "18.0.0",
- "react-native": "0.69.4",
- "react-native-gesture-handler": "^2.5.0",
- "react-native-maps": "^0.30.1",
- "react-native-pager-view": "^5.4.9",
- "react-native-reanimated": "^2.9.1",
- "react-native-redash": "^16.0.11",
- "react-native-safe-area-context": "4.2.4",
- "react-native-screens": "^3.15.0",
- "react-native-tab-view": "^3.1.1"
- },
- "devDependencies": {
- "@babel/core": "^7.18.0",
- "@babel/runtime": "^7.18.0",
- "@types/faker": "^4.1.12",
- "@types/react": "17.0.2",
- "@types/react-native": "^0.67.7",
- "metro-react-native-babel-preset": "^0.70.3",
- "typescript": "^4.2.4"
- },
- "resolutions": {
- "@babel/core": "^7.18.0",
- "@babel/runtime": "^7.18.0",
- "@types/react": "17.0.2",
- "@types/react-native": "0.67.7"
- }
-}
diff --git a/example/bare/patches/@react-native-community+blur+3.6.0.patch b/example/bare/patches/@react-native-community+blur+3.6.0.patch
deleted file mode 100644
index 7f3e2ef17..000000000
--- a/example/bare/patches/@react-native-community+blur+3.6.0.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff --git a/node_modules/@react-native-community/blur/android/build.gradle b/node_modules/@react-native-community/blur/android/build.gradle
-index 8177235..b401cb8 100644
---- a/node_modules/@react-native-community/blur/android/build.gradle
-+++ b/node_modules/@react-native-community/blur/android/build.gradle
-@@ -43,5 +43,5 @@ repositories {
- dependencies {
- //noinspection GradleDynamicVersion
- implementation 'com.facebook.react:react-native:+'
-- implementation 'com.eightbitlab:blurview:1.6.3'
-+ implementation 'com.github.Dimezis:BlurView:version-1.6.6'
- }
diff --git a/example/bare/patches/react-native-gesture-handler+1.10.3._patch b/example/bare/patches/react-native-gesture-handler+1.10.3._patch
deleted file mode 100644
index 8919a2b73..000000000
--- a/example/bare/patches/react-native-gesture-handler+1.10.3._patch
+++ /dev/null
@@ -1,46 +0,0 @@
-diff --git a/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java b/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java
-index f08713b..14f7729 100644
---- a/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java
-+++ b/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java
-@@ -13,6 +13,8 @@ import java.util.Comparator;
-
- import androidx.annotation.Nullable;
-
-+import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper;
-+
- public class GestureHandlerOrchestrator {
-
- // The limit doesn't necessarily need to exists, it was just simpler to implement it that way
-@@ -513,6 +515,7 @@ public class GestureHandlerOrchestrator {
- }
-
- private static boolean canRunSimultaneously(GestureHandler a, GestureHandler b) {
-+
- return a == b || a.shouldRecognizeSimultaneously(b) || b.shouldRecognizeSimultaneously(a);
- }
-
-@@ -533,6 +536,11 @@ public class GestureHandlerOrchestrator {
- // state, we delegate the decision to the implementation of GestureHandler#shouldBeCancelledBy
- return handler.shouldBeCancelledBy(other);
- }
-+
-+ if (other instanceof RNGestureHandlerRootHelper.RootViewGestureHandler && handler instanceof PanGestureHandler) {
-+ return false;
-+ }
-+
- return true;
- }
-
-diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java
-index 9bf0c8f..8d4e58c 100644
---- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java
-+++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.java
-@@ -81,7 +81,7 @@ public class RNGestureHandlerRootHelper {
- return mRootView;
- }
-
-- private class RootViewGestureHandler extends GestureHandler {
-+ public class RootViewGestureHandler extends GestureHandler {
- @Override
- protected void onHandle(MotionEvent event) {
- int currentState = getState();
diff --git a/example/bare/patches/react-native-gesture-handler+2.1.0.patch b/example/bare/patches/react-native-gesture-handler+2.1.0.patch
deleted file mode 100644
index ae689c642..000000000
--- a/example/bare/patches/react-native-gesture-handler+2.1.0.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-diff --git a/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt b/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt
-index 51be37c..cb507d4 100644
---- a/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt
-+++ b/node_modules/react-native-gesture-handler/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt
-@@ -5,6 +5,7 @@ import android.graphics.PointF
- import android.view.MotionEvent
- import android.view.View
- import android.view.ViewGroup
-+import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper
- import java.util.*
-
- class GestureHandlerOrchestrator(
-@@ -546,12 +547,19 @@ class GestureHandlerOrchestrator(
- // in began state
- return false
- }
-- return if (handler !== other &&
-+
-+ if (handler !== other &&
- (handler.isAwaiting || handler.state == GestureHandler.STATE_ACTIVE)) {
- // in every other case as long as the handler is about to be activated or already in active
- // state, we delegate the decision to the implementation of GestureHandler#shouldBeCancelledBy
-- handler.shouldBeCancelledBy(other)
-- } else true
-+ return handler.shouldBeCancelledBy(other)
-+ }
-+
-+ if (other is RNGestureHandlerRootHelper.RootViewGestureHandler && handler is PanGestureHandler) {
-+ return false;
-+ }
-+
-+ return true
- }
-
- private fun isFinished(state: Int) =
-diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
-index 8c20453..dcf54dd 100644
---- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
-+++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
-@@ -53,7 +53,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
- }
- }
-
-- private inner class RootViewGestureHandler : GestureHandler() {
-+ inner class RootViewGestureHandler : GestureHandler() {
- override fun onHandle(event: MotionEvent) {
- val currentState = state
- if (currentState == STATE_UNDETERMINED) {
diff --git a/example/bare/src/App.tsx b/example/bare/src/App.tsx
deleted file mode 100644
index a4ec4c1a2..000000000
--- a/example/bare/src/App.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-import { screens } from './screens';
-import { App } from '@gorhom/bottom-sheet-example-app';
-
-export default () => ;
diff --git a/example/bare/src/Dev.tsx b/example/bare/src/Dev.tsx
deleted file mode 100644
index 6146b56e3..000000000
--- a/example/bare/src/Dev.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-import React, { useCallback, useMemo, useRef, useState } from 'react';
-import { StyleSheet, View, Button } from 'react-native';
-import { DarkTheme, NavigationContainer } from '@react-navigation/native';
-import {
- createBottomTabNavigator,
- useBottomTabBarHeight,
-} from '@react-navigation/bottom-tabs';
-import {
- // BottomSheetBackdrop,
- BottomSheetFlatList,
- BottomSheetModal,
- BottomSheetModalProvider,
-} from '@gorhom/bottom-sheet';
-import Animated, {
- useAnimatedStyle,
- useSharedValue,
-} from 'react-native-reanimated';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
-import { createContactListMockData } from './utilities';
-import { SearchHandle, ContactItem } from '@gorhom/bottom-sheet-example-app';
-
-const SNAP_POINTS = [300];
-const DATA = createContactListMockData(30);
-
-const keyExtractor = (item: any, index: number) => `${item.name}.${index}`;
-
-const App = () => {
- //#region state
- const bottomSheetRef = useRef(null);
- const [filter, setFilter] = useState('');
- //#endregion
-
- //#region hooks
- const { top: topSafeArea } = useSafeAreaInsets();
- const bottomSafeArea = useBottomTabBarHeight();
- //#endregion
-
- //#region animated values
- const data = useMemo(
- () =>
- filter === '' ? DATA : DATA.filter(item => item.name.includes(filter)),
- [filter]
- );
- const animatedPosition = useSharedValue(0);
- //#endregion
-
- //#region styles
- const positionLineAnimatedStyle = useAnimatedStyle(() => ({
- top: animatedPosition.value,
- }));
- //#endregion
-
- //#region render
- const renderItem = useCallback(
- ({ item, index }) => (
-
- ),
- []
- );
- const renderHandle = useCallback(
- props => (
-
- ),
- // eslint-disable-next-line react-hooks/exhaustive-deps
- []
- );
- return (
-
- bottomSheetRef.current?.present()}
- />
- bottomSheetRef.current?.forceClose()}
- />
- (
- //
- // )}
- handleComponent={renderHandle}
- >
-
-
-
- {SNAP_POINTS.map(snapPoint => (
-
- ))}
-
-
-
-
-
- );
- //#endregion
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- },
- line: {
- position: 'absolute',
- left: 0,
- right: 0,
- height: 1,
- backgroundColor: 'red',
- },
- flatlist: {
- flex: 1,
- },
- flatlistContainer: {
- paddingHorizontal: 24,
- },
- footer: {
- justifyContent: 'center',
- alignItems: 'center',
- marginHorizontal: 12,
- padding: 12,
- marginBottom: 12,
- borderRadius: 24,
- backgroundColor: '#80f',
- },
- footerText: {
- fontSize: 16,
- fontWeight: '600',
- color: '#fff',
- },
-});
-
-const Tab = createBottomTabNavigator();
-
-export default () => (
-
-
-
-
-
-
-
-);
diff --git a/example/bare/src/Perf.tsx b/example/bare/src/Perf.tsx
deleted file mode 100644
index 208a40b28..000000000
--- a/example/bare/src/Perf.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, {
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react';
-import { SafeAreaView, StyleSheet, Text, View } from 'react-native';
-import BottomSheet from '@gorhom/bottom-sheet';
-import { SafeAreaProvider } from 'react-native-safe-area-context';
-
-const App = () => {
- // state
- const [end, setEnd] = useState(false);
- const [mount, setMount] = useState(false);
- const [showResult, setShowResult] = useState(false);
-
- // ref
- const bottomSheetRef = useRef(null);
-
- // variables
- const snapPoints = useMemo(() => [150, 300, 450], []);
- const initialSnapPoint = useRef(0);
- const startPerfTime = useRef(0);
- const endPerfTime = useRef(0);
-
- // callbacks
- const finishPerformanceTest = useCallback(() => {
- endPerfTime.current = Date.now();
- setShowResult(true);
- }, []);
-
- const handleMountPress = useCallback(() => {
- startPerfTime.current = Date.now();
- setMount(state => !state);
- }, []);
-
- const handleAutoAnimatePress = useCallback(() => {
- // initialSnapPoint.current = -1;
- // handleMountPress();
- let index = 0;
- let loop = 1;
-
- const timer = setInterval(() => {
- if (loop === 4) {
- clearInterval(timer);
- setEnd(state => !state);
- return;
- }
-
- if (index > snapPoints.length - 1) {
- index = 0;
- loop++;
- }
-
- bottomSheetRef.current?.snapToIndex(index++);
- }, 1000);
-
- return () => {
- clearInterval(timer);
- };
- }, [snapPoints]);
-
- // effects
- useEffect(() => {
- const timeout = setTimeout(() => {
- handleMountPress();
- clearTimeout(timeout);
- }, 5000);
-
- const timeout2 = setTimeout(() => {
- handleAutoAnimatePress();
- clearTimeout(timeout2);
- }, 10000);
-
- return () => {
- clearTimeout(timeout);
- clearTimeout(timeout2);
- };
- }, [handleMountPress, handleAutoAnimatePress]);
- // render
- return end ? (
-
- ) : (
-
-
- Bottom Sheet v2 alpha-0
- Reanimated v2 alpha-6
-
- {showResult && (
-
- {endPerfTime.current - startPerfTime.current}ms
-
- )}
-
- {mount && (
-
-
-
- )}
-
-
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: '#555',
- },
- endContainer: {
- flex: 1,
- backgroundColor: 'red',
- },
- content: {
- flex: 1,
- backgroundColor: 'white',
- },
- buttonContainer: {
- marginHorizontal: 24,
- marginBottom: 6,
- },
- measure: {
- marginHorizontal: 24,
- fontSize: 64,
- fontWeight: 'bold',
- color: 'white',
- },
- version: {
- marginHorizontal: 24,
- marginTop: 12,
- color: 'white',
- fontSize: 20,
- },
-});
-
-export default App;
diff --git a/example/bare/src/components/blurredBackground/BlurredBackground.tsx b/example/bare/src/components/blurredBackground/BlurredBackground.tsx
deleted file mode 100644
index ef0ea0b57..000000000
--- a/example/bare/src/components/blurredBackground/BlurredBackground.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import React, { useMemo } from 'react';
-import { Platform, StyleSheet, View } from 'react-native';
-import { BlurView } from '@react-native-community/blur';
-import { useShowcaseTheme } from '@gorhom/showcase-template';
-
-const BlurredBackground = () => {
- const { colors } = useShowcaseTheme();
- const containerStyle = useMemo(
- () => [
- styles.container,
- {
- backgroundColor: colors.background,
- opacity: 0.95,
- },
- ],
- [colors.background]
- );
- return Platform.OS === 'ios' ? (
-
-
-
- ) : (
-
- );
-};
-
-const styles = StyleSheet.create({
- blurView: {
- ...StyleSheet.absoluteFillObject,
- },
- container: {
- ...StyleSheet.absoluteFillObject,
- borderTopLeftRadius: 10,
- borderTopRightRadius: 10,
- overflow: 'hidden',
- },
-});
-
-export default BlurredBackground;
diff --git a/example/bare/src/components/blurredBackground/index.ts b/example/bare/src/components/blurredBackground/index.ts
deleted file mode 100644
index 133f5887f..000000000
--- a/example/bare/src/components/blurredBackground/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './BlurredBackground';
diff --git a/example/bare/src/components/locationDetails/index.ts b/example/bare/src/components/locationDetails/index.ts
deleted file mode 100644
index 5f9d043b1..000000000
--- a/example/bare/src/components/locationDetails/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { LocationDetails, LOCATION_DETAILS_HEIGHT } from './LocationDetails';
diff --git a/example/bare/src/components/locationDetailsHandle/index.ts b/example/bare/src/components/locationDetailsHandle/index.ts
deleted file mode 100644
index 55e79fd2f..000000000
--- a/example/bare/src/components/locationDetailsHandle/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './LocationDetailsHandle';
diff --git a/example/bare/src/components/locationItem/index.ts b/example/bare/src/components/locationItem/index.ts
deleted file mode 100644
index a7bed37ec..000000000
--- a/example/bare/src/components/locationItem/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { LocationItem } from './LocationItem';
diff --git a/example/bare/src/components/weather/Weather.tsx b/example/bare/src/components/weather/Weather.tsx
deleted file mode 100644
index c0fe5d313..000000000
--- a/example/bare/src/components/weather/Weather.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import React, { useMemo } from 'react';
-import { Dimensions, StyleSheet } from 'react-native';
-import Animated, {
- Extrapolate,
- interpolate,
- useAnimatedStyle,
-} from 'react-native-reanimated';
-import { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
-import { SEARCH_HANDLE_HEIGHT } from '@gorhom/bottom-sheet-example-app';
-import { LOCATION_DETAILS_HEIGHT } from '../locationDetails';
-
-interface WeatherProps {
- animatedPosition: Animated.SharedValue;
- animatedIndex: Animated.SharedValue;
-}
-
-const { height: SCREEN_HEIGHT } = Dimensions.get('window');
-
-const Weather = ({ animatedIndex, animatedPosition }: WeatherProps) => {
- // hooks
- const { colors } = useShowcaseTheme();
- const { bottom: bottomSafeArea } = useSafeAreaInsets();
-
- // styles
- const lockedYPosition = useMemo(
- () =>
- SCREEN_HEIGHT -
- SEARCH_HANDLE_HEIGHT -
- LOCATION_DETAILS_HEIGHT -
- bottomSafeArea,
- [bottomSafeArea]
- );
- const containerAnimatedStyle = useAnimatedStyle(
- () => ({
- transform: [
- {
- translateY:
- animatedPosition.value > lockedYPosition
- ? animatedPosition.value - 24
- : lockedYPosition - 24,
- },
- {
- scale: interpolate(
- animatedIndex.value,
- [1, 1.25],
- [1, 0],
- Extrapolate.CLAMP
- ),
- },
- ],
- }),
- [lockedYPosition]
- );
- const containerStyle = useMemo(
- () => [
- styles.container,
- { backgroundColor: colors.secondaryCard },
- containerAnimatedStyle,
- ],
- [colors.secondaryCard, containerAnimatedStyle]
- );
- return (
-
- ☁️12°
-
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- position: 'absolute',
- right: 12,
- top: 0,
- padding: 2,
- marginTop: 0,
- borderRadius: 4,
- },
- label: {
- fontSize: 16,
- lineHeight: 16,
- },
-});
-
-export default Weather;
diff --git a/example/bare/src/components/weather/index.ts b/example/bare/src/components/weather/index.ts
deleted file mode 100644
index 2a4b8ecc3..000000000
--- a/example/bare/src/components/weather/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './Weather';
diff --git a/example/bare/src/screens/index.ts b/example/bare/src/screens/index.ts
deleted file mode 100644
index 0cd87109f..000000000
--- a/example/bare/src/screens/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { screens } from './screens';
diff --git a/example/bare/src/screens/integrations/MapExample.tsx b/example/bare/src/screens/integrations/MapExample.tsx
deleted file mode 100644
index c57ac688b..000000000
--- a/example/bare/src/screens/integrations/MapExample.tsx
+++ /dev/null
@@ -1,242 +0,0 @@
-import React, {
- useCallback,
- useLayoutEffect,
- useMemo,
- useRef,
- useState,
-} from 'react';
-import { View, StyleSheet, Dimensions } from 'react-native';
-import MapView from 'react-native-maps';
-import {
- useSharedValue,
- useAnimatedStyle,
- useDerivedValue,
-} from 'react-native-reanimated';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
-import {
- BottomSheetModal,
- BottomSheetScrollView,
- BottomSheetBackdrop,
- TouchableOpacity,
- BottomSheetBackdropProps,
-} from '@gorhom/bottom-sheet';
-import { useHeaderHeight } from '@react-navigation/elements';
-import { createLocationListMockData } from '../../utilities';
-import {
- withModalProvider,
- SearchHandle,
- SEARCH_HANDLE_HEIGHT,
-} from '@gorhom/bottom-sheet-example-app';
-import { LocationItem } from '../../components/locationItem';
-import {
- LocationDetails,
- LOCATION_DETAILS_HEIGHT,
-} from '../../components/locationDetails';
-import LocationDetailsHandle from '../../components/locationDetailsHandle';
-import Weather from '../../components/weather';
-import BlurredBackground from '../../components/blurredBackground';
-import type { Location } from '../../types';
-
-const { height: SCREEN_HEIGHT } = Dimensions.get('window');
-
-const MapExample = () => {
- const [selectedItem, setSelectedItem] = useState();
-
- // refs
- const mapRef = useRef(null);
- const poiListModalRef = useRef(null);
- const poiDetailsModalRef = useRef(null);
-
- // hooks
- const headerHeight = useHeaderHeight();
- const { bottom: bottomSafeArea } = useSafeAreaInsets();
-
- //#region variables
- const data = useMemo(() => createLocationListMockData(15), []);
- const poiListSnapPoints = useMemo(
- () => [
- bottomSafeArea + SEARCH_HANDLE_HEIGHT,
- LOCATION_DETAILS_HEIGHT + bottomSafeArea,
- '100%',
- ],
- [bottomSafeArea]
- );
- const poiDetailsSnapPoints = useMemo(
- () => [
- LOCATION_DETAILS_HEIGHT + bottomSafeArea + SEARCH_HANDLE_HEIGHT,
- '100%',
- ],
- [bottomSafeArea]
- );
- const mapInitialCamera = useMemo(
- () => ({
- center: {
- latitude: 52.3791,
- longitude: 4.9003,
- },
- heading: 0,
- pitch: 0,
- zoom: 0,
- altitude: 40000,
- }),
- []
- );
- //#endregion
-
- //#region animated variables
- const animatedPOIListIndex = useSharedValue(0);
- const animatedPOIListPosition = useSharedValue(SCREEN_HEIGHT);
- const animatedPOIDetailsIndex = useSharedValue(0);
- const animatedPOIDetailsPosition = useSharedValue(SCREEN_HEIGHT);
-
- const weatherAnimatedIndex = useDerivedValue(() =>
- animatedPOIListIndex.value > animatedPOIDetailsIndex.value
- ? animatedPOIListIndex.value
- : animatedPOIDetailsIndex.value
- );
- const weatherAnimatedPosition = useDerivedValue(() =>
- animatedPOIListPosition.value < animatedPOIDetailsPosition.value
- ? animatedPOIListPosition.value
- : animatedPOIDetailsPosition.value
- );
- //#endregion
-
- //#region callbacks
- const handleTouchStart = useCallback(() => {
- poiListModalRef.current?.collapse();
- }, []);
- const handleCloseLocationDetails = useCallback(() => {
- setSelectedItem(undefined);
- poiDetailsModalRef.current?.dismiss();
- }, []);
- const handlePresentLocationDetails = useCallback((item: Location) => {
- setSelectedItem(item);
- poiDetailsModalRef.current?.present();
- }, []);
- //#endregion
-
- //#region styles
- const scrollViewAnimatedStyle = useAnimatedStyle(() => ({
- opacity: animatedPOIListIndex.value,
- }));
- const scrollViewStyle = useMemo(
- () => [styles.scrollView, scrollViewAnimatedStyle],
- [scrollViewAnimatedStyle]
- );
- const scrollViewContentContainer = useMemo(
- () => [
- styles.scrollViewContentContainer,
- { paddingBottom: bottomSafeArea },
- ],
- [bottomSafeArea]
- );
- //#endregion
-
- //#region effects
- useLayoutEffect(() => {
- requestAnimationFrame(() => poiListModalRef.current?.present());
- }, []);
- //#endregion
-
- // renders
- const renderItem = useCallback(
- (item, index) => (
- handlePresentLocationDetails(item)}
- >
-
-
- ),
- [handlePresentLocationDetails]
- );
- const renderBackdrop = useCallback(
- (props: BottomSheetBackdropProps) => (
-
- ),
- []
- );
-
- return (
-
-
-
-
-
- {data.map(renderItem)}
-
-
-
-
-
-
-
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- padding: 24,
- },
- mapContainer: {
- ...StyleSheet.absoluteFillObject,
- },
- scrollView: {
- flex: 1,
- },
- scrollViewContentContainer: {
- paddingHorizontal: 16,
- },
-});
-
-export default withModalProvider(MapExample);
diff --git a/example/bare/src/screens/screens.ts b/example/bare/src/screens/screens.ts
deleted file mode 100644
index b07bc3ffb..000000000
--- a/example/bare/src/screens/screens.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import type { ShowcaseExampleScreenType } from '@gorhom/showcase-template';
-
-export const screens = [
- {
- title: 'Third Party Integration',
- data: [
- {
- name: 'React Navigation',
- slug: 'Integrations/NavigatorExample',
- getScreen: () => require('./integrations/NavigatorExample').default,
- },
- {
- name: 'React Native Screens',
- slug: 'Integrations/NativeScreensExample',
- getScreen: () => require('./integrations/NativeScreensExample').default,
- },
- {
- name: 'View Pager',
- slug: 'Integrations/ViewPagerExample',
- getScreen: () => require('./integrations/ViewPagerExample').default,
- },
- {
- name: 'Map',
- slug: 'Integrations/MapExample',
- getScreen: () => require('./integrations/MapExample').default,
- screenOptions: {
- headerTintColor: 'black',
- headerTransparent: true,
- },
- },
- ] as ShowcaseExampleScreenType[],
- },
-];
diff --git a/example/bare/src/types.d.ts b/example/bare/src/types.d.ts
deleted file mode 100644
index 482ad62be..000000000
--- a/example/bare/src/types.d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export type Contact = {
- name: string;
- jobTitle: string;
- address: string;
-};
-
-export type Location = {
- id: string;
- name: string;
- address: string;
- photos: string[];
-};
diff --git a/example/bare/src/utilities/createMockData.ts b/example/bare/src/utilities/createMockData.ts
deleted file mode 100644
index 96fd1d979..000000000
--- a/example/bare/src/utilities/createMockData.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import Faker from 'faker';
-import { Dimensions } from 'react-native';
-import type { Contact, Location } from '../types';
-
-const { width: SCREEN_WIDTH } = Dimensions.get('screen');
-
-export const createContactListMockData = (count: number = 20): Contact[] => {
- return new Array(count).fill(0).map(() => ({
- name: `${Faker.name.firstName()} ${Faker.name.lastName()}`,
- address: `${Faker.address.city()}, ${Faker.address.country()}`,
- jobTitle: Faker.name.jobTitle(),
- }));
-};
-
-export const createContactSectionsMockData = (count: number = 20) => {
- return new Array(Math.round(count / 4)).fill(0).map(() => ({
- title: Faker.address.country(),
- data: new Array(Math.round(count / 4)).fill(0).map(() => ({
- name: `${Faker.name.firstName()} ${Faker.name.lastName()}`,
- address: `${Faker.address.city()}, ${Faker.address.country()}`,
- jobTitle: Faker.name.jobTitle(),
- })),
- }));
-};
-
-export const createLocationListMockData = (count: number = 50): Location[] => {
- return [
- {
- id: 'ams',
- name: 'Amsterdam',
- address: 'North Holland, Netherlands',
- photos: [
- 'https://www.infocusclinical.com/wp-content/uploads/2020/02/summer-amsterdam-FP.jpg',
- 'https://images.theconversation.com/files/162459/original/image-20170325-12162-1tfrmbb.jpg?ixlib=rb-1.1.0&q=45&auto=format&w=200&fit=clip',
- 'https://www.kevinandamanda.com/wp-content/uploads/2014/09/amsterdam-2014-03.jpg',
- 'https://specials-images.forbesimg.com/imageserve/5de4a1db755ebf0006fbea42/960x0.jpg?cropX1=0&cropX2=2121&cropY1=0&cropY2=1414',
- ],
- },
- ...new Array(count).fill(0).map((_, index) => ({
- id: Faker.random.alphaNumeric(6),
- name: `${Faker.address.city()}`,
- address: `${Faker.address.state()}, ${Faker.address.country()}`,
- photos: Array(5)
- .fill(0)
- .map((__, _index) => Faker.image.city(SCREEN_WIDTH + index + _index)),
- })),
- ];
-};
diff --git a/example/bare/src/utilities/index.ts b/example/bare/src/utilities/index.ts
deleted file mode 100644
index 8b9c15b89..000000000
--- a/example/bare/src/utilities/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export {
- createContactListMockData,
- createContactSectionsMockData,
- createLocationListMockData,
-} from './createMockData';
-export { transformOrigin } from './transformOrigin';
diff --git a/example/bare/src/utilities/transformOrigin.ts b/example/bare/src/utilities/transformOrigin.ts
deleted file mode 100644
index a0d2c3811..000000000
--- a/example/bare/src/utilities/transformOrigin.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// @ts-ignore
-export const transformOrigin = ({ x, y }, ...transformations) => {
- 'worklet';
- return [
- { translateX: x },
- { translateY: y },
- ...transformations,
- { translateX: x * -1 },
- { translateY: y * -1 },
- ];
-};
diff --git a/example/bare/tsconfig.json b/example/bare/tsconfig.json
deleted file mode 100644
index 689583a0e..000000000
--- a/example/bare/tsconfig.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@gorhom/bottom-sheet": ["../../src/index"],
- "@gorhom/bottom-sheet-example-app": ["../app/src/index"]
- },
- "allowUnreachableCode": false,
- "allowUnusedLabels": false,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "jsx": "react",
- "lib": ["esnext"],
- "module": "esnext",
- "moduleResolution": "node",
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "noImplicitUseStrict": false,
- "noStrictGenericChecks": false,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "strict": true,
- "target": "esnext"
- },
- "include": ["src"]
-}
diff --git a/example/expo/.gitignore b/example/expo/.gitignore
deleted file mode 100644
index ec8a36a25..000000000
--- a/example/expo/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-node_modules/
-.expo/
-dist/
-npm-debug.*
-*.jks
-*.p8
-*.p12
-*.key
-*.mobileprovision
-*.orig.*
-web-build/
-
-# macOS
-.DS_Store
diff --git a/example/expo/app.json b/example/expo/app.json
deleted file mode 100644
index fca2a6076..000000000
--- a/example/expo/app.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "expo": {
- "name": "BottomSheetExample",
- "slug": "BottomSheetExample",
- "version": "1.0.0",
- "orientation": "portrait",
- "icon": "./assets/icon.png",
- "entryPoint": "./index.ts",
- "userInterfaceStyle": "light",
- "splash": {
- "image": "./assets/splash.png",
- "resizeMode": "contain",
- "backgroundColor": "#ffffff"
- },
- "updates": {
- "fallbackToCacheTimeout": 0
- },
- "assetBundlePatterns": ["**/*"],
- "ios": {
- "supportsTablet": true
- },
- "android": {
- "adaptiveIcon": {
- "foregroundImage": "./assets/adaptive-icon.png",
- "backgroundColor": "#FFFFFF"
- }
- },
- "web": {
- "favicon": "./assets/favicon.png"
- }
- }
-}
diff --git a/example/expo/assets/adaptive-icon.png b/example/expo/assets/adaptive-icon.png
deleted file mode 100644
index 03d6f6b6c..000000000
Binary files a/example/expo/assets/adaptive-icon.png and /dev/null differ
diff --git a/example/expo/assets/favicon.png b/example/expo/assets/favicon.png
deleted file mode 100644
index e75f697b1..000000000
Binary files a/example/expo/assets/favicon.png and /dev/null differ
diff --git a/example/expo/assets/icon.png b/example/expo/assets/icon.png
deleted file mode 100644
index a0b1526fc..000000000
Binary files a/example/expo/assets/icon.png and /dev/null differ
diff --git a/example/expo/assets/splash.png b/example/expo/assets/splash.png
deleted file mode 100644
index 0e89705a9..000000000
Binary files a/example/expo/assets/splash.png and /dev/null differ
diff --git a/example/expo/babel.config.js b/example/expo/babel.config.js
deleted file mode 100644
index 8c702fa88..000000000
--- a/example/expo/babel.config.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const path = require('path');
-const fs = require('fs');
-
-const root = path.resolve(__dirname, '../..');
-const rootPak = JSON.parse(
- fs.readFileSync(path.join(root, 'package.json'), 'utf8')
-);
-
-const app = path.join(__dirname, '../app');
-const appPak = JSON.parse(
- fs.readFileSync(path.join(app, 'package.json'), 'utf8')
-);
-
-module.exports = function (api) {
- api.cache(true);
- return {
- presets: ['babel-preset-expo'],
- plugins: [
- 'react-native-reanimated/plugin',
- [
- 'module-resolver',
- {
- extensions: ['.tsx', '.ts', '.js', '.json'],
- alias: {
- // For development, we want to alias the library to the source
- [rootPak.name]: path.join(root, rootPak['react-native']),
- [appPak.name]: path.join(app, appPak['react-native']),
- },
- },
- ],
- ],
- };
-};
diff --git a/example/expo/index.ts b/example/expo/index.ts
deleted file mode 100644
index d70a55804..000000000
--- a/example/expo/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { registerRootComponent } from 'expo';
-
-import { enableScreens } from 'react-native-screens';
-enableScreens(true);
-
-// @ts-ignore
-import { enableLogging } from '@gorhom/bottom-sheet';
-enableLogging();
-
-import App from './src/App';
-
-registerRootComponent(App);
diff --git a/example/expo/metro.config.js b/example/expo/metro.config.js
deleted file mode 100644
index 24ccdc29b..000000000
--- a/example/expo/metro.config.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const path = require('path');
-const fs = require('fs');
-const exclusionList = require('metro-config/src/defaults/exclusionList');
-const escape = require('escape-string-regexp');
-
-const root = path.resolve(__dirname, '../..');
-const rootPak = JSON.parse(
- fs.readFileSync(path.join(root, 'package.json'), 'utf8')
-);
-
-const app = path.join(__dirname, '../app');
-const appPak = JSON.parse(
- fs.readFileSync(path.join(app, 'package.json'), 'utf8')
-);
-
-const modules = [
- '@babel/runtime',
- ...Object.keys({
- ...rootPak.dependencies,
- ...rootPak.peerDependencies,
- ...appPak.devDependencies,
- ...appPak.peerDependencies,
- }),
-];
-
-module.exports = {
- projectRoot: __dirname,
- watchFolders: [root],
-
- // We need to make sure that only one version is loaded for peerDependencies
- // So we blacklist them at the root, and alias them to the versions in example's node_modules
- resolver: {
- blacklistRE: exclusionList([
- new RegExp(`^${escape(path.join(root, 'node_modules'))}\\/.*$`),
- new RegExp(`^${escape(path.join(app, 'node_modules'))}\\/.*$`),
- ]),
-
- extraNodeModules: modules.reduce((acc, name) => {
- acc[name] = path.join(__dirname, 'node_modules', name);
- return acc;
- }, {}),
- },
-
- transformer: {
- getTransformOptions: async () => ({
- transform: {
- experimentalImportSupport: false,
- inlineRequires: true,
- },
- }),
- },
-};
diff --git a/example/expo/package.json b/example/expo/package.json
deleted file mode 100644
index 521b9a090..000000000
--- a/example/expo/package.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "name": "@gorhom/bottom-sheet-example-expo",
- "description": "Example app for @gorhom/bottom-sheet",
- "version": "0.0.1",
- "private": true,
- "main": "./index.ts",
- "scripts": {
- "start": "expo start",
- "android": "expo start --android",
- "ios": "expo start --ios",
- "web": "expo start --web",
- "eject": "expo eject"
- },
- "dependencies": {
- "@gorhom/portal": "^1.0.13",
- "@gorhom/showcase-template": "^2.1.0",
- "@react-navigation/bottom-tabs": "^6.3.1",
- "@react-navigation/elements": "^1.3.3",
- "@react-navigation/material-top-tabs": "^6.2.1",
- "@react-navigation/native": "^6.0.10",
- "@react-navigation/native-stack": "^6.6.2",
- "@react-navigation/stack": "^6.2.1",
- "expo": "^46.0.0",
- "expo-status-bar": "~1.4.0",
- "faker": "^4.1.0",
- "nanoid": "^3.3.3",
- "react": "18.0.0",
- "react-dom": "18.0.0",
- "react-native": "0.69.4",
- "react-native-gesture-handler": "~2.5.0",
- "react-native-pager-view": "5.4.24",
- "react-native-reanimated": "~2.9.1",
- "react-native-redash": "^16.2.4",
- "react-native-safe-area-context": "4.3.1",
- "react-native-screens": "~3.15.0",
- "react-native-tab-view": "^3.1.1",
- "react-native-web": "~0.18.7"
- },
- "devDependencies": {
- "@babel/core": "^7.18.6",
- "@types/react": "~18.0.0",
- "@types/react-native": "~0.69.1",
- "babel-plugin-module-resolver": "^4.1.0",
- "expo-cli": "^6.0.2",
- "typescript": "^4.6.3"
- },
- "resolutions": {
- "@babel/core": "^7.18.0",
- "@babel/runtime": "^7.18.0",
- "@babel/preset-typescript": "7.17.12",
- "@types/react": "17.0.2",
- "@types/react-native": "0.67.7"
- }
-}
diff --git a/example/expo/src/App.tsx b/example/expo/src/App.tsx
deleted file mode 100644
index 3098080c5..000000000
--- a/example/expo/src/App.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-import React from 'react';
-import { App } from '@gorhom/bottom-sheet-example-app';
-
-export default () => ;
diff --git a/example/expo/tsconfig.json b/example/expo/tsconfig.json
deleted file mode 100644
index b5074aade..000000000
--- a/example/expo/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "expo/tsconfig.base",
- "compilerOptions": {
- "paths": {
- "@gorhom/bottom-sheet": ["../../src/index"],
- "@gorhom/bottom-sheet-example-app": ["../app/src/index"]
- },
- "strict": true
- }
-}
diff --git a/example/expo/webpack.config.js b/example/expo/webpack.config.js
deleted file mode 100644
index 3bbbfe4d9..000000000
--- a/example/expo/webpack.config.js
+++ /dev/null
@@ -1,32 +0,0 @@
-const path = require('path');
-const createExpoWebpackConfigAsync = require('@expo/webpack-config');
-const { resolver } = require('./metro.config');
-
-const root = path.resolve(__dirname, '../..');
-const app = path.resolve(__dirname, '../app');
-const node_modules = path.join(__dirname, 'node_modules');
-
-module.exports = async function (env, argv) {
- const config = await createExpoWebpackConfigAsync(env, argv);
-
- config.module.rules.push({
- test: /\.(js|jsx|ts|tsx)$/,
- include: path.resolve(root, 'src'),
- use: 'babel-loader',
- });
-
- config.module.rules.push({
- test: /\.(js|jsx|ts|tsx)$/,
- include: path.resolve(app, 'src'),
- use: 'babel-loader',
- });
-
- // We need to make sure that only one version is loaded for peerDependencies
- // So we alias them to the versions in example's node_modules
- Object.assign(config.resolve.alias, {
- ...resolver.extraNodeModules,
- 'react-native-web': path.join(node_modules, 'react-native-web'),
- });
-
- return config;
-};
diff --git a/example/metro.config.js b/example/metro.config.js
new file mode 100644
index 000000000..5e7e22378
--- /dev/null
+++ b/example/metro.config.js
@@ -0,0 +1,21 @@
+// Learn more https://docs.expo.io/guides/customizing-metro
+const { getDefaultConfig } = require('expo/metro-config');
+const path = require('node:path');
+const {
+ wrapWithReanimatedMetroConfig,
+} = require('react-native-reanimated/metro-config');
+
+// Find the project and workspace directories
+const projectRoot = __dirname;
+// This can be replaced with `find-yarn-workspace-root`
+const workspaceRoot = path.resolve(projectRoot, '..');
+
+/** @type {import('expo/metro-config').MetroConfig} */
+const config = getDefaultConfig(__dirname);
+
+config.watchFolders = [workspaceRoot];
+config.resolver.nodeModulesPaths = [path.resolve(projectRoot, 'node_modules')];
+
+config.resolver.disableHierarchicalLookup = true;
+
+module.exports = wrapWithReanimatedMetroConfig(config);
diff --git a/example/package.json b/example/package.json
new file mode 100644
index 000000000..5c2a955fa
--- /dev/null
+++ b/example/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "@gorhom/bottomsheet-example",
+ "version": "5.0.0",
+ "main": "node_modules/expo/AppEntry.js",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web"
+ },
+ "dependencies": {
+ "@expo/webpack-config": "~19.0.1",
+ "@gorhom/portal": "^1.0.14",
+ "@gorhom/showcase-template": "^3.0.2",
+ "@react-navigation/material-top-tabs": "^6.6.5",
+ "@react-navigation/native": "^6.1.9",
+ "@react-navigation/native-stack": "^6.9.17",
+ "@react-navigation/stack": "^6.3.20",
+ "@shopify/flash-list": "1.7.1",
+ "expo": "^52.0.7",
+ "expo-asset": "~11.0.1",
+ "expo-blur": "~14.0.1",
+ "expo-image": "~2.0.0",
+ "expo-status-bar": "~2.0.0",
+ "react": "18.3.1",
+ "react-dom": "18.3.1",
+ "react-native": "0.76.2",
+ "react-native-gesture-handler": "~2.20.2",
+ "react-native-maps": "1.18.0",
+ "react-native-pager-view": "6.4.1",
+ "react-native-reanimated": "~3.16.1",
+ "react-native-redash": "^18.1.0",
+ "react-native-safe-area-context": "4.12.0",
+ "react-native-screens": "~4.1.0",
+ "react-native-tab-view": "^3.5.2",
+ "react-native-web": "~0.19.13"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
+ "@types/faker": "^4.1.12",
+ "@types/react": "~18.3.12",
+ "@types/react-native": "^0.73.0",
+ "babel-plugin-module-resolver": "^5.0.0",
+ "faker": "^4.1.0",
+ "typescript": "^5.3.3"
+ },
+ "private": true
+}
diff --git a/example/src/Dev.tsx b/example/src/Dev.tsx
new file mode 100644
index 000000000..804684364
--- /dev/null
+++ b/example/src/Dev.tsx
@@ -0,0 +1,65 @@
+import React, { useCallback, useMemo, useRef } from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';
+import {
+ SafeAreaProvider,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context';
+
+const App = () => {
+ //#region ref
+ const bottomSheetRef = useRef(null);
+ //#endregion
+
+ //#region hooks
+ const { bottom: bottomSafeArea } = useSafeAreaInsets();
+ //#endregion
+
+ //#region callbacks
+ const handleSheetChanges = useCallback((index: number) => {
+ // eslint-disable-next-line no-console
+ console.log('handleSheetChanges', index);
+ }, []);
+ //#endregion
+
+ //#region styles
+ const contentContainerStyle = useMemo(
+ () => ({
+ ...styles.contentContainer,
+ paddingBottom: bottomSafeArea,
+ }),
+ [bottomSafeArea]
+ );
+ //#endregion
+
+ // renders
+ return (
+
+
+
+ Awesome 🎉
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ backgroundColor: 'grey',
+ },
+ contentContainer: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ minHeight: 200,
+ },
+});
+
+export default () => (
+
+
+
+);
diff --git a/example/src/Main.tsx b/example/src/Main.tsx
new file mode 100644
index 000000000..8a98d888b
--- /dev/null
+++ b/example/src/Main.tsx
@@ -0,0 +1,19 @@
+import { ShowcaseApp } from '@gorhom/showcase-template';
+import React from 'react';
+import { description, version } from '../../package.json';
+import { screens } from './screens';
+
+const author = {
+ username: 'Mo Gorhom',
+ url: 'https://gorhom.dev',
+};
+
+export default () => (
+
+);
diff --git a/example/app/src/components/button/Button.tsx b/example/src/components/button/Button.tsx
similarity index 100%
rename from example/app/src/components/button/Button.tsx
rename to example/src/components/button/Button.tsx
diff --git a/example/app/src/components/button/index.ts b/example/src/components/button/index.ts
similarity index 100%
rename from example/app/src/components/button/index.ts
rename to example/src/components/button/index.ts
diff --git a/example/app/src/components/contactItem/ContactItem.tsx b/example/src/components/contactItem/ContactItem.tsx
similarity index 100%
rename from example/app/src/components/contactItem/ContactItem.tsx
rename to example/src/components/contactItem/ContactItem.tsx
diff --git a/example/app/src/components/contactItem/index.ts b/example/src/components/contactItem/index.ts
similarity index 100%
rename from example/app/src/components/contactItem/index.ts
rename to example/src/components/contactItem/index.ts
diff --git a/example/app/src/components/contactList/ContactList.tsx b/example/src/components/contactList/ContactList.tsx
similarity index 99%
rename from example/app/src/components/contactList/ContactList.tsx
rename to example/src/components/contactList/ContactList.tsx
index cd945cd61..18707d3df 100644
--- a/example/app/src/components/contactList/ContactList.tsx
+++ b/example/src/components/contactList/ContactList.tsx
@@ -93,7 +93,7 @@ const ContactListComponent = ({
[type, onItemPress]
);
const renderSectionHeader = useCallback(
- ({ section }) => (
+ ({ section }: any) => (
{section.title}
diff --git a/example/app/src/components/contactList/index.ts b/example/src/components/contactList/index.ts
similarity index 100%
rename from example/app/src/components/contactList/index.ts
rename to example/src/components/contactList/index.ts
diff --git a/example/app/src/components/contactList/styles.ts b/example/src/components/contactList/styles.ts
similarity index 100%
rename from example/app/src/components/contactList/styles.ts
rename to example/src/components/contactList/styles.ts
diff --git a/example/app/src/components/contactList/styles.web.ts b/example/src/components/contactList/styles.web.ts
similarity index 93%
rename from example/app/src/components/contactList/styles.web.ts
rename to example/src/components/contactList/styles.web.ts
index b4f6f8ff0..44e5b1e37 100644
--- a/example/app/src/components/contactList/styles.web.ts
+++ b/example/src/components/contactList/styles.web.ts
@@ -9,10 +9,10 @@ export const styles = StyleSheet.create({
sectionHeaderTitle: {
fontSize: 16,
textTransform: 'uppercase',
+ color: 'black',
},
container: {
flex: 1,
- paddingHorizontal: 16,
},
contentContainer: {
paddingHorizontal: 16,
diff --git a/example/app/src/components/customBackground/CustomBackground.tsx b/example/src/components/customBackground/CustomBackground.tsx
similarity index 78%
rename from example/app/src/components/customBackground/CustomBackground.tsx
rename to example/src/components/customBackground/CustomBackground.tsx
index 175e0e964..57a3392f2 100644
--- a/example/app/src/components/customBackground/CustomBackground.tsx
+++ b/example/src/components/customBackground/CustomBackground.tsx
@@ -13,14 +13,17 @@ const CustomBackgroundComponent: React.FC = ({
animatedIndex,
}) => {
//#region styles
- const containerAnimatedStyle = useAnimatedStyle(() => ({
- // @ts-ignore
- backgroundColor: interpolateColor(
- animatedIndex.value,
- [0, 1],
- ['#ffffff', '#a8b5eb']
- ),
- }));
+ const containerAnimatedStyle = useAnimatedStyle(
+ () => ({
+ // @ts-ignore
+ backgroundColor: interpolateColor(
+ animatedIndex.value,
+ [0, 1],
+ ['#ffffff', '#a8b5eb']
+ ),
+ }),
+ [animatedIndex.value]
+ );
const containerStyle = useMemo(
() => [styles.container, style, containerAnimatedStyle],
[style, containerAnimatedStyle]
diff --git a/example/app/src/components/customBackground/index.ts b/example/src/components/customBackground/index.ts
similarity index 100%
rename from example/app/src/components/customBackground/index.ts
rename to example/src/components/customBackground/index.ts
diff --git a/example/app/src/components/customFooter/CustomFooter.tsx b/example/src/components/customFooter/CustomFooter.tsx
similarity index 90%
rename from example/app/src/components/customFooter/CustomFooter.tsx
rename to example/src/components/customFooter/CustomFooter.tsx
index ac9fbfa66..afa1af4a1 100644
--- a/example/app/src/components/customFooter/CustomFooter.tsx
+++ b/example/src/components/customFooter/CustomFooter.tsx
@@ -1,20 +1,19 @@
import React, { memo, useCallback, useMemo } from 'react';
-import { StyleSheet } from 'react-native';
+import { Pressable, StyleSheet } from 'react-native';
import {
BottomSheetFooter,
BottomSheetFooterProps,
useBottomSheet,
} from '@gorhom/bottom-sheet';
-import { RectButton } from 'react-native-gesture-handler';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Animated, {
- Extrapolate,
+ Extrapolation,
interpolate,
useAnimatedStyle,
} from 'react-native-reanimated';
import { toRad } from 'react-native-redash';
-const AnimatedRectButton = Animated.createAnimatedComponent(RectButton);
+const AnimatedRectButton = Animated.createAnimatedComponent(Pressable);
interface CustomFooterProps extends BottomSheetFooterProps {}
@@ -32,12 +31,12 @@ const CustomFooterComponent = ({
animatedIndex.value,
[0, 1],
[toRad(0), toRad(-180)],
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
);
return {
transform: [{ rotate: `${arrowRotate}rad` }],
};
- }, []);
+ }, [animatedIndex.value]);
const arrowStyle = useMemo(
() => [arrowAnimatedStyle, styles.arrow],
[arrowAnimatedStyle]
@@ -48,7 +47,7 @@ const CustomFooterComponent = ({
animatedIndex.value,
[-0.85, 0],
[0, 1],
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
),
}),
[animatedIndex]
diff --git a/example/app/src/components/customFooter/index.ts b/example/src/components/customFooter/index.ts
similarity index 100%
rename from example/app/src/components/customFooter/index.ts
rename to example/src/components/customFooter/index.ts
diff --git a/example/app/src/components/customHandle/CustomHandle.tsx b/example/src/components/customHandle/CustomHandle.tsx
similarity index 87%
rename from example/app/src/components/customHandle/CustomHandle.tsx
rename to example/src/components/customHandle/CustomHandle.tsx
index b5eb59bf6..5c90299f9 100644
--- a/example/app/src/components/customHandle/CustomHandle.tsx
+++ b/example/src/components/customHandle/CustomHandle.tsx
@@ -2,7 +2,7 @@ import React, { memo, useMemo } from 'react';
import { StyleProp, StyleSheet, Text, ViewStyle } from 'react-native';
import { BottomSheetHandleProps } from '@gorhom/bottom-sheet';
import Animated, {
- Extrapolate,
+ Extrapolation,
interpolate,
useAnimatedStyle,
useDerivedValue,
@@ -22,8 +22,15 @@ const CustomHandleComponent: React.FC = ({
}) => {
//#region animations
- const indicatorTransformOriginY = useDerivedValue(() =>
- interpolate(animatedIndex.value, [0, 1, 2], [-1, 0, 1], Extrapolate.CLAMP)
+ const indicatorTransformOriginY = useDerivedValue(
+ () =>
+ interpolate(
+ animatedIndex.value,
+ [0, 1, 2],
+ [-1, 0, 1],
+ Extrapolation.CLAMP
+ ),
+ [animatedIndex.value]
);
//#endregion
@@ -34,13 +41,13 @@ const CustomHandleComponent: React.FC = ({
animatedIndex.value,
[1, 2],
[20, 0],
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
);
return {
borderTopLeftRadius: borderTopRadius,
borderTopRightRadius: borderTopRadius,
};
- });
+ }, [animatedIndex.value]);
const leftIndicatorStyle = useMemo(
() => ({
...styles.indicator,
@@ -53,7 +60,7 @@ const CustomHandleComponent: React.FC = ({
animatedIndex.value,
[0, 1, 2],
[toRad(-30), 0, toRad(30)],
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
);
return {
transform: transformOrigin(
@@ -66,7 +73,7 @@ const CustomHandleComponent: React.FC = ({
}
),
};
- });
+ }, [animatedIndex.value, indicatorTransformOriginY.value]);
const rightIndicatorStyle = useMemo(
() => ({
...styles.indicator,
@@ -79,7 +86,7 @@ const CustomHandleComponent: React.FC = ({
animatedIndex.value,
[0, 1, 2],
[toRad(30), 0, toRad(-30)],
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
);
return {
transform: transformOrigin(
@@ -92,7 +99,7 @@ const CustomHandleComponent: React.FC = ({
}
),
};
- });
+ }, [animatedIndex.value, indicatorTransformOriginY.value]);
//#endregion
// render
diff --git a/example/app/src/components/customHandle/index.ts b/example/src/components/customHandle/index.ts
similarity index 100%
rename from example/app/src/components/customHandle/index.ts
rename to example/src/components/customHandle/index.ts
diff --git a/example/app/src/components/headerHandle/HeaderHandle.tsx b/example/src/components/headerHandle/HeaderHandle.tsx
similarity index 100%
rename from example/app/src/components/headerHandle/HeaderHandle.tsx
rename to example/src/components/headerHandle/HeaderHandle.tsx
diff --git a/example/app/src/components/headerHandle/index.ts b/example/src/components/headerHandle/index.ts
similarity index 100%
rename from example/app/src/components/headerHandle/index.ts
rename to example/src/components/headerHandle/index.ts
diff --git a/example/app/src/components/searchHandle/SearchHandle.tsx b/example/src/components/searchHandle/SearchHandle.tsx
similarity index 100%
rename from example/app/src/components/searchHandle/SearchHandle.tsx
rename to example/src/components/searchHandle/SearchHandle.tsx
diff --git a/example/app/src/components/searchHandle/index.ts b/example/src/components/searchHandle/index.ts
similarity index 100%
rename from example/app/src/components/searchHandle/index.ts
rename to example/src/components/searchHandle/index.ts
diff --git a/example/app/src/screens/advanced/BackdropExample.tsx b/example/src/screens/advanced/BackdropExample.tsx
similarity index 100%
rename from example/app/src/screens/advanced/BackdropExample.tsx
rename to example/src/screens/advanced/BackdropExample.tsx
diff --git a/example/app/src/screens/advanced/CustomBackgroundExample.tsx b/example/src/screens/advanced/CustomBackgroundExample.tsx
similarity index 100%
rename from example/app/src/screens/advanced/CustomBackgroundExample.tsx
rename to example/src/screens/advanced/CustomBackgroundExample.tsx
diff --git a/example/app/src/screens/advanced/CustomHandleExample.tsx b/example/src/screens/advanced/CustomHandleExample.tsx
similarity index 100%
rename from example/app/src/screens/advanced/CustomHandleExample.tsx
rename to example/src/screens/advanced/CustomHandleExample.tsx
diff --git a/example/app/src/screens/advanced/CustomThemeExample.tsx b/example/src/screens/advanced/CustomThemeExample.tsx
similarity index 100%
rename from example/app/src/screens/advanced/CustomThemeExample.tsx
rename to example/src/screens/advanced/CustomThemeExample.tsx
diff --git a/example/src/screens/advanced/DynamicSizingExample.tsx b/example/src/screens/advanced/DynamicSizingExample.tsx
new file mode 100644
index 000000000..a7c14b280
--- /dev/null
+++ b/example/src/screens/advanced/DynamicSizingExample.tsx
@@ -0,0 +1,148 @@
+import BottomSheet, {
+ BottomSheetFooter,
+ type BottomSheetFooterProps,
+ BottomSheetScrollView,
+ BottomSheetView,
+ type SNAP_POINT_TYPE,
+} from '@gorhom/bottom-sheet';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
+import { StyleSheet, View } from 'react-native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import { Button } from '../../components/button';
+import { ContactItem } from '../../components/contactItem';
+import { createContactListMockData } from '../../utilities/createMockData';
+
+const DATA = createContactListMockData(20);
+
+const DynamicSizingExample = () => {
+ //#region state
+ const [count, setCount] = useState(1);
+ const [maxHeight, setMaxHeight] = useState();
+ //#endregion
+
+ //#region variable
+ const data = useMemo(() => DATA.slice(0, count), [count]);
+ //#endregion
+
+ //#region hooks
+ const { bottom: safeBottomArea } = useSafeAreaInsets();
+ const bottomSheetRef = useRef(null);
+ //#endregion
+
+ //#region callbacks
+ const handleIncreaseContentPress = useCallback(() => {
+ setCount(state => state + 1);
+ }, []);
+ const handleDecreaseContentPress = useCallback(() => {
+ setCount(state => Math.max(state - 1, 1));
+ }, []);
+ const handleSetMaxHeight = useCallback(() => {
+ setMaxHeight(state => (state ? undefined : 500));
+ }, []);
+ const handleExpandPress = useCallback(() => {
+ bottomSheetRef.current?.expand();
+ }, []);
+ const handleClosePress = useCallback(() => {
+ bottomSheetRef.current?.close();
+ }, []);
+ const handleSheetChange = useCallback(
+ (index: number, position: number, type: SNAP_POINT_TYPE) => {
+ // biome-ignore lint/suspicious/noConsole:
+ console.log('handleSheetChange', { index, position, type });
+ },
+ []
+ );
+ //#endregion
+
+ //#region styles
+ const footerContainerStyle = useMemo(
+ () => ({
+ ...styles.footerContainer,
+ paddingBottom: safeBottomArea || 6,
+ }),
+ [safeBottomArea]
+ );
+ //#endregion
+
+ //#region renders
+ const footerComponent = useMemo(
+ () => (props: BottomSheetFooterProps) => (
+
+
+
+
+ ),
+ [
+ footerContainerStyle,
+ handleIncreaseContentPress,
+ handleDecreaseContentPress,
+ ]
+ );
+ return (
+
+
+
+
+
+
+ {data.map(item => (
+
+ ))}
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ },
+ contentContainerStyle: {
+ paddingTop: 12,
+ paddingHorizontal: 24,
+ backgroundColor: 'white',
+ },
+ message: {
+ fontSize: 24,
+ fontWeight: '600',
+ marginBottom: 12,
+ color: 'black',
+ },
+ footerContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ gap: 12,
+ paddingHorizontal: 24,
+ },
+ footerButton: {
+ flex: 1,
+ },
+});
+
+export default DynamicSizingExample;
diff --git a/example/app/src/screens/advanced/FooterExample.tsx b/example/src/screens/advanced/FooterExample.tsx
similarity index 100%
rename from example/app/src/screens/advanced/FooterExample.tsx
rename to example/src/screens/advanced/FooterExample.tsx
diff --git a/example/app/src/screens/advanced/KeyboardHandlingExample.tsx b/example/src/screens/advanced/KeyboardHandlingExample.tsx
similarity index 98%
rename from example/app/src/screens/advanced/KeyboardHandlingExample.tsx
rename to example/src/screens/advanced/KeyboardHandlingExample.tsx
index 306e55aac..8c8c94bf4 100644
--- a/example/app/src/screens/advanced/KeyboardHandlingExample.tsx
+++ b/example/src/screens/advanced/KeyboardHandlingExample.tsx
@@ -73,6 +73,7 @@ const KeyboardHandlingExample = () => {
{
// callbacks
const handleRefresh = useCallback(() => {
- // eslint-disable-next-line no-console
+ // biome-ignore lint/suspicious/noConsole: it is need for the example
console.log('handleRefresh');
}, []);
const handleExpandPress = useCallback(() => {
@@ -40,6 +40,7 @@ const PullToRefreshExample = () => {
diff --git a/example/app/src/screens/advanced/ShadowExample.tsx b/example/src/screens/advanced/ShadowExample.tsx
similarity index 82%
rename from example/app/src/screens/advanced/ShadowExample.tsx
rename to example/src/screens/advanced/ShadowExample.tsx
index 4bf497250..f791728a3 100644
--- a/example/app/src/screens/advanced/ShadowExample.tsx
+++ b/example/src/screens/advanced/ShadowExample.tsx
@@ -1,5 +1,5 @@
import React, { useCallback, useMemo, useRef } from 'react';
-import { View, StyleSheet } from 'react-native';
+import { View, StyleSheet, Platform } from 'react-native';
import BottomSheet from '@gorhom/bottom-sheet';
import { useShowcaseTheme } from '@gorhom/showcase-template';
import { Button } from '../../components/button';
@@ -18,6 +18,7 @@ const ShadowExample = () => {
const sheetStyle = useMemo(
() => ({
...styles.sheetContainer,
+ ...styles.sheetContainerShadow,
shadowColor: colors.secondaryText,
}),
[colors.secondaryText]
@@ -68,15 +69,24 @@ const styles = StyleSheet.create({
backgroundColor: 'white',
borderTopStartRadius: 24,
borderTopEndRadius: 24,
- shadowOffset: {
- width: 0,
- height: 12,
- },
- shadowOpacity: 0.75,
- shadowRadius: 16.0,
-
- elevation: 24,
},
+ sheetContainerShadow: Platform.select({
+ ios: {
+ shadowOffset: {
+ width: 0,
+ height: 12,
+ },
+ shadowOpacity: 0.75,
+ shadowRadius: 16.0,
+ shadowColor: '#000',
+ },
+ android: {
+ elevation: 24,
+ },
+ web: {
+ boxShadow: '0px -4px 16px rgba(0,0,0, 0.25)',
+ },
+ }) as any,
});
export default ShadowExample;
diff --git a/example/app/src/screens/basic/BasicExamples.tsx b/example/src/screens/basic/BasicExamples.tsx
similarity index 96%
rename from example/app/src/screens/basic/BasicExamples.tsx
rename to example/src/screens/basic/BasicExamples.tsx
index 8988e3c17..509971f0e 100644
--- a/example/app/src/screens/basic/BasicExamples.tsx
+++ b/example/src/screens/basic/BasicExamples.tsx
@@ -49,7 +49,7 @@ const createExampleScreen = ({ type, count = 25 }: ExampleScreenProps) =>
//#endregion
//#region callbacks
- const handleSheetChange = useCallback(index => {
+ const handleSheetChange = useCallback((index: number) => {
// eslint-disable-next-line no-console
console.log('handleSheetChange', index);
}, []);
@@ -60,7 +60,7 @@ const createExampleScreen = ({ type, count = 25 }: ExampleScreenProps) =>
},
[]
);
- const handleSnapPress = useCallback(index => {
+ const handleSnapPress = useCallback((index: number) => {
bottomSheetRef.current?.snapToIndex(index);
}, []);
const handleExpandPress = useCallback(() => {
@@ -104,6 +104,7 @@ const createExampleScreen = ({ type, count = 25 }: ExampleScreenProps) =>
animateOnMount={true}
enableContentPanningGesture={enableContentPanningGesture}
enableHandlePanningGesture={enableHandlePanningGesture}
+ enableDynamicSizing={false}
onChange={handleSheetChange}
onAnimate={handleSheetAnimate}
>
diff --git a/example/src/screens/index.ts b/example/src/screens/index.ts
new file mode 100644
index 000000000..49f434593
--- /dev/null
+++ b/example/src/screens/index.ts
@@ -0,0 +1,179 @@
+import type { ShowcaseExampleScreenSectionType } from '@gorhom/showcase-template';
+import { Platform } from 'react-native';
+
+const screens: ShowcaseExampleScreenSectionType[] = [];
+
+//#region Basic Section
+const basicSection = {
+ title: 'Basic',
+ collapsible: false,
+ data: [
+ {
+ name: 'View',
+ slug: 'Basic/ViewExample',
+ getScreen: () => require('./basic/BasicExamples').ViewExampleScreen,
+ },
+ {
+ name: 'ScrollView',
+ slug: 'Basic/ScrollViewExample',
+ getScreen: () => require('./basic/BasicExamples').ScrollViewExampleScreen,
+ },
+ {
+ name: 'FlatList',
+ slug: 'Basic/FlatListExample',
+ getScreen: () => require('./basic/BasicExamples').FlatListExampleScreen,
+ },
+ {
+ name: 'SectionList',
+ slug: 'Basic/SectionListExample',
+ getScreen: () =>
+ require('./basic/BasicExamples').SectionListExampleScreen,
+ },
+ {
+ name: 'VirtualizedList',
+ slug: 'Basic/VirtualizedListExample',
+ getScreen: () =>
+ require('./basic/BasicExamples').VirtualizedListExampleScreen,
+ },
+ ],
+};
+screens.push(basicSection);
+//#endregion
+
+//#region Modal Section
+const modalSection = {
+ title: 'Modal',
+ data: [
+ {
+ name: 'Simple',
+ slug: 'Modal/SimpleExample',
+ getScreen: () => require('./modal/SimpleExample').default,
+ },
+ {
+ name: 'Backdrop',
+ slug: 'Modal/BackdropExample',
+ getScreen: () => require('./modal/BackdropExample').default,
+ },
+ {
+ name: 'Stack Modals',
+ slug: 'Modal/StackExample',
+ getScreen: () => require('./modal/StackExample').default,
+ },
+ {
+ name: 'Dynamic Sizing',
+ slug: 'Modal/DynamicSizingExample',
+ getScreen: () => require('./modal/DynamicSizingExample').default,
+ },
+ {
+ name: 'Detached',
+ slug: 'Modal/DetachedExample',
+ getScreen: () => require('./modal/DetachedExample').default,
+ },
+ ],
+};
+screens.push(modalSection);
+//#endregion
+
+//#region Advanced Section
+const advancedSection = {
+ title: 'Advanced',
+ collapsed: true,
+ data: [
+ {
+ name: 'Custom Handle',
+ slug: 'Advanced/CustomHandleExample',
+ getScreen: () => require('./advanced/CustomHandleExample').default,
+ },
+ {
+ name: 'Custom Background',
+ slug: 'Advanced/CustomBackgroundExample',
+ getScreen: () => require('./advanced/CustomBackgroundExample').default,
+ },
+ {
+ name: 'Custom Theme',
+ slug: 'Advanced/CustomThemeExample',
+ getScreen: () => require('./advanced/CustomThemeExample').default,
+ },
+ {
+ name: 'Backdrop',
+ slug: 'Advanced/BackdropExample',
+ getScreen: () => require('./advanced/BackdropExample').default,
+ },
+ {
+ name: 'Dynamic Sizing',
+ slug: 'Advanced/DynamicSizingExample',
+ getScreen: () => require('./advanced/DynamicSizingExample').default,
+ },
+ {
+ name: 'Shadow',
+ slug: 'Advanced/ShadowExample',
+ getScreen: () => require('./advanced/ShadowExample').default,
+ },
+ {
+ name: 'Footer',
+ slug: 'Advanced/FooterExample',
+ getScreen: () => require('./advanced/FooterExample').default,
+ },
+ ],
+};
+if (Platform.OS !== 'web') {
+ advancedSection.data.push(
+ {
+ name: 'Keyboard Handling',
+ slug: 'Advanced/KeyboardHandlingExample',
+ getScreen: () => require('./advanced/KeyboardHandlingExample').default,
+ },
+ {
+ name: 'Pull To Refresh',
+ slug: 'Advanced/PullToRefreshExample',
+ getScreen: () => require('./advanced/PullToRefreshExample').default,
+ }
+ );
+}
+screens.push(advancedSection);
+//#endregion
+
+//#region Third Party Integration Section
+if (Platform.OS !== 'web') {
+ const integrationSection = {
+ title: 'Third Party Integration',
+ data: [
+ {
+ name: 'React Navigation',
+ slug: 'Integrations/NavigatorExample',
+ getScreen: () =>
+ require('./integrations/navigation/NavigatorExample').default,
+ },
+ {
+ name: 'React Native Screens',
+ slug: 'Integrations/NativeScreensExample',
+ getScreen: () => require('./integrations/NativeScreensExample').default,
+ },
+ {
+ name: 'View Pager',
+ slug: 'Integrations/ViewPagerExample',
+ getScreen: () => require('./integrations/ViewPagerExample').default,
+ },
+ {
+ name: 'Map',
+ slug: 'Integrations/MapExample',
+ getScreen: () => require('./integrations/map/MapExample').default,
+ screenOptions: {
+ headerTintColor: 'black',
+ headerTransparent: true,
+ },
+ },
+ {
+ name: 'FlashList',
+ slug: 'Integrations/FlashList',
+ getScreen: () => require('./integrations/flashlist').default,
+ },
+ ],
+ collapsed: true,
+ };
+ screens.push(integrationSection);
+}
+
+//#endregion
+
+export { screens };
diff --git a/example/bare/src/screens/integrations/NativeScreensExample.tsx b/example/src/screens/integrations/NativeScreensExample.tsx
similarity index 85%
rename from example/bare/src/screens/integrations/NativeScreensExample.tsx
rename to example/src/screens/integrations/NativeScreensExample.tsx
index 55fda20bb..ffd9d41c2 100644
--- a/example/bare/src/screens/integrations/NativeScreensExample.tsx
+++ b/example/src/screens/integrations/NativeScreensExample.tsx
@@ -2,11 +2,9 @@ import React from 'react';
import { View, StyleSheet, Platform } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import {
- ModalBackdropExample,
- Button,
- withModalProvider,
-} from '@gorhom/bottom-sheet-example-app';
+import { Button } from '../../components/button';
+import ModalBackdropExample from '../modal/BackdropExample';
+import { withModalProvider } from '../modal/withModalProvider';
const RootScreen = () => {
const { navigate } = useNavigation();
diff --git a/example/bare/src/screens/integrations/ViewPagerExample.tsx b/example/src/screens/integrations/ViewPagerExample.tsx
similarity index 93%
rename from example/bare/src/screens/integrations/ViewPagerExample.tsx
rename to example/src/screens/integrations/ViewPagerExample.tsx
index 66a823e60..fd618f2d9 100644
--- a/example/bare/src/screens/integrations/ViewPagerExample.tsx
+++ b/example/src/screens/integrations/ViewPagerExample.tsx
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import BottomSheet from '@gorhom/bottom-sheet';
-import { ContactList } from '@gorhom/bottom-sheet-example-app';
+import { ContactList } from '../../components/contactList';
const FirstRoute = () => {
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
@@ -11,6 +11,7 @@ const FirstRoute = () => {
{
+ return item.id;
+};
+
+const snapPoints = ['25%', '50%', '90%'];
+
+const FlashListExample = () => {
+ //#region state
+ const [tweets, setTweets] = useState(tweetsData);
+ //#endregion
+
+ //#region refs
+ const bottomSheetRef = useRef(null);
+ const remainingTweets = useRef([...tweetsData].splice(10, tweetsData.length));
+ const viewabilityConfig = useRef({
+ waitForInteraction: true,
+ itemVisiblePercentThreshold: 50,
+ minimumViewTime: 1000,
+ }).current;
+ //#endregion
+
+ const handleOnEndReached = useCallback(() => {
+ setTimeout(() => {
+ setTweets([...tweets, ...remainingTweets.current.splice(0, 10)]);
+ }, 1000);
+ }, [tweets]);
+ const handleSnapPress = useCallback((index: number) => {
+ bottomSheetRef.current?.snapToIndex(index);
+ }, []);
+ const handleExpandPress = useCallback(() => {
+ bottomSheetRef.current?.expand();
+ }, []);
+ const handleCollapsePress = useCallback(() => {
+ bottomSheetRef.current?.collapse();
+ }, []);
+ const handleClosePress = useCallback(() => {
+ bottomSheetRef.current?.close();
+ }, []);
+
+ //#region render
+ const renderItem = useCallback(
+ ({ item }: ListRenderItemInfo) => ,
+ []
+ );
+ const renderFooter = useMemo(
+ () => ,
+ [tweets]
+ );
+ return (
+
+ handleSnapPress(2)} />
+ handleSnapPress(1)} />
+ handleSnapPress(0)} />
+
+
+
+
+
+
+
+ );
+ //#endregion
+};
+
+const Divider = () => {
+ return ;
+};
+
+const Footer = ({ isLoading }: { isLoading: boolean }) => {
+ return (
+
+ {isLoading ? (
+
+ ) : (
+ No more tweets
+ )}
+
+ );
+};
+
+const Empty = () => {
+ const title = 'Welcome to your timeline';
+ const subTitle =
+ "It's empty now but it won't be for long. Start following peopled you'll see Tweets show up here";
+ return (
+
+ {title}
+ {subTitle}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ },
+
+ divider: {
+ width: '100%',
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: '#DDD',
+ },
+ header: {
+ height: 40,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#1DA1F2',
+ },
+ footer: {
+ height: 40,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ headerTitle: {
+ color: '#FFFFFF',
+ padding: 8,
+ borderRadius: 12,
+ fontSize: 12,
+ },
+ footerTitle: {
+ padding: 8,
+ borderRadius: 12,
+ fontSize: 12,
+ },
+ emptyComponentTitle: {
+ color: 'black',
+ fontSize: 20,
+ fontWeight: 'bold',
+ },
+ emptyComponentSubtitle: {
+ color: '#808080',
+ padding: 8,
+ fontSize: 14,
+ textAlign: 'center',
+ },
+ emptyComponent: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ flex: 1,
+ },
+});
+
+export default FlashListExample;
diff --git a/example/src/screens/integrations/flashlist/TweetContent.tsx b/example/src/screens/integrations/flashlist/TweetContent.tsx
new file mode 100644
index 000000000..53bde33e5
--- /dev/null
+++ b/example/src/screens/integrations/flashlist/TweetContent.tsx
@@ -0,0 +1,181 @@
+import { Image } from 'expo-image';
+import React from 'react';
+
+import { StyleSheet, Text, View, type ViewStyle } from 'react-native';
+
+import type Author from './models/Author';
+import type Tweet from './models/Tweet';
+
+export interface TweetContentProps {
+ tweet: Tweet;
+}
+
+const tweetActions = (
+ retweets: React.ReactNode,
+ comments: React.ReactNode,
+ likes: React.ReactNode
+) => {
+ return (
+
+
+
+ {comments}
+
+
+
+ {retweets}
+
+
+
+ {likes}
+
+
+
+ );
+};
+
+const avatar = (author: Author) => {
+ return (
+
+
+ {author.name.toUpperCase().charAt(0)}
+
+
+ );
+};
+interface GrayTextProps {
+ children: React.ReactNode;
+ numberOfLines?: number;
+ style?: ViewStyle;
+}
+
+const GrayText = ({ children, numberOfLines, style }: GrayTextProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const TweetContent = ({ tweet }: TweetContentProps) => {
+ return (
+
+
+ {avatar(tweet.author)}
+
+
+
+ {tweet.author.name}
+
+
+ @{tweet.author.screenName}
+
+ ·
+ 2h
+
+ {tweet.fullText}
+
+ {tweetActions(
+ tweet.retweetCount,
+ tweet.replyCount,
+ tweet.favoriteCount
+ )}
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ author: {
+ flexShrink: 1,
+ },
+ actionBar: {
+ marginTop: 8,
+ justifyContent: 'space-between',
+ marginRight: 16,
+ },
+ actionButton: {
+ width: 18,
+ height: 18,
+ marginRight: 8,
+ backgroundColor: 'red',
+ },
+ gray: {
+ color: '#777',
+ fontSize: 13,
+ paddingRight: 2,
+ },
+ avatar: {
+ height: 44,
+ width: 44,
+ backgroundColor: '#00A4EF',
+ marginRight: 16,
+ flexShrink: 0,
+ marginTop: 4,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ avatarTextStyle: {
+ color: '#FFF',
+ fontSize: 18,
+ fontWeight: 'bold',
+ },
+ header: {
+ fontSize: 14,
+ fontWeight: 'bold',
+ paddingBottom: 4,
+ paddingRight: 4,
+ color: '#000',
+ },
+ description: {
+ fontSize: 14,
+ color: '#000',
+ },
+ singleItem: {
+ paddingHorizontal: 16,
+ minHeight: 44,
+ flex: 1,
+ padding: 16,
+ backgroundColor: '#FFF',
+ },
+ rowTop: {
+ flexDirection: 'row',
+ },
+ rowActions: {
+ flexGrow: 1,
+ justifyContent: 'space-between',
+ flexDirection: 'row',
+ },
+ row: {
+ flexDirection: 'row',
+ },
+ elemAction: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'flex-start',
+ },
+ actionText: {
+ fontSize: 12,
+ color: '#444',
+ },
+ tweetContentContainer: {
+ flexShrink: 1,
+ flexGrow: 1,
+ },
+});
+
+export default TweetContent;
diff --git a/example/src/screens/integrations/flashlist/data/tweets.ts b/example/src/screens/integrations/flashlist/data/tweets.ts
new file mode 100644
index 000000000..ac61c84fa
--- /dev/null
+++ b/example/src/screens/integrations/flashlist/data/tweets.ts
@@ -0,0 +1,2021 @@
+/* eslint-disable max-len */
+
+import type Tweet from '../models/Tweet';
+
+export const tweets: Tweet[] = [
+ {
+ author: {
+ name: 'Aram Miquel',
+ screenName: 'aram_miquel',
+ avatar:
+ 'https://images.unsplash.com/photo-1649011463206-cb765493f8bf?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480837336535646209',
+ fullText:
+ 'Apple should pay more attention. It’s unfair to users, but even more to the small developers that play by the rules!',
+ retweetCount: 2,
+ replyCount: 1,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480833114096214018',
+ fullText:
+ 'I write about real-world hiring insights for paid subscribers of https://t.co/SLe64y6YsX - many of whom are hiring managers themselves.\n\nIt might be a hard pill to swallow, but retaining existing folks, not overloading them with too many in-person interviews comes before hiring.',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'ryancarson.eth',
+ screenName: 'ryancarson',
+ avatar:
+ 'https://images.unsplash.com/photo-1650355255329-66a873ebab57?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480806838140649472',
+ fullText:
+ 'Not bullish on @LooksRareNFT and $LOOKS yet? (Disclosure: I staked my airdropped tokens. DYOR as always.)',
+ retweetCount: 2,
+ replyCount: 2,
+ favoriteCount: 13,
+ },
+ {
+ author: {
+ name: 'Cris Miquel',
+ screenName: 'crismiquelg',
+ avatar:
+ 'https://images.unsplash.com/photo-1650192905858-e0bc957bf390?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480543522465976324',
+ fullText:
+ 'mi único propósito para 2022 es dejar de despedirme con la mano en las videollamadas como si fuera idiota',
+ retweetCount: 2,
+ replyCount: 14,
+ favoriteCount: 64,
+ },
+ {
+ author: {
+ name: 'Lorenzo',
+ screenName: 'Kelset',
+ avatar:
+ 'https://images.unsplash.com/photo-1650346910129-e73df7b26eb0?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480879826781286413',
+ fullText: '🔥this is fine🔥',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Vitto Rivabella 🥑',
+ screenName: 'VittoStack',
+ avatar:
+ 'https://images.unsplash.com/photo-1649623053337-03a9aca84fc1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480576201878028289',
+ fullText:
+ 'DAOs are the best place to become a Web3 developer.\n\nUnfortunately, only a bunch are really valuable.\n\n4 best DAOs to learn Web3 ↓',
+ retweetCount: 158,
+ replyCount: 20,
+ favoriteCount: 551,
+ },
+ {
+ author: {
+ name: 'Justin Moore | Sponsorship Coach',
+ screenName: 'justinmooretfam',
+ avatar:
+ 'https://images.unsplash.com/photo-1650213986462-1804543441c2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480875135355666432',
+ fullText: 'Stop waiting for brands to contact you.',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 11,
+ },
+ {
+ author: {
+ name: 'March',
+ screenName: 'fdesbml',
+ avatar:
+ 'https://images.unsplash.com/photo-1650975109944-2772703c72f7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480362830805311495',
+ fullText:
+ 'Hand-knit jewelry by Nora Folk | She uses a mixed technique of weaving, knitting, braiding and knotting fine nylon microfilaments to create organic shapes. https://t.co/BZFBQwuHeO',
+ retweetCount: 901,
+ replyCount: 10,
+ favoriteCount: 5889,
+ },
+ {
+ author: {
+ name: 'Samuel Molina',
+ screenName: 'FuKuy',
+ avatar:
+ 'https://images.unsplash.com/photo-1651264042772-23891c614270?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480818112614260739',
+ fullText:
+ 'RT @Sadface_RL: A beginners guide to health bars.\n\n#pixelart #art #animation #gamedev #indiedev #indiegamedev #indiegame https://t.co/Fhb4m…',
+ retweetCount: 177,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Fumio 💡',
+ screenName: 'IK1T',
+ avatar:
+ 'https://images.unsplash.com/photo-1650548211932-f6ebd1c73867?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480811969242357760',
+ fullText:
+ "Happy #PortfolioDay !\nDear friends ❤️ I'm Fumio, a Lighting Artist 💡 currently working on Star Citizen.\nLooking forward to meeting awesome artists on twitter 😊🎨✨\n\n🖼️ https://t.co/HOEB3v9c6E\n\n#PortfolioDay #LightingArtist #gamedev #Lighting https://t.co/ROIZ4iqRkE",
+ retweetCount: 19,
+ replyCount: 1,
+ favoriteCount: 70,
+ },
+ {
+ author: {
+ name: 'ryancarson.eth',
+ screenName: 'ryancarson',
+ avatar:
+ 'https://images.unsplash.com/photo-1650355255329-66a873ebab57?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480809821754511361',
+ fullText: 'gm y’all!',
+ retweetCount: 0,
+ replyCount: 11,
+ favoriteCount: 19,
+ },
+ {
+ author: {
+ name: 'SonyAlphaRumors',
+ screenName: 'SonyAlphaRumors',
+ avatar:
+ 'https://images.unsplash.com/photo-1650170495855-add188d60239?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480859756940218370',
+ fullText:
+ 'ZY Productions: This $429 Viltrox FE 24mm F1.8 Lens Is Surprisingly Good https://t.co/pAPvDYI5t4',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Sommer Panage',
+ screenName: 'Sommer',
+ avatar:
+ 'https://images.unsplash.com/photo-1651236243448-ff4ea397cdf5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480713374350651394',
+ fullText:
+ 'I love working with people who are friendly. Who say “thank you” or cheer you on or say “good job.” These things may seem small, but they add up in the same way (but opposite direction) that all the negs and “paper cuts” do. They create a culture. They matter. Kindness matters.',
+ retweetCount: 94,
+ replyCount: 11,
+ favoriteCount: 744,
+ },
+ {
+ author: {
+ name: '@levelsio',
+ screenName: 'levelsio',
+ avatar:
+ 'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480883313787084801',
+ fullText:
+ '✨ Added a mailto: link so people can invite their friends too https://t.co/fR3ufZJeuP',
+ retweetCount: 0,
+ replyCount: 3,
+ favoriteCount: 18,
+ },
+ {
+ author: {
+ name: 'The muy ameisin Bonilista',
+ screenName: 'bonilista',
+ avatar:
+ 'https://images.unsplash.com/photo-1650296231490-2deba34258bf?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480843314349981698',
+ fullText:
+ 'El patrocinio de la #Bonilista cuesta 0,036 centimos por cada persona que lee el correo. Eso, sin contar la republicación en @lavozdegalicia.\nSi te interesa reservar un patrocinio, tienes fechas disponibles a partir del 1 de mayo y más info en \nhttps://t.co/umLWuCrVnY',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'John Arthorne',
+ screenName: 'jarthorne',
+ avatar:
+ 'https://images.unsplash.com/photo-1651417060303-716ae896ef88?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480546473590857729',
+ fullText:
+ 'The number of people joining Shopify RnD *today* alone is greater than the size of the RnD team when I joined 6 years ago 🤯. To my ~300 new colleagues: Welcome! 🚀',
+ retweetCount: 14,
+ replyCount: 6,
+ favoriteCount: 234,
+ },
+ {
+ author: {
+ name: 'Paul Graham',
+ screenName: 'paulg',
+ avatar:
+ 'https://images.unsplash.com/photo-1649089475942-b523f9d00219?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480875433013002243',
+ fullText:
+ '"In truth, Theodoric was something of a parvenu, as every other Goth must have been aware."\n\n— J. M. Wallace-Hadrill',
+ retweetCount: 1,
+ replyCount: 2,
+ favoriteCount: 22,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480813715880615936',
+ fullText:
+ 'Ok I got hooked on Wordle as well.\n\nWordle 206 3/6\n\n⬜🟨🟩⬜⬜\n🟩⬜🟩🟩⬜\n🟩🟩🟩🟩🟩',
+ retweetCount: 0,
+ replyCount: 6,
+ favoriteCount: 31,
+ },
+ {
+ author: {
+ name: 'Toni Colom',
+ screenName: 'tonicolom',
+ avatar:
+ 'https://images.unsplash.com/photo-1649861972512-faadc16a4571?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480824991486824448',
+ fullText:
+ 'Para cumplir todas las tradiciones de estas fechas sólo me faltaba una cosa: la revisión de 2021 y los objetivos de 2022.\n\nEn este episodio con @chusnarrolo, que viene de un año movidito, hablamos del presente y del futuro de nuestras #marcas.\n\n#Podcast\nhttps://t.co/7YA6KrPrwX',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Amanda Emmanuel',
+ screenName: 'amandaemmanuel',
+ avatar:
+ 'https://images.unsplash.com/photo-1649894158708-bd47ad9ef4e3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Ng&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480611397503492100',
+ fullText:
+ "Last year I had an idea but I couldn't find a technical co-founder to build it, so I became one\n\nIn 12-weeks:\n\nI taught myself Rails \nbuilt the MVP\non-boarded 10 customers\nadded customer requested features\nhit 165K MAUs\n\nNever underestimate yourself 🚀",
+ retweetCount: 240,
+ replyCount: 175,
+ favoriteCount: 4385,
+ },
+ {
+ author: {
+ name: 'Majid Jabrayilov',
+ screenName: 'mecid',
+ avatar:
+ 'https://images.unsplash.com/photo-1649080480680-221b69e21ce1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480876283382935552',
+ fullText:
+ 'Pull-to-refresh is a widespread User Interface pattern that we use to request a data update in our apps. The SwiftUI Release 3 provides a brand new way to set up a pull-to-refresh action using the new refreshable view modifier.\nhttps://t.co/bqU9Qaak1K https://t.co/wwNHOAhYtY',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 19,
+ },
+ {
+ author: {
+ name: 'Icon Galleries',
+ screenName: 'icongalleries',
+ avatar:
+ 'https://images.unsplash.com/photo-1649733484875-2e837f5b640b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480669856647233543',
+ fullText:
+ 'Lots of new #macOS icons today, including work from @raphaellopesph \n\nCheck out the icons at https://t.co/puMlrIlC6N',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 4,
+ },
+ {
+ author: {
+ name: 'Capture One Pro',
+ screenName: 'captureonepro',
+ avatar:
+ 'https://images.unsplash.com/photo-1649393153970-fd7ec111a577?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480841955613581313',
+ fullText:
+ 'Want to know what @dunnadidit thinks about Capture One 22?\n\nWatch the video in the link below, where he tries out our new HDR and Panorama features.\n\n#hdr #panorama #captureone #editingsoftware\n\nhttps://t.co/7FxEC2LBwo https://t.co/sxvi6UQC8o',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 7,
+ },
+ {
+ author: {
+ name: 'Colin Cornaby',
+ screenName: 'colincornaby',
+ avatar:
+ 'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480321521126019073',
+ fullText:
+ 'Anyone seen inconsistent Metal performance numbers on Apple Silicon Macs? Xcode FPS counter shows a GPU time of about 9 ms. But the built in shader profiler shows a time less than 3 ms. My best guess is maybe there is a significant of time being spent not in shaders?',
+ retweetCount: 0,
+ replyCount: 2,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Smashing Magazine',
+ screenName: 'smashingmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480816866360766465',
+ fullText:
+ 'RT @smashingmag: 📣 New Smashing Workshops in 2022:\n \n😎 Accessible Front-End Patterns — @cariefisher\n👾 Front-End Testing — @bahmutov\n👻 HTML…',
+ retweetCount: 15,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Young IT Girls',
+ screenName: 'youngitgirls',
+ avatar:
+ 'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480856688060256258',
+ fullText:
+ "🚀 Arranquem l'any amb noves aventures i moltes ganes de continuar treballant \n\n@CanodromBCN",
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480832043093221379',
+ fullText:
+ 'I refrain from talking much about the "real world" of hiring on Twitter, because the majority of people have not been on the other side.\n\nIt\'s easy to gather likes by tweeting "hire more juniors" when it\'s not you who will be responsible for the success - or failure - of them.',
+ retweetCount: 0,
+ replyCount: 3,
+ favoriteCount: 37,
+ },
+ {
+ author: {
+ name: 'I Am Devloper',
+ screenName: 'iamdevloper',
+ avatar:
+ 'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480861741185650691',
+ fullText:
+ "you don't need to spend 3hrs automating a solution to save you 10 minutes of manual input",
+ retweetCount: 20,
+ replyCount: 40,
+ favoriteCount: 339,
+ },
+ {
+ author: {
+ name: 'Connor Shorten',
+ screenName: 'CShorten30',
+ avatar:
+ 'https://images.unsplash.com/photo-1649711992982-092a8e53e39c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1466746804704354309',
+ fullText:
+ "This video explains Weaviate's Wikidata Vector Search Web Demo! 🔥💻🔥\n\nThis covers a range of topics from:\n• Wikidata versus Wikipedia\n• PyTorch-BigGraph\n• The Weaviate Demo and Vector Search Visualization\n• My thoughts on Graph Data in Deep Learning\n\nhttps://t.co/SaTC0Ltvpi",
+ retweetCount: 21,
+ replyCount: 1,
+ favoriteCount: 79,
+ },
+ {
+ author: {
+ name: 'Digital Photography School (dPS)',
+ screenName: 'digitalps',
+ avatar:
+ 'https://images.unsplash.com/photo-1649920762277-3dcd6db40334?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480863337219080196',
+ fullText:
+ 'The Essential Guide to Depth of Field for Beginners https://t.co/GySMCoXRWr',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 6,
+ },
+ {
+ author: {
+ name: 'Manuel Maly',
+ screenName: 'manuelmaly',
+ avatar:
+ 'https://images.unsplash.com/photo-1650821314547-ea4e6f5c31ab?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480815825133129736',
+ fullText:
+ 'You know you’re coding SwiftUI when the tabbar hide/show animation is the hardest part in your AR app',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 12,
+ },
+ {
+ author: {
+ name: 'Dickie Bush 🚢',
+ screenName: 'dickiebush',
+ avatar:
+ 'https://images.unsplash.com/photo-1649470241643-e601950cc489?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480886826638487560',
+ fullText:
+ 'RT @Nicolascole77: Digital Writing 101: \n\nStart small. Test ideas. Double-down and invest in the winners. Repeat.',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Kuba Jaroszewski',
+ screenName: 'pierd86',
+ avatar:
+ 'https://images.unsplash.com/photo-1650315985351-d56d1a00f227?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5MA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480884617838141443',
+ fullText:
+ 'RT @Kjell_Kod: The worst thing about Rust is that it raises the bar for every other programming language.',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Applesfera',
+ screenName: 'applesfera',
+ avatar:
+ 'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480802469361950720',
+ fullText:
+ 'Así de potentes serán las Apple Glass: usarán el cargador de 96W de los nuevos MacBook Pro, según Kuo https://t.co/j2dVay33il https://t.co/5ooOIuks9n',
+ retweetCount: 3,
+ replyCount: 1,
+ favoriteCount: 23,
+ },
+ {
+ author: {
+ name: 'mossegalapoma',
+ screenName: 'mossegalapoma',
+ avatar:
+ 'https://images.unsplash.com/photo-1649898914298-244e49d9a8ac?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480885162665721862',
+ fullText:
+ 'En breu enregistrem el programa 503 amb convidats parlant de Catalan DAO @catalandaoETH - seguiment en directe al nostre canal de Twitch i en format podcast https://t.co/eHj6alp2yp}',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Javier Rosano',
+ screenName: 'Javi_Rosano',
+ avatar:
+ 'https://images.unsplash.com/photo-1650971831044-ccf2ac979a92?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5Ng&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480884199288721408',
+ fullText:
+ '@Imanolzuaznabar Había olvidado por qué quería bloquearte... 😂😂😂',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Antoni Bassas',
+ screenName: 'antonibassas',
+ avatar:
+ 'https://images.unsplash.com/photo-1650139504331-9bc867a86b3b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480844486158786560',
+ fullText:
+ "RT @AraBassas: 📹 L'anàlisi d'@antonibassas: \"La independència no és el projecte d'un home sol'' 👇\nhttps://t.co/QYBdrLOOLQ https://t.co/Ggmv…",
+ retweetCount: 5,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Rapha 🎄',
+ screenName: 'raphaellopesph',
+ avatar:
+ 'https://images.unsplash.com/photo-1649051048669-1e86a8170ab9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480877054484692993',
+ fullText:
+ 'RT @icongalleries: Lots of new #macOS icons today, including work from @raphaellopesph \n\nCheck out the icons at https://t.co/puMlrIlC6N',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Sidney Diongzon',
+ screenName: 'SidneyDiongzon',
+ avatar:
+ 'https://images.unsplash.com/photo-1649731284194-d2ba81f16ba3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Ng&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480886466725167105',
+ fullText: 'Video coming out tomorrow instead. In the mean, gimme a 🖐',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480827445775323138',
+ fullText:
+ 'Hace unos 10 años que diseño profesionalmente.\n\nEn ocasiones me sigo encallando al definir el sistema tipográfico de un proyecto.\n\nY esto no me hace peor diseñadora 💁🏻♀️\n\n¿Qué se te atraganta a ti?',
+ retweetCount: 0,
+ replyCount: 2,
+ favoriteCount: 10,
+ },
+ {
+ author: {
+ name: 'Colin Cornaby',
+ screenName: 'colincornaby',
+ avatar:
+ 'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480795430405349377',
+ fullText:
+ 'Update: I think this is due to "legacy" sort of game engine issues like main thread rendering and no double or triple buffering. Mostly the double or triple buffering. When aiming for 120 fps any little delay seems to cause a cascade of frame misses, which can happen often.',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Easlo',
+ screenName: 'heyeaslo',
+ avatar:
+ 'https://images.unsplash.com/photo-1650035417643-250fa6ee5895?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480856110261157894',
+ fullText:
+ 'Get access to 140+ Notion resources below!\nhttps://t.co/r3wkfOdu4S',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 35,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480856144960761858',
+ fullText:
+ 'RT @cbusquets: Sinceramente, cada vez me preocupa más la brecha tecnológica que estamos creando.\n\nUsar aplicaciones y webs es fácil para mí…',
+ retweetCount: 6,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Colin Cornaby',
+ screenName: 'colincornaby',
+ avatar:
+ 'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480800801794658304',
+ fullText:
+ 'It puts a bit of a shadow over middleware like MoltenVk too. Tuning for M1 really has to be done through Metal. A lot of companies are sustaining their Mac development through tooling like MoltenVk. But results on Apple hardware may just be ok.',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Tyler Hedrick',
+ screenName: 'tyler_hedrick',
+ avatar:
+ 'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480581024241258500',
+ fullText:
+ 'Wordle 205 5/6\n\n🟨🟨⬛⬛🟩\n⬛🟨⬛🟩🟩\n⬛⬛🟩🟩🟩\n⬛⬛⬛⬛⬛\n🟩🟩🟩🟩🟩',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: '@levelsio',
+ screenName: 'levelsio',
+ avatar:
+ 'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480807787336650752',
+ fullText:
+ '🏎 Less than 3 hours from feature request to implemented by @derrickreimer, indie founder of @savvycal\n\n📆 I needed single-use calendar links but based on already existing links I made b4, because ppl were sharing the link to others w/out paying for https://t.co/PL9rryfQ7X https://t.co/29JqkB9nDQ',
+ retweetCount: 1,
+ replyCount: 3,
+ favoriteCount: 84,
+ },
+ {
+ author: {
+ name: 'Itnig',
+ screenName: 'itnig',
+ avatar:
+ 'https://images.unsplash.com/photo-1650035418821-77ee35531a6b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480834735383273474',
+ fullText:
+ 'Internxt, competing against Google Drive and Dropbox\n\nCheck our weekly newsletter:\nhttps://t.co/Jd9yYf2d8L https://t.co/QZzXnOwgWu',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 7,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480818823448207363',
+ fullText:
+ "When you're looking at companies with great engineering cultures, look for those that have parallel career tracks between eng management and engineering. And examples of actual moves.\n\nLike at @Shopify. Two moves to opposite tracks at the same time. 👏 @MikkoH & @stephanleroux https://t.co/nJgpiZvCwu",
+ retweetCount: 8,
+ replyCount: 4,
+ favoriteCount: 101,
+ },
+ {
+ author: {
+ name: 'Jordi Sellas Ferrés',
+ screenName: 'jordisellas',
+ avatar:
+ 'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480804792230453255',
+ fullText:
+ 'RT @artsinhealthfdn: #ArtsAgainstCovid TALKS 🎥\n\n"Després de 200 anys parlant d\'objectes, potser toca parlar de subjectes, i això obliga als…',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Nicolas Cole',
+ screenName: 'Nicolascole77',
+ avatar:
+ 'https://images.unsplash.com/photo-1649452814987-ece76376762a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480714108253048834',
+ fullText:
+ 'Digital Writing 101: \n\nStart small. Test ideas. Double-down and invest in the winners. Repeat.',
+ retweetCount: 2,
+ replyCount: 2,
+ favoriteCount: 34,
+ },
+ {
+ author: {
+ name: 'Jordi Sellas Ferrés',
+ screenName: 'jordisellas',
+ avatar:
+ 'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480879213729222663',
+ fullText:
+ "RT @elmondahir: 👶🏻 Ja és aquí el número 21!\n\nDedicat a la INFÀNCIA, hi trobareu articles d'@emparmoliner @MiquiOtero @AlexGutierrezM @atril…",
+ retweetCount: 8,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'puntCAT',
+ screenName: 'puntCAT',
+ avatar:
+ 'https://images.unsplash.com/photo-1649510998230-fda6188271fe?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480854330374868993',
+ fullText:
+ "Les @youngitgirls formaran part de l'ecosistema creatiu del #Canòdrom de Barcelona.\nA més d'aquesta associació, que impulsa el talent digital jove entre les noies, hi ha 12 projectes més que l'Ateneu d'Innovació Digital incorpora pel curs vinent.\n\n👇\nhttps://t.co/1qFbk4oR1m",
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Un Sr de Barcelona',
+ screenName: 'UnSrdeBarcelona',
+ avatar:
+ 'https://images.unsplash.com/photo-1650357519740-c888919621f8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1478406590730547203',
+ fullText:
+ 'Hola.\n\nMe llamo Elizabeth Holmes.\n\nProbablemente me quedan pocos días antes de entrar en la cárcel. Por mucho tiempo.\n\n¿Mi crimen?\nHaber demostrado que Silicon Valley, Wall Street y toda la prensa económica no se enteran. Vamos, que no tienen ni puta idea.\n\n¿Te lo explico? https://t.co/Dk0ZUnL5pP',
+ retweetCount: 3800,
+ replyCount: 138,
+ favoriteCount: 9052,
+ },
+ {
+ author: {
+ name: 'Samuel Molina',
+ screenName: 'FuKuy',
+ avatar:
+ 'https://images.unsplash.com/photo-1651264042772-23891c614270?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480840983914946560',
+ fullText:
+ "RT @IK1T: Happy #PortfolioDay !\nDear friends ❤️ I'm Fumio, a Lighting Artist 💡 currently working on Star Citizen.\nLooking forward to meetin…",
+ retweetCount: 19,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'I Am Devloper',
+ screenName: 'iamdevloper',
+ avatar:
+ 'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480861250678575104',
+ fullText:
+ "that thing you've been putting off will take around 15 minutes to complete",
+ retweetCount: 46,
+ replyCount: 14,
+ favoriteCount: 358,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480855281655586817',
+ fullText:
+ "Want to get better at writing? Here's what I do:\n\nI start writing those drafts when the ideas come.\n\nTweak them as I go.\n\nI looked back at all the posts I never ended publishing on my blog. Here's some from the last 12 months, many of these a few thousand words in: https://t.co/CFxLlZWxjp",
+ retweetCount: 1,
+ replyCount: 7,
+ favoriteCount: 49,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480872218360004610',
+ fullText:
+ 'Paraconsistent logics find structure in our inconsistent world https://t.co/aAmusRlUzt',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Ara Bassas',
+ screenName: 'AraBassas',
+ avatar:
+ 'https://images.unsplash.com/photo-1650448211778-da533fd39266?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4MA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480841869001113600',
+ fullText:
+ "📹 L'anàlisi d'@antonibassas: \"La independència no és el projecte d'un home sol'' 👇\nhttps://t.co/QYBdrLOOLQ https://t.co/GgmvzQ3zhy",
+ retweetCount: 5,
+ replyCount: 4,
+ favoriteCount: 12,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480887302893322242',
+ fullText:
+ 'Paraconsistent logics help us find structure in the noise of a world messy with inconsistencies https://t.co/aAmusRlUzt',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'Pedro',
+ screenName: 'pepicrft',
+ avatar:
+ 'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480857038804586497',
+ fullText:
+ 'I find very annoying the power Spanish media has to discredit topics some politicians bring up for debate like “why the reduction of meat consumption is good for the environment”. If we can’t talk about fighting climate change, do we prefer to move on and ignore the issue?',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 4,
+ },
+ {
+ author: {
+ name: 'ganyet.eth',
+ screenName: 'ganyet',
+ avatar:
+ 'https://images.unsplash.com/photo-1650476217339-6b7e08b844a7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480816503138177024',
+ fullText:
+ 'Ens hem trobat amb el @jordisellas al #CatVers fa una estona. https://t.co/pMo97qa2xm https://t.co/1bHfEdoeDQ',
+ retweetCount: 0,
+ replyCount: 2,
+ favoriteCount: 7,
+ },
+ {
+ author: {
+ name: 'Imanol Zuaznabar',
+ screenName: 'Imanolzuaznabar',
+ avatar:
+ 'https://images.unsplash.com/photo-1650502446427-0307c61635be?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480574196396744708',
+ fullText:
+ 'El antes y el después de una fotografía de la Vía Láctea en media hora de edición. https://t.co/RWDRdPVfNg',
+ retweetCount: 182,
+ replyCount: 29,
+ favoriteCount: 1478,
+ },
+ {
+ author: {
+ name: 'Victor Blackwell CNN',
+ screenName: 'VictorBlackwell',
+ avatar:
+ 'https://images.unsplash.com/photo-1649019612111-2f919bb7fd61?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480653173224321030',
+ fullText:
+ 'Poet Maya Angelou becomes the first Black woman to appear on a US quarter https://t.co/6MI768E6kV',
+ retweetCount: 10321,
+ replyCount: 732,
+ favoriteCount: 73010,
+ },
+ {
+ author: {
+ name: 'Paul Orlando',
+ screenName: 'porlando',
+ avatar:
+ 'https://images.unsplash.com/photo-1649741622889-f46774607f66?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxMQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480698332510969860',
+ fullText:
+ "I was on the @changelog podcast talking about complex systems, Goodhart's Law, autonomous vehicles, A Pattern Language, and more. Have a listen: https://t.co/y5uORofMWt",
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Directo al paladar',
+ screenName: 'directopaladar',
+ avatar:
+ 'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480859549330554884',
+ fullText:
+ 'Lubina con calabacín, ají dulce y tomates cherry al horno, receta ligera para disfrutar https://t.co/0wcU8jmaXM https://t.co/W14VI5C3h7',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Niall McCormack',
+ screenName: 'ndmccormack',
+ avatar:
+ 'https://images.unsplash.com/photo-1649624964799-609681c92d1b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxMw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480825783086206981',
+ fullText:
+ 'RT @fdesbml: Hand-knit jewelry by Nora Folk | She uses a mixed technique of weaving, knitting, braiding and knotting fine nylon microfilame…',
+ retweetCount: 901,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'James Meickle',
+ screenName: 'jmeickle',
+ avatar:
+ 'https://images.unsplash.com/photo-1649960234288-7049f6020779?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Ng&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480540773036793862',
+ fullText:
+ "Me in 2005: computers aren't magic, they're just machines that do exactly what you tell them\n\nMe in 2022 exhaling an enormous vape hit: SO, the first thing to know about computers is, you never give one your true name",
+ retweetCount: 2431,
+ replyCount: 43,
+ favoriteCount: 17504,
+ },
+ {
+ author: {
+ name: 'Makers.cat',
+ screenName: 'makers_cat',
+ avatar:
+ 'https://images.unsplash.com/photo-1649682716735-b1ba94eda742?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480826431362019328',
+ fullText:
+ 'RT @palmerabollo: Las impresoras térmicas básicas solo pintan puntos negros. Pensé que tendría que hacer el "dithering" de la imagen, pero…',
+ retweetCount: 7,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Guido',
+ screenName: 'palmerabollo',
+ avatar:
+ 'https://images.unsplash.com/photo-1649877845039-2f1f5e524b91?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480599758641287169',
+ fullText:
+ 'Las impresoras térmicas básicas solo pintan puntos negros. Pensé que tendría que hacer el "dithering" de la imagen, pero lo hace la librería python "thermalprinter" https://t.co/TI5OzzF787. Floyd y Steinberg eran unos genios. Cabalgamos a hombros de gigantes. https://t.co/rPubwSzrYs',
+ retweetCount: 7,
+ replyCount: 1,
+ favoriteCount: 165,
+ },
+ {
+ author: {
+ name: 'Chus Naharro',
+ screenName: 'chusnarrolo',
+ avatar:
+ 'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480872099141103616',
+ fullText:
+ 'RT @sunne: Necesito una lista de podcast grabados por mujeres , de la zona de Barcelona. Me da igual el idioma.\n\nMe ayudáis? Yo conozco alg…',
+ retweetCount: 8,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Justin Moore | Sponsorship Coach',
+ screenName: 'justinmooretfam',
+ avatar:
+ 'https://images.unsplash.com/photo-1650213986462-1804543441c2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480800006412009472',
+ fullText: 'Opp!',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Directo al paladar',
+ screenName: 'directopaladar',
+ avatar:
+ 'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480829354150092801',
+ fullText:
+ 'Rebajas en El Corte Inglés: robots de cocina, batidoras, cafeteras y más ofertas en pequeño electrodoméstico de cocina https://t.co/ZT4gBTcnzs https://t.co/oH0oiIt5kz',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Farhan is hiring engineers',
+ screenName: 'fnthawar',
+ avatar:
+ 'https://images.unsplash.com/photo-1651522003733-647782d87365?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480867384751763457',
+ fullText: '🔥',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 4,
+ },
+ {
+ author: {
+ name: 'Pranshu Bahadur',
+ screenName: 'PranshuBahadur',
+ avatar:
+ 'https://images.unsplash.com/photo-1649896867298-3f991eeb6ca2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480807117325889536',
+ fullText:
+ 'Hey everyone! Ever wanted to "find the needle in the haystack"?\n\nCheck out @CShorten30\'s new video about the haystack vector search engine by @SeMI_tech!\n\nFor real though, this is really cool stuff 🤓',
+ retweetCount: 2,
+ replyCount: 2,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Antonio Ortiz',
+ screenName: 'antonello',
+ avatar:
+ 'https://images.unsplash.com/photo-1649437637540-2b9f980399db?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxOQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480849157287989249',
+ fullText:
+ 'Me reafirmo en cómo creo que podemos afrontar esta variante: asumir que casi todos la vamos a pillar, protegiendo sólo a los muy vulnerables; asumir que atención primeria no puede asumir esto ni con refuerzos, descargar procesos a la población. Y confiar en vacunas y anticuerpos',
+ retweetCount: 15,
+ replyCount: 3,
+ favoriteCount: 26,
+ },
+ {
+ author: {
+ name: 'EL PAÍS',
+ screenName: 'el_pais',
+ avatar:
+ 'https://images.unsplash.com/photo-1649600748105-871cb9b4631e?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480846818481221632',
+ fullText:
+ '🔴ÚLTIMA HORA | La OMS calcula que más del 50% de la población europea se contagiará de ómicron en las próximas 6 a 8 semanas https://t.co/x9xC3IWPMy https://t.co/WAn95IhYx3',
+ retweetCount: 636,
+ replyCount: 117,
+ favoriteCount: 949,
+ },
+ {
+ author: {
+ name: 'Glenn McComb',
+ screenName: 'lenymo',
+ avatar:
+ 'https://images.unsplash.com/photo-1649482409426-f0813f293610?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480812010774294529',
+ fullText:
+ 'Retrogram is now accepting “yeet”. Great game, thanks @twolivesleft and @alittlecj.',
+ retweetCount: 1,
+ replyCount: 2,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480857415721660419',
+ fullText:
+ 'RT @cbusquets: Creo que cada día se genera más contenido sobre diseño en español y esto me hace feliz.\n\nConfío en que algo habrá contribuid…',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Oriol Capdevila',
+ screenName: 'urikpd',
+ avatar:
+ 'https://images.unsplash.com/photo-1649001241772-a0dfc60aa1d4?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480843919659257857',
+ fullText:
+ 'RT @crismiquelg: mi único propósito para 2022 es dejar de despedirme con la mano en las videollamadas como si fuera idiota',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Tyler Hedrick',
+ screenName: 'tyler_hedrick',
+ avatar:
+ 'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1479133518189924352',
+ fullText:
+ 'Alright I’m gonna be one of those people now that shares his Wordle each day \n\nWordle 201 4/6\n\n⬛⬛⬛🟨⬛\n⬛🟨⬛🟩⬛\n🟩🟨⬛🟨⬛\n🟩🟩🟩🟩🟩',
+ retweetCount: 0,
+ replyCount: 3,
+ favoriteCount: 9,
+ },
+ {
+ author: {
+ name: 'Jordi Sellas Ferrés',
+ screenName: 'jordisellas',
+ avatar:
+ 'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480820257937936390',
+ fullText:
+ 'Passejada digital matinal amb en Ganyet. Coses que fem i que explicarem demà a la ràdio.',
+ retweetCount: 0,
+ replyCount: 2,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480879690801987585',
+ fullText:
+ 'Tension, bureaucracy and deep humanity define life aboard a refugee rescue ship. @guardian on Aeon Video: https://t.co/qrtEf27Omh',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'puntCAT',
+ screenName: 'puntCAT',
+ avatar:
+ 'https://images.unsplash.com/photo-1649510998230-fda6188271fe?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480857176117809159',
+ fullText:
+ "RT @youngitgirls: 🚀 Arranquem l'any amb noves aventures i moltes ganes de continuar treballant \n\n@CanodromBCN",
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Smashing Magazine',
+ screenName: 'smashingmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480824523247296514',
+ fullText:
+ "RT @jmeickle: Me in 2005: computers aren't magic, they're just machines that do exactly what you tell them\n\nMe in 2022 exhaling an enormous…",
+ retweetCount: 2431,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Applesfera',
+ screenName: 'applesfera',
+ avatar:
+ 'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480810888932306948',
+ fullText:
+ 'Private Relay qué es y cómo podemos utilizarlo para navegar de forma más segura y privada https://t.co/NEpltAYwyA https://t.co/r193iBDOar',
+ retweetCount: 5,
+ replyCount: 0,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Directo al paladar',
+ screenName: 'directopaladar',
+ avatar:
+ 'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480799151659044866',
+ fullText:
+ 'Así es el banco italiano donde el queso parmesano sirve como aval bancario desde la II Guerra Mundial https://t.co/6niGp8CfiM https://t.co/lqWyYN0ugb',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 14,
+ },
+ {
+ author: {
+ name: 'Aitor Goyenechea 💭',
+ screenName: 'AitorGoy',
+ avatar:
+ 'https://images.unsplash.com/photo-1650269717251-d3e5249a8bc8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480834634091008007',
+ fullText: 'Esto',
+ retweetCount: 1,
+ replyCount: 1,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Dean Jackson 🦕',
+ screenName: 'grorg',
+ avatar:
+ 'https://images.unsplash.com/photo-1589049216803-a40738dfef85?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1478178339747602432',
+ fullText:
+ '@twolivesleft retrogram is telling me that “yeet” is not a word! the youth will be disappointed.',
+ retweetCount: 0,
+ replyCount: 3,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Simon Nickel',
+ screenName: 'simonnickel',
+ avatar:
+ 'https://images.unsplash.com/photo-1649869140207-53a4722ce7d8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2Ng&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480823771200110592',
+ fullText:
+ 'Anyone ever had the App Store Connect app actually open the review when you get a notification? Never worked for me.\n\nAlso: Layout is hard 🙄 https://t.co/m1PBl71iOH',
+ retweetCount: 0,
+ replyCount: 5,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Santiago Alonso 💬',
+ screenName: 'salonsoweb',
+ avatar:
+ 'https://images.unsplash.com/photo-1649423515812-5d7f4adb170c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480793786225676289',
+ fullText: 'Primera charleta del año! 🥳🤸♂️🥳🤸♂️🥳🤸♂️🥳🤸♂️ 👇🏻👇🏻',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 6,
+ },
+ {
+ author: {
+ name: 'Arts in Health International Foundation',
+ screenName: 'artsinhealthfdn',
+ avatar:
+ 'https://images.unsplash.com/photo-1650633904515-af9f8caa8582?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480497586595414019',
+ fullText:
+ '#ArtsAgainstCovid TALKS 🎥\n\n"Després de 200 anys parlant d\'objectes, potser toca parlar de subjectes, i això obliga als museus a fer un canvi copernicà"\n\nPepe Serra, director de @MuseuNac_Cat, reflexiona sobre el paper actual dels museus. \nMira-ho aquí 👉 https://t.co/3prlEnWExp',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 8,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480493695560568834',
+ fullText:
+ 'Sinceramente, cada vez me preocupa más la brecha tecnológica que estamos creando.\n\nUsar aplicaciones y webs es fácil para mí, pero constantemente veo personas a quienes les cuesta entender el flujo / iconos / botones.\n\nMe da la impresión de que es porque hacemos user tests...',
+ retweetCount: 6,
+ replyCount: 8,
+ favoriteCount: 57,
+ },
+ {
+ author: {
+ name: '📸 𝙼𝚊𝚞𝚛𝚘 𝙵𝚞𝚎𝚗𝚝𝚎𝚜 🤳 fotomaf ⭐️',
+ screenName: 'Fotomaf',
+ avatar:
+ 'https://images.unsplash.com/photo-1649003175381-2df7e82ef6f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480850406892838917',
+ fullText:
+ 'RT @antonello: Me reafirmo en cómo creo que podemos afrontar esta variante: asumir que casi todos la vamos a pillar, protegiendo sólo a los…',
+ retweetCount: 15,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Ben Scheirman',
+ screenName: 'subdigital',
+ avatar:
+ 'https://images.unsplash.com/photo-1651419935061-c7f954d37446?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480882339005747204',
+ fullText:
+ 'RT @VictorBlackwell: Poet Maya Angelou becomes the first Black woman to appear on a US quarter https://t.co/6MI768E6kV',
+ retweetCount: 10321,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: "El Món d'Ahir",
+ screenName: 'elmondahir',
+ avatar:
+ 'https://images.unsplash.com/photo-1649005200470-3ac8cc79a7bc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480869573796798464',
+ fullText:
+ "👶🏻 Ja és aquí el número 21!\n\nDedicat a la INFÀNCIA, hi trobareu articles d'@emparmoliner @MiquiOtero @AlexGutierrezM @atrillas @Guillemmartnez @_mrspremise @RaquelRicart1 i @XavierAntich, entre d'altres. \n\nJA A LA VENDA a https://t.co/uRF4jx4mpa i molt aviat a llibreries! https://t.co/vxdylJJGaq",
+ retweetCount: 8,
+ replyCount: 1,
+ favoriteCount: 7,
+ },
+ {
+ author: {
+ name: 'Elvira',
+ screenName: 'ElviraBurchik',
+ avatar:
+ 'https://images.unsplash.com/photo-1649171170932-c2dfd27321b4?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480822722838077441',
+ fullText:
+ 'RT @Sommer: I love working with people who are friendly. Who say “thank you” or cheer you on or say “good job.” These things may seem small…',
+ retweetCount: 94,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Webificando Podcast',
+ screenName: 'Webificandop',
+ avatar:
+ 'https://images.unsplash.com/photo-1650790362837-a450407ceb1c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480792377065365511',
+ fullText:
+ 'Holis! 👋\n\nHoy tendremos al gran @salonsoweb para hablar de sus proyectos, automatizaciones y más cosas 🍿🍿\n\n¿Integromat o Zapier? ¿Hay alguna alternativa a la altura? 🤔\n\n🕕 18:00 CET\n\nEn Twitch 👇\nhttps://t.co/tVO9irSqpj',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'Applesfera',
+ screenName: 'applesfera',
+ avatar:
+ 'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480804355263631360',
+ fullText:
+ 'Por qué Apple no adopta RCS en iMessage a pesar de las polémicas declaraciones de un responsable de Android https://t.co/OWVa6gle5k https://t.co/Wrvmi0S3wh',
+ retweetCount: 5,
+ replyCount: 1,
+ favoriteCount: 8,
+ },
+ {
+ author: {
+ name: 'DAZN España',
+ screenName: 'DAZN_ES',
+ avatar:
+ 'https://images.unsplash.com/photo-1650400759211-2d8ae616b006?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480872115276496904',
+ fullText:
+ 'El recital de adelantamientos que Hamilton nos regaló en Brasil 🔥\n\n📽️: @F1\nhttps://t.co/d2lSNmz1Qq',
+ retweetCount: 17,
+ replyCount: 3,
+ favoriteCount: 151,
+ },
+ {
+ author: {
+ name: 'Envato Tuts+',
+ screenName: 'tutsplus',
+ avatar:
+ 'https://images.unsplash.com/photo-1650542914594-033761afbd86?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyOQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480885466668974083',
+ fullText:
+ 'Losing data from an external hard drive can send you into a panic. But before losing hope, READ THIS: ➡️ \n\nThose lost files can be recovered. Head to @tutsplus to learn four ways to restore data from an external hard drive for #Mac. Let’s begin: https://t.co/xIeOtrGwXL https://t.co/F3R1fA2u85',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Connor Shorten',
+ screenName: 'CShorten30',
+ avatar:
+ 'https://images.unsplash.com/photo-1649711992982-092a8e53e39c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480880267816546307',
+ fullText:
+ 'RT @PranshuBahadur: Hey everyone! Ever wanted to "find the needle in the haystack"?\n\nCheck out @CShorten30\'s new video about the haystack v…',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Changelog',
+ screenName: 'changelog',
+ avatar:
+ 'https://images.unsplash.com/photo-1649219026888-aca032914261?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480858641959956483',
+ fullText:
+ "RT @porlando: I was on the @changelog podcast talking about complex systems, Goodhart's Law, autonomous vehicles, A Pattern Language, and m…",
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Applesfera',
+ screenName: 'applesfera',
+ avatar:
+ 'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480881128617791488',
+ fullText:
+ 'El adiós a Lightning y la teoría del Smart Connector en el iPhone del futuro https://t.co/1sQWRVR9z6 https://t.co/3qEcGvi5ha',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 11,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480857084883345408',
+ fullText:
+ 'When logic fails to make sense of a world noisy with inconsistency, paraconsistent logics hold out (im)possible solutions https://t.co/aAmusRlUzt',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: '˗ˏˋrogieˎˊ',
+ screenName: 'rogie',
+ avatar:
+ 'https://images.unsplash.com/photo-1648198835787-9f1b46dd261b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480802209474351105',
+ fullText:
+ 'I just applied for a FREE Citizenship NFT for Satoshi Island 🏝️ @satoshiisland \n\nA real private island being turned into the crypto capital of the world!\n\nTo apply for yours, go to https://t.co/IASuZO959O and click on the Citizenship tab in the menu.\n#satoshiisland #NFT #Airdrop',
+ retweetCount: 0,
+ replyCount: 3,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Álvaro Bernal 🥑',
+ screenName: 'abn',
+ avatar:
+ 'https://images.unsplash.com/photo-1650754294117-f648f300545f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480872313792962568',
+ fullText:
+ 'RT @DAZN_ES: El recital de adelantamientos que Hamilton nos regaló en Brasil 🔥\n\n📽️: @F1\nhttps://t.co/d2lSNmz1Qq',
+ retweetCount: 17,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Michael Andersson',
+ screenName: 'Kjell_Kod',
+ avatar:
+ 'https://images.unsplash.com/photo-1650719782577-d16dddc61ca7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480631817472466946',
+ fullText:
+ 'The worst thing about Rust is that it raises the bar for every other programming language.',
+ retweetCount: 3,
+ replyCount: 4,
+ favoriteCount: 18,
+ },
+ {
+ author: {
+ name: 'I Am Devloper',
+ screenName: 'iamdevloper',
+ avatar:
+ 'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480861999953289216',
+ fullText:
+ "although arguably, the 19th time you ran the automated solution, you'll have recouped your initial investment\n\nso, by all means, shave that yak",
+ retweetCount: 7,
+ replyCount: 5,
+ favoriteCount: 164,
+ },
+ {
+ author: {
+ name: 'Tyler Hedrick',
+ screenName: 'tyler_hedrick',
+ avatar:
+ 'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480887659379654657',
+ fullText:
+ 'My first time in 3!\n\nWordle 206 3/6*\n\n🟨⬛⬛🟨⬛\n🟩🟩🟩⬛⬛\n🟩🟩🟩🟩🟩',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'The Spectator Index',
+ screenName: 'spectatorindex',
+ avatar:
+ 'https://images.unsplash.com/photo-1651245571998-b3a505f2fa96?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480876650514448385',
+ fullText:
+ "JUST IN: World Health Organization regional director says over half Europe's population could be infected with omicron variant within a few weeks",
+ retweetCount: 416,
+ replyCount: 57,
+ favoriteCount: 1147,
+ },
+ {
+ author: {
+ name: 'sadface',
+ screenName: 'Sadface_RL',
+ avatar:
+ 'https://images.unsplash.com/photo-1650304003871-2bdb8aa62dfc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480602754435407876',
+ fullText:
+ 'A beginners guide to health bars.\n\n#pixelart #art #animation #gamedev #indiedev #indiegamedev #indiegame https://t.co/Fhb4mQITRc',
+ retweetCount: 177,
+ replyCount: 2,
+ favoriteCount: 1056,
+ },
+ {
+ author: {
+ name: 'SunnePod 🎙️',
+ screenName: 'sunne',
+ avatar:
+ 'https://images.unsplash.com/photo-1650743768349-94043ebae1e3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480676869720657920',
+ fullText:
+ "Necesito una lista de podcast grabados por mujeres , de la zona de Barcelona. Me da igual el idioma.\n\nMe ayudáis? Yo conozco algunos pero necesito conocer más ' pa una cosa'",
+ retweetCount: 8,
+ replyCount: 8,
+ favoriteCount: 9,
+ },
+ {
+ author: {
+ name: 'MoonCat2878',
+ screenName: 'mooncat2878',
+ avatar:
+ 'https://images.unsplash.com/photo-1650797073595-0a415bb3764a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480601483141959688',
+ fullText:
+ "1/20\n\nI invested 55 $ETH into @LooksRareNFT for 85,636 $LOOKS tokens + I got 12,000 tokens from Airdrops.\n\nI paid an average of $ 1,90 per $LOOKS.\n\nI own a total of 97,935 $LOOKS and am staking all of them.\n\nSo why did I invest in @LooksRareNFT let's dig in! https://t.co/MFTMJc0gpp",
+ retweetCount: 583,
+ replyCount: 131,
+ favoriteCount: 1896,
+ },
+ {
+ author: {
+ name: 'Pedro',
+ screenName: 'pepicrft',
+ avatar:
+ 'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480879632840859648',
+ fullText: 'https://t.co/J0KnQjvwfA',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Chus Naharro',
+ screenName: 'chusnarrolo',
+ avatar:
+ 'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480859223038865408',
+ fullText:
+ 'Revisar y proyectar. @tonicolom me invitó a su podcast para hablar de cómo nos fue en 2021 y qué esperamos del 2022 (y damos detalles de lo que nos hemos marcado 🤓)',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Directo al paladar',
+ screenName: 'directopaladar',
+ avatar:
+ 'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480843457946128388',
+ fullText:
+ 'Qué es la dieta keto, quién puede seguirla y 43 recetas que se adaptan a ella https://t.co/ElB0N2HTG9 https://t.co/Q8xwC9EDyY',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 4,
+ },
+ {
+ author: {
+ name: 'Chus Naharro',
+ screenName: 'chusnarrolo',
+ avatar:
+ 'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480811903400255489',
+ fullText:
+ 'RT @salonsoweb: Primera charleta del año! 🥳🤸♂️🥳🤸♂️🥳🤸♂️🥳🤸♂️ 👇🏻👇🏻',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Dru Riley 📈',
+ screenName: 'DruRly',
+ avatar:
+ 'https://images.unsplash.com/photo-1650502445841-162208d37a79?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480570135878451205',
+ fullText: 'Who should I talk to about DAOs?',
+ retweetCount: 11,
+ replyCount: 100,
+ favoriteCount: 144,
+ },
+ {
+ author: {
+ name: 'Philip Young',
+ screenName: 'philipyoungg',
+ avatar:
+ 'https://images.unsplash.com/photo-1651437074099-fa632f2e708f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480835233796657152',
+ fullText:
+ "Re reading it today and it still blew my mind. You really have to read this. \n\nIt's all meat.",
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 3,
+ },
+ {
+ author: {
+ name: 'Buffer',
+ screenName: 'buffer',
+ avatar:
+ 'https://images.unsplash.com/photo-1651067046747-39410fa2d173?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480842677738516481',
+ fullText:
+ "“The amount of transparency that we have with our customers definitely generates a lot of trust, because they understand that we are doing things that are new and that we're trying things to improve the impact of our products.”\n\n✨ Phantila Phataraprasit, founder of @Sabai_Design",
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 4,
+ },
+ {
+ author: {
+ name: 'James Saeed 🤼♂️',
+ screenName: 'j_t_saeed',
+ avatar:
+ 'https://images.unsplash.com/photo-1650022935614-e215270b77de?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480839929664098307',
+ fullText:
+ 'RT @aram_miquel: Apple should pay more attention. It’s unfair to users, but even more to the small developers that play by the rules!',
+ retweetCount: 2,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'DUNNA',
+ screenName: 'dunnadidit',
+ avatar:
+ 'https://images.unsplash.com/photo-1650471506791-adff557fd92b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzOA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480883792260775938',
+ fullText:
+ 'RT @captureonepro: Want to know what @dunnadidit thinks about Capture One 22?\n\nWatch the video in the link below, where he tries out our ne…',
+ retweetCount: 3,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1374083317935570947',
+ fullText:
+ 'Creo que cada día se genera más contenido sobre diseño en español y esto me hace feliz.\n\nConfío en que algo habrá contribuido mi aventura marciana 😁',
+ retweetCount: 1,
+ replyCount: 2,
+ favoriteCount: 76,
+ },
+ {
+ author: {
+ name: 'Pedro',
+ screenName: 'pepicrft',
+ avatar:
+ 'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480880317737152517',
+ fullText: '🤯 Around 300 people',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 2,
+ },
+ {
+ author: {
+ name: 'Imanol Zuaznabar',
+ screenName: 'Imanolzuaznabar',
+ avatar:
+ 'https://images.unsplash.com/photo-1650502446427-0307c61635be?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480837773800181765',
+ fullText:
+ '@Javi_Rosano La primera vez que disparé desde ahí me quedé alucinado viendo el JPEG de cámara, aquello es otra liga 😄',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Cris Busquets 🦊',
+ screenName: 'cbusquets',
+ avatar:
+ 'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480861803496280065',
+ fullText:
+ 'Si estás construyendo tu #portfolio y no puedes publicar algunos de los proyectos porque están bajo un NDA, quizás esto te interesa 🤘\n\nhttps://t.co/6kvzwCQs1H',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 6,
+ },
+ {
+ author: {
+ name: 'Gergely Orosz',
+ screenName: 'GergelyOrosz',
+ avatar:
+ 'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480830543382122499',
+ fullText:
+ "If you work in tech, you probably have strong opinions on how hiring is broken.\n\nWrite this down. The pain points you see and what you'd solve if you were the hiring manager.\n\nThere's a good chance you'll be a hiring manager in a few years. Get this list out and make the changes.",
+ retweetCount: 11,
+ replyCount: 8,
+ favoriteCount: 85,
+ },
+ {
+ author: {
+ name: 'Ludo the great',
+ screenName: 'granludo',
+ avatar:
+ 'https://images.unsplash.com/photo-1651226550740-b30efba028f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480823014409355266',
+ fullText:
+ 'He decidit no comprar-me aquesta samarreta. #butIshould https://t.co/zkao8s06Tx',
+ retweetCount: 1,
+ replyCount: 2,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: '@levelsio',
+ screenName: 'levelsio',
+ avatar:
+ 'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480808657780543493',
+ fullText:
+ '1) User clicks on https://t.co/PL9rryfQ7X client dashboard to schedule meeting\n2) Robot checks where user is from, EU, non-EU or US\n3) Robot picks right calendar link\n4) Robot duplicates the link, makes it single-use and personalizes the title with their name in it',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 19,
+ },
+ {
+ author: {
+ name: 'Kosta Eleftheriou',
+ screenName: 'keleftheriou',
+ avatar:
+ 'https://images.unsplash.com/photo-1651017810072-3043e05ddbcc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0MA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480626605370142724',
+ fullText: '💰 How to make $13,000,000 on the App Store:\n\n(thread)',
+ retweetCount: 606,
+ replyCount: 25,
+ favoriteCount: 2201,
+ },
+ {
+ author: {
+ name: 'Philip Young',
+ screenName: 'philipyoungg',
+ avatar:
+ 'https://images.unsplash.com/photo-1651437074099-fa632f2e708f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480876712275496960',
+ fullText:
+ "Session milestone:\n\nToday's revenue is at $500 😱\n\nAn outlier but worth to celebrate! 🥳\n\nSpend my day cleaning the house, learning AWS + SNS (painful), and reading book to make Session better ⚡️ https://t.co/2Zf7UJStt6",
+ retweetCount: 0,
+ replyCount: 4,
+ favoriteCount: 36,
+ },
+ {
+ author: {
+ name: 'Easlo',
+ screenName: 'heyeaslo',
+ avatar:
+ 'https://images.unsplash.com/photo-1650035417643-250fa6ee5895?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480766432275144706',
+ fullText:
+ 'Notion can literally do everything.\n\nNotion + Super → Website\nNotion + Queue → Schedule Twitter\nNotion + Instapost → Schedule Instagram\nNotion + Zorbi → Flashcards\nNotion + NotionForms → Forms\nNotion + HelpKit → Knowledge Base \nNotion + Float → Course',
+ retweetCount: 55,
+ replyCount: 15,
+ favoriteCount: 532,
+ },
+ {
+ author: {
+ name: 'SonyAlphaRumors',
+ screenName: 'SonyAlphaRumors',
+ avatar:
+ 'https://images.unsplash.com/photo-1650170495855-add188d60239?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480809744881303554',
+ fullText: 'Sony Tidbits… https://t.co/xOStQJcjO9',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480841997997035524',
+ fullText:
+ 'Recognising that waste is central, not peripheral, to everything we design, make and do is key to transforming the future https://t.co/2iIvy0430c',
+ retweetCount: 4,
+ replyCount: 0,
+ favoriteCount: 12,
+ },
+ {
+ author: {
+ name: 'Dickie Bush 🚢',
+ screenName: 'dickiebush',
+ avatar:
+ 'https://images.unsplash.com/photo-1649470241643-e601950cc489?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480713019772518407',
+ fullText:
+ 'The single biggest mistake beginner writers make:\n\nPublishing weekly blog posts into the void.\n\nInstead, you should write daily Atomic Essays.\n\nAnd here are 4 reasons why: https://t.co/FoYUUkA3RV',
+ retweetCount: 58,
+ replyCount: 16,
+ favoriteCount: 439,
+ },
+ {
+ author: {
+ name: 'B&H Photo Video',
+ screenName: 'bhphoto',
+ avatar:
+ 'https://images.unsplash.com/photo-1651275001129-e8e4fbba075d?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0MQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480876449284472838',
+ fullText:
+ 'The latest Canon Cinema EOS System release is coming and it will be "Ready for Anything." \nClick here for more information on January 19, 2022 at 7 AM EST - https://t.co/1BS8S8uAhm\n\nWhat are you hoping this release will bring? https://t.co/UIFyV8hyqv',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 7,
+ },
+ {
+ author: {
+ name: 'Simeon',
+ screenName: 'twolivesleft',
+ avatar:
+ 'https://images.unsplash.com/photo-1649633720119-ae64fda5fac9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480831252060016640',
+ fullText:
+ 'RT @lenymo: Retrogram is now accepting “yeet”. Great game, thanks @twolivesleft and @alittlecj. https://t.co/5Y7oiqIQua',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Aeon+Psyche',
+ screenName: 'aeonmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480864584710103046',
+ fullText:
+ 'Artworks have the capacity to transport us into other worlds. But where exactly do we go when we are immersed in art? https://t.co/F1QXdpujFh',
+ retweetCount: 4,
+ replyCount: 0,
+ favoriteCount: 14,
+ },
+ {
+ author: {
+ name: 'Zachary Diaz',
+ screenName: 'ZacharyDiaz',
+ avatar:
+ 'https://images.unsplash.com/photo-1651045433852-1a4dc09fc859?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480713396806832132',
+ fullText:
+ 'A week of onboarding later and I can share my new role: I’ve joined @tiktok_us Live and will be leading the Creator Management team. \n\nThere is a massive opportunity to bring more live creators and content categories to the existing ecosystem.\n\nPSA: I’m hiring Creator Managers! https://t.co/VGeTOtVvSq',
+ retweetCount: 20,
+ replyCount: 242,
+ favoriteCount: 721,
+ },
+ {
+ author: {
+ name: 'David Cortés',
+ screenName: 'davebcn87',
+ avatar:
+ 'https://images.unsplash.com/photo-1650509354833-d3eeb1d161e1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0Nw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480887856184897538',
+ fullText:
+ 'Want to keep track of your achievements? \n\nStart a brag document.\n\n https://t.co/5BivvuxWzO',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Smashing Magazine',
+ screenName: 'smashingmag',
+ avatar:
+ 'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1479108107154255875',
+ fullText:
+ '📣 New Smashing Workshops in 2022:\n \n😎 Accessible Front-End Patterns — @cariefisher\n👾 Front-End Testing — @bahmutov\n👻 HTML Email — \n@HTeuMeuLeu\n🚚 DevOps — \n@mishunov\n🚂 Designing For Complex UI — @smashingmag\n🚚 Data Visualization — \n@wattenberger\n \n👉 https://t.co/aFVbyZMada https://t.co/1MORKvqwYZ',
+ retweetCount: 15,
+ replyCount: 1,
+ favoriteCount: 52,
+ },
+ {
+ author: {
+ name: 'Applesfera',
+ screenName: 'applesfera',
+ avatar:
+ 'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480870016425902081',
+ fullText:
+ 'La App Store deberá permitir pagos de terceros, pero Apple seguirá cobrando una comisión reducida al desarrollador https://t.co/TZboDnFhoc https://t.co/Ci1RRMjMzq',
+ retweetCount: 5,
+ replyCount: 0,
+ favoriteCount: 5,
+ },
+ {
+ author: {
+ name: 'Franz Jeitz',
+ screenName: 'fudgegraphics',
+ avatar:
+ 'https://images.unsplash.com/photo-1650039673254-08927baf72ac?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480842566685925377',
+ fullText: 'Wordle 206 3/6\n\n⬜🟩⬜🟨⬜\n⬜🟩🟩⬜🟩\n🟩🟩🟩🟩🟩',
+ retweetCount: 0,
+ replyCount: 0,
+ favoriteCount: 1,
+ },
+ {
+ author: {
+ name: '📸 𝙼𝚊𝚞𝚛𝚘 𝙵𝚞𝚎𝚗𝚝𝚎𝚜 🤳 fotomaf ⭐️',
+ screenName: 'Fotomaf',
+ avatar:
+ 'https://images.unsplash.com/photo-1649003175381-2df7e82ef6f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNA&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480837515909246977',
+ fullText: 'RT @AitorGoy: Esto https://t.co/NEIdMjQtzF',
+ retweetCount: 1,
+ replyCount: 0,
+ favoriteCount: 0,
+ },
+ {
+ author: {
+ name: 'Colin Cornaby',
+ screenName: 'colincornaby',
+ avatar:
+ 'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',
+ },
+ id: '1480800802599956480',
+ fullText:
+ 'If you know what to look for you might be able to write more M1 friendly Vulkan code and shaders.',
+ retweetCount: 0,
+ replyCount: 1,
+ favoriteCount: 0,
+ },
+];
diff --git a/example/src/screens/integrations/flashlist/index.ts b/example/src/screens/integrations/flashlist/index.ts
new file mode 100644
index 000000000..af9ce6967
--- /dev/null
+++ b/example/src/screens/integrations/flashlist/index.ts
@@ -0,0 +1 @@
+export { default } from './FlashListExample';
diff --git a/example/src/screens/integrations/flashlist/models/Author.ts b/example/src/screens/integrations/flashlist/models/Author.ts
new file mode 100644
index 000000000..10e673ff8
--- /dev/null
+++ b/example/src/screens/integrations/flashlist/models/Author.ts
@@ -0,0 +1,5 @@
+export default interface Author {
+ name: string;
+ avatar: string;
+ screenName: string;
+}
diff --git a/example/src/screens/integrations/flashlist/models/Tweet.ts b/example/src/screens/integrations/flashlist/models/Tweet.ts
new file mode 100644
index 000000000..198d98343
--- /dev/null
+++ b/example/src/screens/integrations/flashlist/models/Tweet.ts
@@ -0,0 +1,10 @@
+import type Author from './Author';
+
+export default interface Tweet {
+ id: string;
+ author: Author;
+ fullText: string;
+ retweetCount: number;
+ replyCount: number;
+ favoriteCount: number;
+}
diff --git a/example/src/screens/integrations/map/BlurredBackground.tsx b/example/src/screens/integrations/map/BlurredBackground.tsx
new file mode 100644
index 000000000..2ea27ecd6
--- /dev/null
+++ b/example/src/screens/integrations/map/BlurredBackground.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { StyleSheet, View } from 'react-native';
+import { BlurView } from 'expo-blur';
+
+const BlurredBackground = () => {
+ return (
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ blurView: {
+ ...StyleSheet.absoluteFillObject,
+ },
+ container: {
+ ...StyleSheet.absoluteFillObject,
+ borderTopLeftRadius: 10,
+ borderTopRightRadius: 10,
+ overflow: 'hidden',
+ },
+});
+
+export default BlurredBackground;
diff --git a/example/bare/src/components/locationDetailsHandle/LocationDetailsHandle.tsx b/example/src/screens/integrations/map/BlurredHandle.tsx
similarity index 80%
rename from example/bare/src/components/locationDetailsHandle/LocationDetailsHandle.tsx
rename to example/src/screens/integrations/map/BlurredHandle.tsx
index 39a8f47ca..32faa3799 100644
--- a/example/bare/src/components/locationDetailsHandle/LocationDetailsHandle.tsx
+++ b/example/src/screens/integrations/map/BlurredHandle.tsx
@@ -4,7 +4,7 @@ import { useShowcaseTheme } from '@gorhom/showcase-template';
const { width: SCREEN_WIDTH } = Dimensions.get('screen');
-const LocationDetailsHandle = () => {
+const BlurredHandle = () => {
// hooks
const { colors } = useShowcaseTheme();
@@ -13,10 +13,10 @@ const LocationDetailsHandle = () => {
() => [
styles.indicator,
{
- backgroundColor: colors.border,
+ backgroundColor: colors.secondaryText,
},
],
- [colors.border]
+ [colors.secondaryText]
);
// render
@@ -37,8 +37,8 @@ export const styles = StyleSheet.create({
width: (8 * SCREEN_WIDTH) / 100,
height: 5,
borderRadius: 4,
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
});
-export default LocationDetailsHandle;
+export default BlurredHandle;
diff --git a/example/bare/src/components/locationDetails/LocationDetails.tsx b/example/src/screens/integrations/map/LocationDetails.tsx
similarity index 85%
rename from example/bare/src/components/locationDetails/LocationDetails.tsx
rename to example/src/screens/integrations/map/LocationDetails.tsx
index 9ea47372a..ac3bd923e 100644
--- a/example/bare/src/components/locationDetails/LocationDetails.tsx
+++ b/example/src/screens/integrations/map/LocationDetails.tsx
@@ -1,16 +1,18 @@
import React, { memo, useCallback, useMemo } from 'react';
-import { View, StyleSheet, Image } from 'react-native';
+import { View, StyleSheet, Image, ViewProps } from 'react-native';
import { FlatList, TouchableOpacity } from 'react-native-gesture-handler';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';
-import { Button } from '@gorhom/bottom-sheet-example-app';
-import type { Location } from '../../types';
+import { BottomSheetView } from '@gorhom/bottom-sheet';
+import { Button } from '../../../components/button';
+import { Location } from '../../../types';
const keyExtractor = (item: string, index: number) => `${index}${item}`;
const photoSize = 180;
export const LOCATION_DETAILS_HEIGHT = 298;
-interface LocationDetailsProps extends Location {
+interface LocationDetailsProps extends Location, Pick {
onClose: () => void;
}
@@ -18,13 +20,22 @@ const LocationDetailsComponent = ({
name,
address,
photos,
+ onLayout,
onClose,
}: LocationDetailsProps) => {
//#region hooks
const { colors } = useShowcaseTheme();
+ const { bottom } = useSafeAreaInsets();
//#endregion
//#region styles
+ const containerStyle = useMemo(
+ () => ({
+ ...styles.container,
+ paddingBottom: bottom,
+ }),
+ [bottom]
+ );
const closeButtonStyle = useMemo(
() => [
styles.closeButton,
@@ -37,7 +48,7 @@ const LocationDetailsComponent = ({
//#endregion
//#region renders
- const renderPhoto = useCallback(({ item }) => {
+ const renderPhoto = useCallback(({ item }: any) => {
return (
+
{name}
@@ -65,12 +76,6 @@ const LocationDetailsComponent = ({
- {}}
- />
-
{}}
/>
-
+
);
//#endregion
};
diff --git a/example/src/screens/integrations/map/LocationDetailsBottomSheet.tsx b/example/src/screens/integrations/map/LocationDetailsBottomSheet.tsx
new file mode 100644
index 000000000..cd2c05c7e
--- /dev/null
+++ b/example/src/screens/integrations/map/LocationDetailsBottomSheet.tsx
@@ -0,0 +1,86 @@
+import React, { useEffect } from 'react';
+import { BottomSheetModal } from '@gorhom/bottom-sheet';
+import {
+ forwardRef,
+ useCallback,
+ useImperativeHandle,
+ useRef,
+ useState,
+} from 'react';
+import { useHeaderHeight } from '@react-navigation/elements';
+import { SharedValue } from 'react-native-reanimated';
+import { LocationDetails } from './LocationDetails';
+import BlurredBackground from './BlurredBackground';
+import BlurredHandle from './BlurredHandle';
+import { Location } from '../../../types';
+
+interface LocationDetailsBottomSheetProps {
+ index: SharedValue;
+ position: SharedValue;
+}
+
+export interface LocationDetailsBottomSheetMethods {
+ present: (location: Location) => void;
+}
+
+const SNAP_POINTS = ['100%'];
+
+export const LocationDetailsBottomSheet = forwardRef<
+ LocationDetailsBottomSheetMethods,
+ LocationDetailsBottomSheetProps
+>(({ index, position }, ref) => {
+ //#region refs
+ const bottomSheetRef = useRef(null);
+ //#endregion
+
+ //#region state
+ const [selectedLocation, setSelectedLocation] = useState();
+ //#endregion
+
+ //#region hooks
+ const headerHeight = useHeaderHeight();
+ //#endregion
+
+ //#region callbacks
+ const handleCloseLocationDetails = useCallback(() => {
+ bottomSheetRef.current?.dismiss();
+ }, []);
+ const handleOnDismiss = useCallback(() => {
+ setSelectedLocation(undefined);
+ }, []);
+ //#endregion
+
+ //#region effects
+ useImperativeHandle(ref, () => ({
+ present: location => {
+ setSelectedLocation(location);
+ },
+ }));
+
+ useEffect(() => {
+ if (selectedLocation) {
+ bottomSheetRef.current?.present();
+ }
+ }, [selectedLocation]);
+ //#endregion
+
+ return (
+
+
+
+ );
+});
diff --git a/example/bare/src/components/locationItem/LocationItem.tsx b/example/src/screens/integrations/map/LocationItem.tsx
similarity index 75%
rename from example/bare/src/components/locationItem/LocationItem.tsx
rename to example/src/screens/integrations/map/LocationItem.tsx
index 37446e7ea..a1fd2316c 100644
--- a/example/bare/src/components/locationItem/LocationItem.tsx
+++ b/example/src/screens/integrations/map/LocationItem.tsx
@@ -1,6 +1,6 @@
-import React, { useMemo, memo } from 'react';
+import React, { memo } from 'react';
import { StyleSheet, View } from 'react-native';
-import { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';
+import { ShowcaseLabel } from '@gorhom/showcase-template';
interface LocationItemProps {
title: string;
@@ -8,16 +8,6 @@ interface LocationItemProps {
}
const LocationItemComponent = ({ title, subTitle }: LocationItemProps) => {
- const { colors } = useShowcaseTheme();
- const separatorStyle = useMemo(
- () => [
- styles.separator,
- {
- backgroundColor: colors.border,
- },
- ],
- [colors.border]
- );
// render
return (
<>
@@ -30,7 +20,7 @@ const LocationItemComponent = ({ title, subTitle }: LocationItemProps) => {
)}
-
+
>
);
};
@@ -55,17 +45,19 @@ const styles = StyleSheet.create({
},
title: {
fontSize: 16,
+ fontWeight: '700',
marginBottom: 4,
textTransform: 'capitalize',
},
subtitle: {
- color: '#666',
+ color: '#999',
fontSize: 14,
textTransform: 'capitalize',
},
separator: {
flex: 1,
- height: 1,
+ height: 0.5,
+ backgroundColor: '#666',
},
});
diff --git a/example/src/screens/integrations/map/LocationListBottomSheet.tsx b/example/src/screens/integrations/map/LocationListBottomSheet.tsx
new file mode 100644
index 000000000..e8f6f5295
--- /dev/null
+++ b/example/src/screens/integrations/map/LocationListBottomSheet.tsx
@@ -0,0 +1,121 @@
+import React, { forwardRef, useCallback, useMemo } from 'react';
+import {
+ BottomSheetBackdrop,
+ BottomSheetBackdropProps,
+ BottomSheetModal,
+ BottomSheetScrollView,
+ TouchableOpacity,
+} from '@gorhom/bottom-sheet';
+import { useHeaderHeight } from '@react-navigation/elements';
+import { StyleSheet } from 'react-native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import { SharedValue, useAnimatedStyle } from 'react-native-reanimated';
+import BlurredBackground from './BlurredBackground';
+import BlurredHandle from './BlurredHandle';
+import { LocationItem } from './LocationItem';
+import { createLocationListMockData } from '../../../utilities/createMockData';
+import { Location } from '../../../types';
+
+interface LocationListBottomSheetProps {
+ index: SharedValue;
+ position: SharedValue;
+ onItemPress: (location: Location) => void;
+}
+
+export const MIDDLE_SNAP_POINT = 300;
+
+const SNAP_POINTS = [64, MIDDLE_SNAP_POINT, '100%'];
+const DATA = createLocationListMockData(15);
+
+export const LocationListBottomSheet = forwardRef<
+ BottomSheetModal,
+ LocationListBottomSheetProps
+>(({ index, position, onItemPress }, ref) => {
+ //#region hooks
+ const headerHeight = useHeaderHeight();
+ const { bottom: bottomSafeArea } = useSafeAreaInsets();
+ //#endregion
+
+ //#region styles
+ const scrollViewAnimatedStyle = useAnimatedStyle(
+ () => ({
+ opacity: index.value,
+ }),
+ [index.value]
+ );
+ const scrollViewStyle = useMemo(
+ () => [styles.scrollView, scrollViewAnimatedStyle],
+ [scrollViewAnimatedStyle]
+ );
+ const scrollViewContentContainer = useMemo(
+ () => [
+ styles.scrollViewContentContainer,
+ { paddingBottom: bottomSafeArea },
+ ],
+ [bottomSafeArea]
+ );
+ //#endregion
+
+ //#region render
+ const renderBackdrop = useCallback(
+ (props: BottomSheetBackdropProps) => (
+
+ ),
+ []
+ );
+
+ const renderItem = useCallback(
+ (item: Location, index: number) => (
+ onItemPress(item)}
+ >
+
+
+ ),
+ [onItemPress]
+ );
+
+ return (
+
+
+ {DATA.map(renderItem)}
+
+
+ );
+});
+
+const styles = StyleSheet.create({
+ scrollView: {
+ flex: 1,
+ },
+ scrollViewContentContainer: {
+ paddingHorizontal: 16,
+ },
+});
diff --git a/example/src/screens/integrations/map/MapExample.tsx b/example/src/screens/integrations/map/MapExample.tsx
new file mode 100644
index 000000000..39ac68726
--- /dev/null
+++ b/example/src/screens/integrations/map/MapExample.tsx
@@ -0,0 +1,120 @@
+import React, { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
+import { View, StyleSheet, Dimensions } from 'react-native';
+import MapView from 'react-native-maps';
+import { useSharedValue, useDerivedValue } from 'react-native-reanimated';
+import { BottomSheetModal } from '@gorhom/bottom-sheet';
+import type { Location } from '../../../types';
+import Weather from './Weather';
+import { withModalProvider } from '../../modal/withModalProvider';
+import {
+ LocationDetailsBottomSheet,
+ LocationDetailsBottomSheetMethods,
+} from './LocationDetailsBottomSheet';
+import { LocationListBottomSheet } from './LocationListBottomSheet';
+
+const { height: SCREEN_HEIGHT } = Dimensions.get('window');
+
+const MapExample = () => {
+ //#region refs
+ const mapRef = useRef(null);
+ const poiListModalRef = useRef(null);
+ const poiDetailsModalRef = useRef(null);
+ //#endregion
+
+ //#region variables
+ const mapInitialCamera = useMemo(
+ () => ({
+ center: {
+ latitude: 52.3791,
+ longitude: 4.9003,
+ },
+ heading: 0,
+ pitch: 0,
+ zoom: 10,
+ altitude: 40000,
+ }),
+ []
+ );
+ //#endregion
+
+ //#region animated variables
+ const animatedPOIListIndex = useSharedValue(0);
+ const animatedPOIListPosition = useSharedValue(SCREEN_HEIGHT);
+ const animatedPOIDetailsIndex = useSharedValue(0);
+ const animatedPOIDetailsPosition = useSharedValue(SCREEN_HEIGHT);
+
+ const weatherAnimatedIndex = useDerivedValue(() =>
+ animatedPOIListIndex.value > animatedPOIDetailsIndex.value
+ ? animatedPOIListIndex.value
+ : animatedPOIDetailsIndex.value
+ );
+ const weatherAnimatedPosition = useDerivedValue(() =>
+ animatedPOIListPosition.value < animatedPOIDetailsPosition.value
+ ? animatedPOIListPosition.value
+ : animatedPOIDetailsPosition.value
+ );
+ //#endregion
+
+ //#region callbacks
+ const handleTouchStart = useCallback(() => {
+ poiListModalRef.current?.collapse();
+ }, []);
+ const handleOnLocationPress = useCallback((item: Location) => {
+ poiDetailsModalRef.current?.present(item);
+ }, []);
+ //#endregion
+
+ //#region effects
+ useLayoutEffect(() => {
+ requestAnimationFrame(() => poiListModalRef.current?.present());
+ }, []);
+ //#endregion
+
+ // renders
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ },
+ mapContainer: {
+ ...StyleSheet.absoluteFillObject,
+ },
+ scrollView: {
+ flex: 1,
+ },
+ scrollViewContentContainer: {
+ paddingHorizontal: 16,
+ },
+});
+
+export default withModalProvider(MapExample);
diff --git a/example/src/screens/integrations/map/Weather.tsx b/example/src/screens/integrations/map/Weather.tsx
new file mode 100644
index 000000000..bfbb88b16
--- /dev/null
+++ b/example/src/screens/integrations/map/Weather.tsx
@@ -0,0 +1,91 @@
+import React, { useCallback, useMemo, useState } from 'react';
+import { LayoutChangeEvent, StyleSheet } from 'react-native';
+import Animated, {
+ Extrapolation,
+ interpolate,
+ useAnimatedStyle,
+} from 'react-native-reanimated';
+import { useSafeAreaFrame } from 'react-native-safe-area-context';
+import { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';
+import { MIDDLE_SNAP_POINT } from './LocationListBottomSheet';
+
+interface WeatherProps {
+ animatedPosition: Animated.SharedValue;
+ animatedIndex: Animated.SharedValue;
+}
+
+const SPACE = 8;
+
+const Weather = ({ animatedIndex, animatedPosition }: WeatherProps) => {
+ //#region state
+ const [height, setHeight] = useState(0);
+ //#endregion
+
+ //#region hooks
+ const { height: screenHeight } = useSafeAreaFrame();
+ const { colors } = useShowcaseTheme();
+ //#endregion
+
+ //#region callbacks
+ const handleOnLayout = useCallback(
+ ({ nativeEvent: { layout } }: LayoutChangeEvent) => {
+ setHeight(layout.height);
+ },
+ []
+ );
+ //#endregion
+
+ //#region styles
+ const containerAnimatedStyle = useAnimatedStyle(() => {
+ const belowMiddlePosition =
+ screenHeight - animatedPosition.value < MIDDLE_SNAP_POINT;
+ return {
+ opacity: interpolate(
+ animatedIndex.value,
+ [1, 1.125],
+ [1, 0],
+ Extrapolation.CLAMP
+ ),
+ transform: [
+ {
+ translateY: belowMiddlePosition
+ ? animatedPosition.value - height - SPACE
+ : screenHeight - MIDDLE_SNAP_POINT - height - SPACE,
+ },
+ ],
+ };
+ }, [animatedIndex.value, animatedPosition.value, height, screenHeight]);
+ const containerStyle = useMemo(
+ () => [
+ styles.container,
+ { backgroundColor: colors.secondaryCard },
+ containerAnimatedStyle,
+ ],
+ [colors.secondaryCard, containerAnimatedStyle]
+ );
+ //#endregion
+
+ return (
+
+ ☁️ 12°
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ position: 'absolute',
+ right: 12,
+ top: 0,
+ padding: 6,
+ marginTop: 0,
+ borderRadius: 4,
+ },
+ label: {
+ fontSize: 12,
+ lineHeight: 12,
+ fontWeight: '800',
+ },
+});
+
+export default Weather;
diff --git a/example/bare/src/screens/DummyScreen.tsx b/example/src/screens/integrations/navigation/DummyScreen.tsx
similarity index 92%
rename from example/bare/src/screens/DummyScreen.tsx
rename to example/src/screens/integrations/navigation/DummyScreen.tsx
index 696e65949..eb3215e2e 100644
--- a/example/bare/src/screens/DummyScreen.tsx
+++ b/example/src/screens/integrations/navigation/DummyScreen.tsx
@@ -1,6 +1,6 @@
import React, { useCallback, memo } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { ContactList } from '@gorhom/bottom-sheet-example-app';
+import { ContactList } from '../../../components/contactList';
interface DummyScreenProps {
title: string;
diff --git a/example/bare/src/screens/integrations/NavigatorExample.tsx b/example/src/screens/integrations/navigation/NavigatorExample.tsx
similarity index 88%
rename from example/bare/src/screens/integrations/NavigatorExample.tsx
rename to example/src/screens/integrations/navigation/NavigatorExample.tsx
index 423e6738e..5e3b2aff7 100644
--- a/example/bare/src/screens/integrations/NavigatorExample.tsx
+++ b/example/src/screens/integrations/navigation/NavigatorExample.tsx
@@ -6,9 +6,9 @@ import {
TransitionPresets,
} from '@react-navigation/stack';
import BottomSheet from '@gorhom/bottom-sheet';
-import { Button } from '@gorhom/bottom-sheet-example-app';
import { NavigationContainer } from '@react-navigation/native';
-import createDummyScreen from '../DummyScreen';
+import createDummyScreen from './DummyScreen';
+import { Button } from '../../../components/button';
const Stack = createStackNavigator();
const ScreenA = createDummyScreen({
@@ -42,7 +42,7 @@ const Navigator = () => {
const screenOptions = useMemo(
() => ({
...TransitionPresets.SlideFromRightIOS,
-
+ headerMode: 'screen',
headerShown: true,
safeAreaInsets: { top: 0 },
cardStyle: {
@@ -56,7 +56,7 @@ const Navigator = () => {
const screenAOptions = useMemo(() => ({ headerLeft: () => null }), []);
return (
-
+
{
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
- const handleSheetChange = useCallback(index => {
- // eslint-disable-next-line no-console
- console.log('handleSheetChange', index);
- }, []);
- const handleSnapPress = useCallback(index => {
+ const handleSnapPress = useCallback((index: number) => {
bottomSheetRef.current?.snapToIndex(index);
}, []);
const handleExpandPress = useCallback(() => {
@@ -107,9 +103,9 @@ const NavigatorExample = () => {
diff --git a/example/app/src/screens/modal/BackdropExample.tsx b/example/src/screens/modal/BackdropExample.tsx
similarity index 93%
rename from example/app/src/screens/modal/BackdropExample.tsx
rename to example/src/screens/modal/BackdropExample.tsx
index c4d37e360..217d97df8 100644
--- a/example/app/src/screens/modal/BackdropExample.tsx
+++ b/example/src/screens/modal/BackdropExample.tsx
@@ -4,6 +4,7 @@ import {
BottomSheetModal,
BottomSheetBackdrop,
BottomSheetBackdropProps,
+ BottomSheetHandleProps,
} from '@gorhom/bottom-sheet';
import { Button } from '../../components/button';
import { ContactList } from '../../components/contactList';
@@ -60,7 +61,9 @@ export const BackdropExample = () => {
);
const renderHeaderHandle = useCallback(
- props => ,
+ (props: BottomSheetHandleProps) => (
+
+ ),
[]
);
return (
@@ -76,9 +79,10 @@ export const BackdropExample = () => {
diff --git a/example/app/src/screens/modal/DetachedExample.tsx b/example/src/screens/modal/DetachedExample.tsx
similarity index 72%
rename from example/app/src/screens/modal/DetachedExample.tsx
rename to example/src/screens/modal/DetachedExample.tsx
index 2e06327fc..54c2802c1 100644
--- a/example/app/src/screens/modal/DetachedExample.tsx
+++ b/example/src/screens/modal/DetachedExample.tsx
@@ -1,53 +1,58 @@
-import React, { useCallback, useMemo, useRef } from 'react';
-import { View, StyleSheet, Text } from 'react-native';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
+ BottomSheetFooter,
+ type BottomSheetFooterProps,
+ type BottomSheetHandleProps,
BottomSheetModal,
BottomSheetView,
- BottomSheetFooter,
- useBottomSheetDynamicSnapPoints,
} from '@gorhom/bottom-sheet';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Button } from '../../components/button';
import { ContactItem } from '../../components/contactItem';
import { HeaderHandle } from '../../components/headerHandle';
-import { withModalProvider } from './withModalProvider';
+import type { Contact } from '../../types';
import { createContactListMockData } from '../../utilities/createMockData';
+import { withModalProvider } from './withModalProvider';
+
+const DATA = createContactListMockData(4);
const DetachedExample = () => {
// refs
const bottomSheetRef = useRef(null);
+ // state
+ const [count, setCount] = useState(2);
+
// variables
- const initialSnapPoints = useMemo(() => ['CONTENT_HEIGHT'], []);
- const data = useMemo(() => createContactListMockData(2), []);
+ const data = useMemo(() => DATA.slice(0, count), [count]);
// hooks
- const {
- animatedHandleHeight,
- animatedSnapPoints,
- animatedContentHeight,
- handleContentLayout,
- } = useBottomSheetDynamicSnapPoints(initialSnapPoints);
const { bottom: safeBottomArea } = useSafeAreaInsets();
// callbacks
const handlePresentPress = useCallback(() => {
- bottomSheetRef.current!.present();
+ bottomSheetRef.current?.present();
}, []);
const handleDismissPress = useCallback(() => {
- bottomSheetRef.current!.dismiss();
+ bottomSheetRef.current?.dismiss();
}, []);
const handleClosePress = useCallback(() => {
bottomSheetRef.current?.close();
}, []);
+ const handleResizePress = useCallback(() => {
+ setCount(state => (state === 2 ? 4 : 2));
+ }, []);
// renders
const renderHeaderHandle = useCallback(
- props => ,
+ (props: BottomSheetHandleProps) => (
+ Detached Example
+ ),
[]
);
const renderItem = useCallback(
- (item, index) => (
+ (item: Contact, index: number) => (
{
[]
);
const renderFooter = useCallback(
- props => (
+ (props: BottomSheetFooterProps) => (
-
- this is a footer!
-
+
),
- []
+ [handleResizePress]
);
return (
@@ -73,10 +81,7 @@ const DetachedExample = () => {
{
{data.map(renderItem)}
@@ -118,13 +122,13 @@ const styles = StyleSheet.create({
contentContainerStyle: {
paddingTop: 12,
paddingBottom: 12,
- paddingHorizontal: 16,
+ paddingHorizontal: 12,
},
footer: {
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 12,
- padding: 12,
+ padding: 6,
marginBottom: 12,
borderRadius: 24,
backgroundColor: '#80f',
diff --git a/example/src/screens/modal/DynamicSizingExample.tsx b/example/src/screens/modal/DynamicSizingExample.tsx
new file mode 100644
index 000000000..9702f7406
--- /dev/null
+++ b/example/src/screens/modal/DynamicSizingExample.tsx
@@ -0,0 +1,149 @@
+import {
+ BottomSheetFooter,
+ type BottomSheetFooterProps,
+ BottomSheetModal,
+ BottomSheetScrollView,
+ type SNAP_POINT_TYPE,
+} from '@gorhom/bottom-sheet';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import { Button } from '../../components/button';
+import { ContactItem } from '../../components/contactItem';
+import { createContactListMockData } from '../../utilities/createMockData';
+import { withModalProvider } from './withModalProvider';
+
+const DATA = createContactListMockData(20);
+
+const DynamicSizingExample = () => {
+ //#region state
+ const [count, setCount] = useState(1);
+ const [maxHeight, setMaxHeight] = useState();
+ //#endregion
+
+ //#region variable
+ const data = useMemo(() => DATA.slice(0, count), [count]);
+ //#endregion
+
+ //#region hooks
+ const { bottom: safeBottomArea } = useSafeAreaInsets();
+ const bottomSheetRef = useRef(null);
+ //#endregion
+
+ //#region callbacks
+ const handleIncreaseContentPress = useCallback(() => {
+ setCount(state => state + 1);
+ }, []);
+ const handleDecreaseContentPress = useCallback(() => {
+ setCount(state => Math.max(state - 1, 1));
+ }, []);
+ const handleSetMaxHeight = useCallback(() => {
+ setMaxHeight(state => (state ? undefined : 500));
+ }, []);
+ const handlePresentPress = useCallback(() => {
+ bottomSheetRef.current?.present();
+ }, []);
+ const handleDismissPress = useCallback(() => {
+ bottomSheetRef.current?.dismiss();
+ }, []);
+ const handleSheetChange = useCallback(
+ (index: number, position: number, type: SNAP_POINT_TYPE) => {
+ // biome-ignore lint/suspicious/noConsole:
+ console.log('handleSheetChange', { index, position, type });
+ },
+ []
+ );
+ //#endregion
+
+ //#region styles
+ const footerContainerStyle = useMemo(
+ () => ({
+ ...styles.footerContainer,
+ paddingBottom: safeBottomArea || 6,
+ }),
+ [safeBottomArea]
+ );
+ //#endregion
+
+ //#region renders
+ const footerComponent = useMemo(
+ () => (props: BottomSheetFooterProps) => (
+
+
+
+
+ ),
+ [
+ footerContainerStyle,
+ handleIncreaseContentPress,
+ handleDecreaseContentPress,
+ ]
+ );
+ return (
+
+
+
+
+
+
+ {data.map(item => (
+
+ ))}
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ },
+ contentContainerStyle: {
+ paddingTop: 12,
+ paddingHorizontal: 24,
+ backgroundColor: 'white',
+ },
+ message: {
+ fontSize: 24,
+ fontWeight: '600',
+ marginBottom: 12,
+ color: 'black',
+ },
+ footerContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ gap: 12,
+ paddingHorizontal: 24,
+ },
+ footerButton: {
+ flex: 1,
+ },
+});
+
+export default withModalProvider(DynamicSizingExample);
diff --git a/example/app/src/screens/modal/SimpleExample.tsx b/example/src/screens/modal/SimpleExample.tsx
similarity index 93%
rename from example/app/src/screens/modal/SimpleExample.tsx
rename to example/src/screens/modal/SimpleExample.tsx
index 15b55dd2f..09febfa25 100644
--- a/example/app/src/screens/modal/SimpleExample.tsx
+++ b/example/src/screens/modal/SimpleExample.tsx
@@ -1,6 +1,6 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { View, StyleSheet } from 'react-native';
-import { BottomSheetModal } from '@gorhom/bottom-sheet';
+import { BottomSheetHandleProps, BottomSheetModal } from '@gorhom/bottom-sheet';
import { Button } from '../../components/button';
import { ContactList } from '../../components/contactList';
import { HeaderHandle } from '../../components/headerHandle';
@@ -52,7 +52,9 @@ export const SimpleExample = () => {
// renders
const renderHeaderHandle = useCallback(
- props => ,
+ (props: BottomSheetHandleProps) => (
+
+ ),
[]
);
return (
@@ -79,6 +81,7 @@ export const SimpleExample = () => {
snapPoints={snapPoints}
enablePanDownToClose={enablePanDownToClose}
enableDismissOnClose={enableDismissOnClose}
+ enableDynamicSizing={false}
onDismiss={handleDismiss}
onChange={handleChange}
handleComponent={renderHeaderHandle}
diff --git a/example/app/src/screens/modal/StackExample.tsx b/example/src/screens/modal/StackExample.tsx
similarity index 90%
rename from example/app/src/screens/modal/StackExample.tsx
rename to example/src/screens/modal/StackExample.tsx
index 9bb044987..a1e53e63e 100644
--- a/example/app/src/screens/modal/StackExample.tsx
+++ b/example/src/screens/modal/StackExample.tsx
@@ -1,6 +1,10 @@
import React, { useCallback, useMemo, useRef } from 'react';
import { View, StyleSheet } from 'react-native';
-import { BottomSheetModal, useBottomSheetModal } from '@gorhom/bottom-sheet';
+import {
+ BottomSheetHandleProps,
+ BottomSheetModal,
+ useBottomSheetModal,
+} from '@gorhom/bottom-sheet';
import { Button } from '../../components/button';
import { ContactList } from '../../components/contactList';
import { HeaderHandle } from '../../components/headerHandle';
@@ -58,12 +62,14 @@ const StackExample = () => {
// renders
const renderHeaderHandle = useCallback(
- (title: string) => (props: any) =>
+ (title: string) => (props: BottomSheetHandleProps) =>
,
[]
);
const renderBottomSheetContent = useCallback(
- onPress => ,
+ (onPress: () => void) => (
+
+ ),
[]
);
return (
@@ -81,6 +87,7 @@ const StackExample = () => {
name="A"
ref={bottomSheetModalARef}
snapPoints={snapPoints}
+ enableDynamicSizing={false}
handleComponent={renderHeaderHandle('Modal A')}
children={renderBottomSheetContent(handlePresentBPress)}
/>
@@ -89,6 +96,7 @@ const StackExample = () => {
name="B"
ref={bottomSheetModalBRef}
snapPoints={snapPoints}
+ enableDynamicSizing={false}
handleComponent={renderHeaderHandle('Modal B')}
children={renderBottomSheetContent(handlePresentCPress)}
/>
@@ -98,6 +106,7 @@ const StackExample = () => {
ref={bottomSheetModalCRef}
index={1}
snapPoints={snapPoints}
+ enableDynamicSizing={false}
enablePanDownToClose={false}
handleComponent={renderHeaderHandle('Modal C')}
children={renderBottomSheetContent(handleDismissCPress)}
diff --git a/example/app/src/screens/modal/withModalProvider.tsx b/example/src/screens/modal/withModalProvider.tsx
similarity index 100%
rename from example/app/src/screens/modal/withModalProvider.tsx
rename to example/src/screens/modal/withModalProvider.tsx
diff --git a/example/src/screens/withGestureHandlerRoot.tsx b/example/src/screens/withGestureHandlerRoot.tsx
new file mode 100644
index 000000000..c044d8354
--- /dev/null
+++ b/example/src/screens/withGestureHandlerRoot.tsx
@@ -0,0 +1,16 @@
+import React, { FC } from 'react';
+import { StyleSheet } from 'react-native';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
+
+export const withGestureHandlerRoot = (Component: FC) => () =>
+ (
+
+
+
+ );
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+});
diff --git a/example/app/src/types.d.ts b/example/src/types.d.ts
similarity index 100%
rename from example/app/src/types.d.ts
rename to example/src/types.d.ts
diff --git a/example/app/src/utilities/createMockData.ts b/example/src/utilities/createMockData.ts
similarity index 100%
rename from example/app/src/utilities/createMockData.ts
rename to example/src/utilities/createMockData.ts
diff --git a/example/app/src/utilities/transformOrigin.ts b/example/src/utilities/transformOrigin.ts
similarity index 100%
rename from example/app/src/utilities/transformOrigin.ts
rename to example/src/utilities/transformOrigin.ts
diff --git a/example/tsconfig.json b/example/tsconfig.json
new file mode 100644
index 000000000..fb7c518ea
--- /dev/null
+++ b/example/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "expo/tsconfig.base",
+ "compilerOptions": {
+ "strict": true,
+ "paths": {
+ "@gorhom/bottom-sheet": ["../src/index"]
+ },
+ }
+}
diff --git a/example/web/index.html b/example/web/index.html
new file mode 100644
index 000000000..b98004386
--- /dev/null
+++ b/example/web/index.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+ %WEB_TITLE%
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/webpack.config.js b/example/webpack.config.js
new file mode 100644
index 000000000..b5e6418a0
--- /dev/null
+++ b/example/webpack.config.js
@@ -0,0 +1,40 @@
+const createExpoWebpackConfigAsync = require('@expo/webpack-config');
+const path = require('path');
+
+const root = path.resolve(__dirname, '..');
+const node_modules = path.join(__dirname, 'node_modules');
+
+module.exports = async function (env, argv) {
+ const config = await createExpoWebpackConfigAsync(
+ {
+ ...env,
+ babel: {
+ dangerouslyAddModulePathsToTranspile: ['react-native-reanimated'],
+ },
+ },
+ argv
+ );
+
+ config.module.rules.push({
+ test: /\.(js|jsx|ts|tsx)$/,
+ include: path.resolve(root, 'src'),
+ use: 'babel-loader',
+ });
+
+ Object.assign(config.resolve.alias, {
+ react: path.join(node_modules, 'react'),
+ 'react-native': path.join(node_modules, 'react-native'),
+ 'react-native-web': path.join(node_modules, 'react-native-web'),
+ 'react-native-reanimated': path.join(
+ node_modules,
+ 'react-native-reanimated'
+ ),
+ 'react-native-gesture-handler': path.join(
+ node_modules,
+ 'react-native-gesture-handler'
+ ),
+ });
+
+ // Customize the config before returning it.
+ return config;
+};
diff --git a/lint-staged.config.js b/lint-staged.config.js
index 8efb35dc5..46f6524be 100644
--- a/lint-staged.config.js
+++ b/lint-staged.config.js
@@ -1,4 +1,13 @@
module.exports = {
- '**/*.js': ['eslint'],
- '**/*.{ts,tsx}': [() => 'tsc --skipLibCheck --noEmit', 'eslint'],
+ '*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}': [
+ 'biome check --files-ignore-unknown=true', // Check formatting and lint
+ 'biome check --write --no-errors-on-unmatched', // Format, sort imports, lint, and apply safe fixes
+ 'biome check --write --organize-imports-enabled=false --no-errors-on-unmatched', // format and apply safe fixes
+ 'biome check --write --unsafe --no-errors-on-unmatched', // Format, sort imports, lints, apply safe/unsafe fixes
+ 'biome format --write --no-errors-on-unmatched', // Format
+ 'biome lint --write --no-errors-on-unmatched', // Lint and apply safe fixes
+ ],
+ '*': [
+ 'biome check --no-errors-on-unmatched --files-ignore-unknown=true', // Check formatting and lint
+ ],
};
diff --git a/mock.js b/mock.js
index d4c85a791..b346057c5 100644
--- a/mock.js
+++ b/mock.js
@@ -9,9 +9,10 @@
*/
const React = require('react');
+const ReactNative = require('react-native');
const NOOP = () => {};
-const NOOP_VALUE = { value: 0 };
+const NOOP_VALUE = { value: 0, set: NOOP, get: () => 0 };
const BottomSheetModalProvider = ({ children }) => {
return children;
@@ -104,10 +105,16 @@ const useBottomSheetDynamicSnapPoints = () => ({
module.exports = {
BottomSheetView: BottomSheetComponent,
- BottomSheetScrollView: BottomSheetComponent,
- BottomSheetSectionList: BottomSheetComponent,
- BottomSheetFlatList: BottomSheetComponent,
- BottomSheetVirtualizedList: BottomSheetComponent,
+ BottomSheetTextInput: ReactNative.TextInput,
+ BottomSheetScrollView: ReactNative.ScrollView,
+ BottomSheetSectionList: ReactNative.SectionList,
+ BottomSheetFlatList: ReactNative.FlatList,
+ BottomSheetFlashList: ReactNative.FlatList,
+ BottomSheetVirtualizedList: ReactNative.VirtualizedList,
+
+ TouchableOpacity: ReactNative.TouchableOpacity,
+ TouchableHighlight: ReactNative.TouchableHighlight,
+ TouchableWithoutFeedback: ReactNative.TouchableWithoutFeedback,
BottomSheetModalProvider,
BottomSheetModal,
diff --git a/package.json b/package.json
index 362ad2e9f..011fee167 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,9 @@
{
- "name": "@gorhom/bottom-sheet",
- "version": "4.4.5",
+ "name": "@discord/bottom-sheet",
+ "version": "5.0.6",
"description": "A performant interactive bottom sheet with fully configurable options 🚀",
- "main": "lib/commonjs/index",
- "module": "lib/module/index",
- "types": "lib/typescript/index.d.ts",
- "react-native": "src/index.ts",
+ "main": "src/index.ts",
+ "source": "src/index.ts",
"files": [
"src",
"lib",
@@ -15,21 +13,22 @@
"react-native",
"ios",
"android",
+ "web",
"bottom-sheet",
"bottomsheet",
"reanimated",
"sheet"
],
- "repository": "https://github.com/gorhom/react-native-bottom-sheet",
+ "repository": "https://github.com/discord/react-native-bottom-sheet",
"author": "Mo Gorhom (https://gorhom.dev)",
"license": "MIT",
"bugs": {
"url": "https://github.com/gorhom/react-native-bottom-sheet/issues"
},
- "homepage": "https://gorhom.github.io/react-native-bottom-sheet",
+ "homepage": "https://gorhom.dev/react-native-bottom-sheet/",
"scripts": {
"typescript": "tsc --skipLibCheck --noEmit",
- "lint": "eslint \"**/*.{js,ts,tsx}\"",
+ "lint": "biome lint --error-on-warnings ./src",
"build": "bob build && yarn copy-dts && yarn delete-dts.js && yarn delete-debug-view",
"copy-dts": "copyfiles -u 1 \"src/**/*.d.ts\" lib/typescript",
"delete-debug-view": "rm -r ./lib/commonjs/components/bottomSheetDebugView && rm -r ./lib/module/components/bottomSheetDebugView && rm -r ./lib/typescript/components/bottomSheetDebugView",
@@ -43,42 +42,44 @@
"invariant": "^2.2.4"
},
"devDependencies": {
- "@commitlint/cli": "^17.1.2",
- "@commitlint/config-conventional": "^17.1.0",
- "@react-native-community/eslint-config": "^3.0.0",
- "@release-it/conventional-changelog": "^5.1.0",
+ "@commitlint/cli": "^17.6.5",
+ "@commitlint/config-conventional": "^17.6.5",
+ "@release-it/conventional-changelog": "^8.0.1",
"@types/invariant": "^2.2.34",
- "@types/react": "17.0.2",
- "@types/react-native": "^0.67.7",
- "auto-changelog": "^2.4.0",
+ "@types/react": "~18.3.12",
+ "@types/react-native": "~0.73.0",
"copyfiles": "^2.4.1",
- "eslint": "^7.32.0",
- "eslint-config-prettier": "^8.3.0",
- "eslint-plugin-prettier": "^3.4.0",
"husky": "^4.3.8",
- "lint-staged": "^11.1.2",
- "prettier": "^2.3.2",
- "react": "~16.9.0",
- "react-native": "^0.62.2",
- "react-native-builder-bob": "^0.18.1",
- "react-native-gesture-handler": "^1.10.3",
- "react-native-reanimated": "^2.8.0",
- "release-it": "^15.4.2",
- "typescript": "^4.2.4"
+ "lint-staged": "^13.2.2",
+ "metro-react-native-babel-preset": "^0.77.0",
+ "react": "18.3.1",
+ "react-native": "0.76.0",
+ "react-native-builder-bob": "^0.30.3",
+ "react-native-gesture-handler": "~2.20.2",
+ "react-native-reanimated": "~3.16.1",
+ "release-it": "^17.6.0",
+ "typescript": "^5.3.0"
},
"peerDependencies": {
+ "@types/react": "*",
+ "@types/react-native": "*",
+ "@shopify/flash-list": "*",
"react": "*",
"react-native": "*",
- "react-native-gesture-handler": ">=1.10.1",
- "react-native-reanimated": ">=2.2.0"
+ "react-native-gesture-handler": ">=2.16.1",
+ "react-native-reanimated": ">=3.16.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react-native": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
},
"react-native-builder-bob": {
"source": "src",
"output": "lib",
- "targets": [
- "commonjs",
- "module",
- "typescript"
- ]
+ "targets": ["commonjs", "module", "typescript"]
}
}
diff --git a/scripts/auto-changelog.js b/scripts/auto-changelog.js
deleted file mode 100644
index 24322e430..000000000
--- a/scripts/auto-changelog.js
+++ /dev/null
@@ -1,44 +0,0 @@
-module.exports = function (Handlebars) {
- Handlebars.registerHelper(
- 'custom',
- function (context, merges, fixes, options) {
- if (
- (!context || context.length === 0) &&
- (!merges || merges.length === 0) &&
- (!fixes || fixes.length === 0)
- ) {
- return '';
- }
-
- const list = [...context, ...(merges || []), ...(fixes || [])]
- .filter(item => {
- const commit = item.commit || item;
- if (options.hash.exclude) {
- const pattern = new RegExp(options.hash.exclude, 'm');
- if (pattern.test(commit.message)) {
- return false;
- }
- }
- if (options.hash.message) {
- const pattern = new RegExp(options.hash.message, 'm');
- return pattern.test(commit.message);
- }
- if (options.hash.subject) {
- const pattern = new RegExp(options.hash.subject);
- return pattern.test(commit.subject);
- }
- return true;
- })
- .map(item => options.fn(item.commit || item))
- .join('');
-
- if (!list) {
- return '';
- }
-
- return options.hash.heading
- ? `${options.hash.heading}\n\n${list}`
- : `${list}`;
- }
- );
-};
diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx
index b16644070..255458795 100644
--- a/src/components/bottomSheet/BottomSheet.tsx
+++ b/src/components/bottomSheet/BottomSheet.tsx
@@ -1,3 +1,4 @@
+import invariant from 'invariant';
import React, {
useMemo,
useCallback,
@@ -6,8 +7,8 @@ import React, {
memo,
useEffect,
} from 'react';
-import { Platform } from 'react-native';
-import invariant from 'invariant';
+import { type Insets, Platform } from 'react-native';
+import { State } from 'react-native-gesture-handler';
import Animated, {
useAnimatedReaction,
useSharedValue,
@@ -15,69 +16,76 @@ import Animated, {
useDerivedValue,
runOnJS,
interpolate,
- Extrapolate,
+ Extrapolation,
runOnUI,
cancelAnimation,
useWorkletCallback,
- WithSpringConfig,
- WithTimingConfig,
+ type WithSpringConfig,
+ type WithTimingConfig,
+ type SharedValue,
+ useReducedMotion,
+ ReduceMotion,
} from 'react-native-reanimated';
-import { State } from 'react-native-gesture-handler';
-import {
- useScrollable,
- usePropsValidator,
- useReactiveSharedValue,
- useNormalizedSnapPoints,
- useKeyboard,
-} from '../../hooks';
-import {
- BottomSheetInternalProvider,
- BottomSheetProvider,
-} from '../../contexts';
-import BottomSheetContainer from '../bottomSheetContainer';
-import BottomSheetGestureHandlersProvider from '../bottomSheetGestureHandlersProvider';
-import BottomSheetBackdropContainer from '../bottomSheetBackdropContainer';
-import BottomSheetHandleContainer from '../bottomSheetHandleContainer';
-import BottomSheetBackgroundContainer from '../bottomSheetBackgroundContainer';
-import BottomSheetFooterContainer from '../bottomSheetFooterContainer/BottomSheetFooterContainer';
-import BottomSheetDraggableView from '../bottomSheetDraggableView';
-// import BottomSheetDebugView from '../bottomSheetDebugView';
import {
+ ANIMATION_SOURCE,
ANIMATION_STATE,
- KEYBOARD_STATE,
KEYBOARD_BEHAVIOR,
- SHEET_STATE,
- SCROLLABLE_STATE,
KEYBOARD_BLUR_BEHAVIOR,
KEYBOARD_INPUT_MODE,
- ANIMATION_SOURCE,
+ KEYBOARD_STATE,
+ SCROLLABLE_STATE,
+ SHEET_STATE,
+ SNAP_POINT_TYPE,
} from '../../constants';
+import {
+ BottomSheetInternalProvider,
+ BottomSheetProvider,
+} from '../../contexts';
+import type { BottomSheetInternalContextType } from '../../contexts/internal';
+import {
+ useAnimatedSnapPoints,
+ useKeyboard,
+ usePropsValidator,
+ useReactiveSharedValue,
+ useScrollable,
+} from '../../hooks';
+import type { BottomSheetMethods } from '../../types';
import {
animate,
getKeyboardAnimationConfigs,
normalizeSnapPoint,
print,
} from '../../utilities';
+import BottomSheetBackdropContainer from '../bottomSheetBackdropContainer';
+import BottomSheetBackgroundContainer from '../bottomSheetBackgroundContainer';
+import BottomSheetContainer from '../bottomSheetContainer';
+// import BottomSheetDebugView from '../bottomSheetDebugView';
+import BottomSheetDraggableView from '../bottomSheetDraggableView';
+import BottomSheetFooterContainer from '../bottomSheetFooterContainer/BottomSheetFooterContainer';
+import BottomSheetGestureHandlersProvider from '../bottomSheetGestureHandlersProvider';
+import BottomSheetHandleContainer from '../bottomSheetHandleContainer';
import {
- DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_ROLE,
+ DEFAULT_ACCESSIBLE,
+ DEFAULT_ANIMATE_ON_MOUNT,
+ DEFAULT_DYNAMIC_SIZING,
DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,
- DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
DEFAULT_ENABLE_OVER_DRAG,
- DEFAULT_ANIMATE_ON_MOUNT,
+ DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
DEFAULT_KEYBOARD_BEHAVIOR,
DEFAULT_KEYBOARD_BLUR_BEHAVIOR,
DEFAULT_KEYBOARD_INPUT_MODE,
+ DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
INITIAL_CONTAINER_HEIGHT,
+ INITIAL_CONTAINER_OFFSET,
INITIAL_HANDLE_HEIGHT,
INITIAL_POSITION,
INITIAL_SNAP_POINT,
- DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
- INITIAL_CONTAINER_OFFSET,
INITIAL_VALUE,
} from './constants';
-import type { BottomSheetMethods, Insets } from '../../types';
-import type { BottomSheetProps, AnimateToPositionType } from './types';
import { styles } from './styles';
+import type { AnimateToPositionType, BottomSheetProps } from './types';
Animated.addWhitelistedUIProps({
decelerationRate: true,
@@ -87,10 +95,6 @@ type BottomSheet = BottomSheetMethods;
const BottomSheetComponent = forwardRef(
function BottomSheet(props, ref) {
- //#region validate props
- usePropsValidator(props);
- //#endregion
-
//#region extract props
const {
// animations configurations
@@ -99,12 +103,15 @@ const BottomSheetComponent = forwardRef(
// configurations
index: _providedIndex = 0,
snapPoints: _providedSnapPoints,
+ initialPosition = INITIAL_POSITION,
animateOnMount = DEFAULT_ANIMATE_ON_MOUNT,
enableContentPanningGesture = DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,
- enableHandlePanningGesture = DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
+ enableHandlePanningGesture,
enableOverDrag = DEFAULT_ENABLE_OVER_DRAG,
enablePanDownToClose = DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
+ enableDynamicSizing = DEFAULT_DYNAMIC_SIZING,
overDragResistanceFactor = DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
+ overrideReduceMotion: _providedOverrideReduceMotion,
// styles
style: _providedStyle,
@@ -122,12 +129,13 @@ const BottomSheetComponent = forwardRef(
android_keyboardInputMode = DEFAULT_KEYBOARD_INPUT_MODE,
// layout
- handleHeight: _providedHandleHeight,
containerHeight: _providedContainerHeight,
- contentHeight: _providedContentHeight,
containerOffset: _providedContainerOffset,
topInset = 0,
bottomInset = 0,
+ maxDynamicContentSize,
+ contentHeight: _providedContentHeight,
+ handleHeight: _providedHandleHeight,
// animated callback shared values
animatedPosition: _providedAnimatedPosition,
@@ -154,11 +162,31 @@ const BottomSheetComponent = forwardRef(
handleComponent,
backdropComponent,
backgroundComponent,
- footerComponent,
- children: Content,
+ renderFooter,
+ children,
+
+ // accessibility
+ accessible: _providedAccessible = DEFAULT_ACCESSIBLE,
+ accessibilityLabel:
+ _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
+ accessibilityRole:
+ _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
} = props;
//#endregion
+ //#region validate props
+ if (__DEV__) {
+ // biome-ignore lint/correctness/useHookAtTopLevel: used in development only.
+ usePropsValidator({
+ index: _providedIndex,
+ snapPoints: _providedSnapPoints,
+ enableDynamicSizing,
+ topInset,
+ bottomInset,
+ });
+ }
+ //#endregion
+
//#region layout variables
/**
* This variable is consider an internal variable,
@@ -177,23 +205,28 @@ const BottomSheetComponent = forwardRef(
return $modal
? _animatedContainerHeight.value - verticalInset
: _animatedContainerHeight.value;
- }, [$modal, topInset, bottomInset]);
+ }, [topInset, bottomInset, $modal, _animatedContainerHeight]);
const animatedContainerOffset = useReactiveSharedValue(
_providedContainerOffset ?? INITIAL_CONTAINER_OFFSET
- ) as Animated.SharedValue;
- const animatedHandleHeight = useReactiveSharedValue(
+ ) as SharedValue>;
+ const animatedHandleHeight = useReactiveSharedValue(
_providedHandleHeight ?? INITIAL_HANDLE_HEIGHT
);
const animatedFooterHeight = useSharedValue(0);
- const animatedSnapPoints = useNormalizedSnapPoints(
- _providedSnapPoints,
- animatedContainerHeight,
- topInset,
- bottomInset,
- $modal
- );
+ const animatedContentHeight = useSharedValue(_providedContentHeight ?? INITIAL_CONTAINER_HEIGHT);
+ const [animatedSnapPoints, animatedDynamicSnapPointIndex] =
+ useAnimatedSnapPoints(
+ _providedSnapPoints,
+ animatedContainerHeight,
+ animatedContentHeight,
+ animatedHandleHeight,
+ animatedFooterHeight,
+ enableDynamicSizing,
+ maxDynamicContentSize
+ );
const animatedHighestSnapPoint = useDerivedValue(
- () => animatedSnapPoints.value[animatedSnapPoints.value.length - 1]
+ () => animatedSnapPoints.value[animatedSnapPoints.value.length - 1],
+ [animatedSnapPoints]
);
const animatedClosedPosition = useDerivedValue(() => {
let closedPosition = animatedContainerHeight.value;
@@ -203,16 +236,17 @@ const BottomSheetComponent = forwardRef(
}
return closedPosition;
- }, [$modal, detached, bottomInset]);
+ }, [animatedContainerHeight, $modal, detached, bottomInset]);
const animatedSheetHeight = useDerivedValue(
- () => animatedContainerHeight.value - animatedHighestSnapPoint.value
+ () => animatedContainerHeight.value - animatedHighestSnapPoint.value,
+ [animatedContainerHeight, animatedHighestSnapPoint]
);
const animatedCurrentIndex = useReactiveSharedValue(
animateOnMount ? -1 : _providedIndex
);
- const animatedPosition = useSharedValue(INITIAL_POSITION);
+ const animatedPosition = useSharedValue(initialPosition);
const animatedNextPosition = useSharedValue(INITIAL_VALUE);
- const animatedNextPositionIndex = useSharedValue(0);
+ const animatedNextPositionIndex = useSharedValue(INITIAL_VALUE);
// conditional
const isAnimatedOnMount = useSharedValue(false);
@@ -232,14 +266,6 @@ const BottomSheetComponent = forwardRef(
}
let isHandleHeightCalculated = false;
- // handle height is provided.
- if (
- _providedHandleHeight !== null &&
- _providedHandleHeight !== undefined &&
- typeof _providedHandleHeight === 'number'
- ) {
- isHandleHeightCalculated = true;
- }
// handle component is null.
if (handleComponent === null) {
animatedHandleHeight.value = 0;
@@ -261,9 +287,16 @@ const BottomSheetComponent = forwardRef(
isHandleHeightCalculated &&
isSnapPointsNormalized
);
- });
+ }, [
+ _providedContainerHeight,
+ animatedContainerHeight,
+ animatedHandleHeight,
+ animatedSnapPoints,
+ handleComponent,
+ ]);
const isInTemporaryPosition = useSharedValue(false);
const isForcedClosing = useSharedValue(false);
+ const animatedContainerHeightDidChange = useSharedValue(false);
// gesture
const animatedContentGestureState = useSharedValue(
@@ -281,6 +314,8 @@ const BottomSheetComponent = forwardRef(
animatedScrollableContentOffsetY,
animatedScrollableOverrideState,
isScrollableRefreshable,
+ isScrollableLocked,
+ isScrollEnded,
setScrollableRef,
removeScrollableRef,
} = useScrollable();
@@ -293,6 +328,13 @@ const BottomSheetComponent = forwardRef(
shouldHandleKeyboardEvents,
} = useKeyboard();
const animatedKeyboardHeightInContainer = useSharedValue(0);
+ const userReduceMotionSetting = useReducedMotion();
+ const reduceMotion = useMemo(() => {
+ return !_providedOverrideReduceMotion ||
+ _providedOverrideReduceMotion === ReduceMotion.System
+ ? userReduceMotionSetting
+ : _providedOverrideReduceMotion === ReduceMotion.Always;
+ }, [userReduceMotionSetting, _providedOverrideReduceMotion]);
//#endregion
//#region state/dynamic variables
@@ -303,14 +345,16 @@ const BottomSheetComponent = forwardRef(
);
const animatedSheetState = useDerivedValue(() => {
// closed position = position >= container height
- if (animatedPosition.value >= animatedClosedPosition.value)
+ if (animatedPosition.value >= animatedClosedPosition.value) {
return SHEET_STATE.CLOSED;
+ }
// extended position = container height - sheet height
const extendedPosition =
animatedContainerHeight.value - animatedSheetHeight.value;
- if (animatedPosition.value === extendedPosition)
+ if (animatedPosition.value === extendedPosition) {
return SHEET_STATE.EXTENDED;
+ }
// extended position with keyboard =
// container height - (sheet height + keyboard height in root container)
@@ -350,7 +394,15 @@ const BottomSheetComponent = forwardRef(
isInTemporaryPosition,
keyboardBehavior,
]);
- const animatedScrollableState = useDerivedValue(() => {
+ const animatedScrollableState = useDerivedValue(() => {
+ /**
+ * if user had disabled content panning gesture, then we unlock
+ * the scrollable state.
+ */
+ if (!enableContentPanningGesture) {
+ return SCROLLABLE_STATE.UNLOCKED;
+ }
+
/**
* if scrollable override state is set, then we just return its value.
*/
@@ -373,6 +425,13 @@ const BottomSheetComponent = forwardRef(
return SCROLLABLE_STATE.UNLOCKED;
}
+ /**
+ * if the current scrollable is blocked from translation, unlock scrolling
+ */
+ if (!isScrollableLocked.value) {
+ return SCROLLABLE_STATE.UNLOCKED;
+ }
+
/**
* if keyboard is shown and sheet is animating
* then we do not lock the scrolling to not lose
@@ -386,9 +445,15 @@ const BottomSheetComponent = forwardRef(
}
return SCROLLABLE_STATE.LOCKED;
- });
+ }, [
+ enableContentPanningGesture,
+ animatedAnimationState,
+ animatedKeyboardState,
+ animatedScrollableOverrideState,
+ animatedSheetState,
+ ]);
// dynamic
- const animatedContentHeight = useDerivedValue(() => {
+ const animatedContentHeightMax = useDerivedValue(() => {
const keyboardHeightInContainer = animatedKeyboardHeightInContainer.value;
const handleHeight = Math.max(0, animatedHandleHeight.value);
let contentHeight = animatedSheetHeight.value - handleHeight;
@@ -457,7 +522,7 @@ const BottomSheetComponent = forwardRef(
const adjustedSnapPoints = animatedSnapPoints.value.slice().reverse();
const adjustedSnapPointsIndexes = animatedSnapPoints.value
.slice()
- .map((_: any, index: number) => index)
+ .map((_, index: number) => index)
.reverse();
/**
@@ -471,7 +536,7 @@ const BottomSheetComponent = forwardRef(
animatedPosition.value,
adjustedSnapPoints,
adjustedSnapPointsIndexes,
- Extrapolate.CLAMP
+ Extrapolation.CLAMP
)
: -1;
@@ -500,15 +565,239 @@ const BottomSheetComponent = forwardRef(
}
return currentIndex;
- }, [android_keyboardInputMode]);
+ }, [
+ android_keyboardInputMode,
+ animatedAnimationSource,
+ animatedAnimationState,
+ animatedContainerHeight,
+ animatedCurrentIndex,
+ animatedNextPositionIndex,
+ animatedPosition,
+ animatedSnapPoints,
+ isInTemporaryPosition,
+ isLayoutCalculated,
+ ]);
+ //#endregion
+
+ //#region private methods
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
+ const handleOnChange = useCallback(
+ function handleOnChange(index: number, position: number) {
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleOnChange.name,
+ category: 'callback',
+ params: {
+ index,
+ animatedCurrentIndex: animatedCurrentIndex.value,
+ },
+ });
+ }
+
+ if (!_providedOnChange) {
+ return;
+ }
+
+ _providedOnChange(
+ index,
+ position,
+ index === animatedDynamicSnapPointIndex.value
+ ? SNAP_POINT_TYPE.DYNAMIC
+ : SNAP_POINT_TYPE.PROVIDED
+ );
+ },
+ [_providedOnChange, animatedCurrentIndex, animatedDynamicSnapPointIndex]
+ );
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
+ const handleOnAnimate = useCallback(
+ function handleOnAnimate(targetIndex: number, source: ANIMATION_SOURCE) {
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleOnAnimate.name,
+ category: 'callback',
+ params: {
+ toIndex: targetIndex,
+ fromIndex: animatedCurrentIndex.value,
+ },
+ });
+ }
+
+ if (!_providedOnAnimate) {
+ return;
+ }
+
+ _providedOnAnimate(animatedCurrentIndex.value, targetIndex, source);
+ },
+ [_providedOnAnimate, animatedCurrentIndex]
+ );
+ //#endregion
+
+ //#region animation
+ const stopAnimation = useWorkletCallback(() => {
+ cancelAnimation(animatedPosition);
+ animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
+ animatedAnimationState.value = ANIMATION_STATE.STOPPED;
+ }, [animatedPosition, animatedAnimationState, animatedAnimationSource]);
+ const animateToPositionCompleted = useWorkletCallback(
+ function animateToPositionCompleted(isFinished?: boolean) {
+ if (!isFinished) {
+ return;
+ }
+
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: animateToPositionCompleted.name,
+ params: {
+ animatedCurrentIndex: animatedCurrentIndex.value,
+ animatedNextPosition: animatedNextPosition.value,
+ animatedNextPositionIndex: animatedNextPositionIndex.value,
+ },
+ });
+ }
+
+ if (animatedAnimationSource.value === ANIMATION_SOURCE.MOUNT) {
+ isAnimatedOnMount.value = true;
+ }
+
+ // reset values
+ isForcedClosing.value = false;
+ animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
+ animatedAnimationState.value = ANIMATION_STATE.STOPPED;
+ animatedNextPosition.value = INITIAL_VALUE;
+ animatedNextPositionIndex.value = INITIAL_VALUE;
+ animatedContainerHeightDidChange.value = false;
+ }
+ );
+ const animateToPosition: AnimateToPositionType = useWorkletCallback(
+ function animateToPosition(
+ position: number,
+ source: ANIMATION_SOURCE,
+ velocity = 0,
+ configs?: WithTimingConfig | WithSpringConfig
+ ) {
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: animateToPosition.name,
+ params: {
+ currentPosition: animatedPosition.value,
+ nextPosition: position,
+ },
+ });
+ }
+
+ if (
+ position === animatedPosition.value ||
+ position === undefined ||
+ (animatedAnimationState.value === ANIMATION_STATE.RUNNING &&
+ position === animatedNextPosition.value)
+ ) {
+ return;
+ }
+
+ // stop animation if it is running
+ if (animatedAnimationState.value === ANIMATION_STATE.RUNNING) {
+ stopAnimation();
+ }
+
+ /**
+ * set animation state to running, and source
+ */
+ animatedAnimationState.value = ANIMATION_STATE.RUNNING;
+ animatedAnimationSource.value = source;
+
+ /**
+ * store next position
+ */
+ animatedNextPosition.value = position;
+
+ /**
+ * offset the position if keyboard is shown
+ */
+ let offset = 0;
+ if (animatedKeyboardState.value === KEYBOARD_STATE.SHOWN) {
+ offset = animatedKeyboardHeightInContainer.value;
+ }
+
+ animatedNextPositionIndex.value = animatedSnapPoints.value.indexOf(
+ position + offset
+ );
+
+ /**
+ * fire `onAnimate` callback
+ */
+ runOnJS(handleOnAnimate)(animatedNextPositionIndex.value, source);
+
+ /**
+ * start animation
+ */
+ animatedPosition.value = animate({
+ point: position,
+ configs: configs || _providedAnimationConfigs,
+ velocity,
+ overrideReduceMotion: _providedOverrideReduceMotion,
+ onComplete: animateToPositionCompleted,
+ });
+ },
+ [
+ handleOnAnimate,
+ _providedAnimationConfigs,
+ _providedOverrideReduceMotion,
+ ]
+ );
+ /**
+ * Set to position without animation.
+ *
+ * @param targetPosition position to be set.
+ */
+ const setToPosition = useWorkletCallback(function setToPosition(
+ targetPosition: number
+ ) {
+ if (
+ targetPosition === animatedPosition.value ||
+ targetPosition === undefined ||
+ (animatedAnimationState.value === ANIMATION_STATE.RUNNING &&
+ targetPosition === animatedNextPosition.value)
+ ) {
+ return;
+ }
+
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: setToPosition.name,
+ params: {
+ currentPosition: animatedPosition.value,
+ targetPosition,
+ },
+ });
+ }
+
+ /**
+ * store next position
+ */
+ animatedNextPosition.value = targetPosition;
+ animatedNextPositionIndex.value =
+ animatedSnapPoints.value.indexOf(targetPosition);
+
+ stopAnimation();
+
+ // set values
+ animatedPosition.value = targetPosition;
+ animatedContainerHeightDidChange.value = false;
+ }, []);
//#endregion
//#region private methods
/**
- * Calculate the next position based on keyboard state.
+ * Calculate and evaluate the current position based on multiple
+ * local states.
*/
- const getNextPosition = useWorkletCallback(
- function getNextPosition() {
+ const getEvaluatedPosition = useWorkletCallback(
+ function getEvaluatedPosition(source: ANIMATION_SOURCE) {
'worklet';
const currentIndex = animatedCurrentIndex.value;
const snapPoints = animatedSnapPoints.value;
@@ -516,9 +805,11 @@ const BottomSheetComponent = forwardRef(
const highestSnapPoint = animatedHighestSnapPoint.value;
/**
- * Handle restore sheet position on blur
+ * if the keyboard blur behavior is restore and keyboard is hidden,
+ * then we return the previous snap point.
*/
if (
+ source === ANIMATION_SOURCE.KEYBOARD &&
keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.restore &&
keyboardState === KEYBOARD_STATE.HIDDEN &&
animatedContentGestureState.value !== State.ACTIVE &&
@@ -530,7 +821,8 @@ const BottomSheetComponent = forwardRef(
}
/**
- * Handle extend behavior
+ * if the keyboard appearance behavior is extend and keyboard is shown,
+ * then we return the heights snap point.
*/
if (
keyboardBehavior === KEYBOARD_BEHAVIOR.extend &&
@@ -540,7 +832,8 @@ const BottomSheetComponent = forwardRef(
}
/**
- * Handle full screen behavior
+ * if the keyboard appearance behavior is fill parent and keyboard is shown,
+ * then we return 0 ( full screen ).
*/
if (
keyboardBehavior === KEYBOARD_BEHAVIOR.fillParent &&
@@ -551,11 +844,18 @@ const BottomSheetComponent = forwardRef(
}
/**
- * handle interactive behavior
+ * if the keyboard appearance behavior is interactive and keyboard is shown,
+ * then we return the heights points minus the keyboard in container height.
*/
if (
keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&
- keyboardState === KEYBOARD_STATE.SHOWN
+ keyboardState === KEYBOARD_STATE.SHOWN &&
+ // ensure that this logic does not run on android
+ // with resize input mode
+ !(
+ Platform.OS === 'android' &&
+ android_keyboardInputMode === 'adjustResize'
+ )
) {
isInTemporaryPosition.value = true;
const keyboardHeightInContainer =
@@ -563,10 +863,27 @@ const BottomSheetComponent = forwardRef(
return Math.max(0, highestSnapPoint - keyboardHeightInContainer);
}
+ /**
+ * if the bottom sheet is in temporary position, then we return
+ * the current position.
+ */
if (isInTemporaryPosition.value) {
return animatedPosition.value;
}
+ /**
+ * if the bottom sheet did not animate on mount,
+ * then we return the provided index or the closed position.
+ */
+ if (!isAnimatedOnMount.value) {
+ return _providedIndex === -1
+ ? animatedClosedPosition.value
+ : snapPoints[_providedIndex];
+ }
+
+ /**
+ * return the current index position.
+ */
return snapPoints[currentIndex];
},
[
@@ -579,156 +896,139 @@ const BottomSheetComponent = forwardRef(
animatedPosition,
animatedSnapPoints,
isInTemporaryPosition,
+ isAnimatedOnMount,
keyboardBehavior,
keyboardBlurBehavior,
+ _providedIndex,
]
);
- const handleOnChange = useCallback(
- function handleOnChange(index: number) {
- print({
- component: BottomSheet.name,
- method: handleOnChange.name,
- params: {
- index,
- animatedCurrentIndex: animatedCurrentIndex.value,
- },
- });
-
- if (_providedOnChange) {
- _providedOnChange(index);
- }
- },
- [_providedOnChange, animatedCurrentIndex]
- );
- const handleOnAnimate = useCallback(
- function handleOnAnimate(toPoint: number) {
- const snapPoints = animatedSnapPoints.value;
- const toIndex = snapPoints.indexOf(toPoint);
-
- print({
- component: BottomSheet.name,
- method: handleOnAnimate.name,
- params: {
- toIndex,
- fromIndex: animatedCurrentIndex.value,
- },
- });
-
- if (!_providedOnAnimate) {
- return;
- }
-
- if (toIndex !== animatedCurrentIndex.value) {
- _providedOnAnimate(animatedCurrentIndex.value, toIndex);
- }
- },
- [_providedOnAnimate, animatedSnapPoints, animatedCurrentIndex]
- );
- //#endregion
-
- //#region animation
- const stopAnimation = useWorkletCallback(() => {
- cancelAnimation(animatedPosition);
- isForcedClosing.value = false;
- animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
- animatedAnimationState.value = ANIMATION_STATE.STOPPED;
- }, [animatedPosition, animatedAnimationState, animatedAnimationSource]);
- const animateToPositionCompleted = useWorkletCallback(
- function animateToPositionCompleted(isFinished?: boolean) {
- isForcedClosing.value = false;
-
- if (!isFinished) {
- return;
- }
- runOnJS(print)({
- component: BottomSheet.name,
- method: animateToPositionCompleted.name,
- params: {
- animatedCurrentIndex: animatedCurrentIndex.value,
- animatedNextPosition: animatedNextPosition.value,
- animatedNextPositionIndex: animatedNextPositionIndex.value,
- },
- });
- animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
- animatedAnimationState.value = ANIMATION_STATE.STOPPED;
- animatedNextPosition.value = INITIAL_VALUE;
- animatedNextPositionIndex.value = INITIAL_VALUE;
- }
- );
- const animateToPosition: AnimateToPositionType = useWorkletCallback(
- function animateToPosition(
- position: number,
- source: ANIMATION_SOURCE,
- velocity: number = 0,
- configs?: WithTimingConfig | WithSpringConfig
- ) {
- if (
- position === animatedPosition.value ||
- position === undefined ||
- (animatedAnimationState.value === ANIMATION_STATE.RUNNING &&
- position === animatedNextPosition.value)
- ) {
+ /**
+ * Evaluate the bottom sheet position based based on a event source and other local states.
+ */
+ const evaluatePosition = useWorkletCallback(
+ function evaluatePosition(
+ source: ANIMATION_SOURCE,
+ animationConfigs?: WithSpringConfig | WithTimingConfig
+ ) {
+ /**
+ * if a force closing is running and source not from user, then we early exit
+ */
+ if (isForcedClosing.value && source !== ANIMATION_SOURCE.USER) {
return;
}
-
- runOnJS(print)({
- component: BottomSheet.name,
- method: animateToPosition.name,
- params: {
- currentPosition: animatedPosition.value,
- position,
- velocity,
- },
- });
-
- stopAnimation();
-
/**
- * set animation state to running, and source
+ * when evaluating the position while layout is not calculated, then we early exit till it is.
*/
- animatedAnimationState.value = ANIMATION_STATE.RUNNING;
- animatedAnimationSource.value = source;
+ if (!isLayoutCalculated.value) {
+ return;
+ }
+
+ const proposedPosition = getEvaluatedPosition(source);
/**
- * store next position
+ * when evaluating the position while the mount animation not been handled,
+ * then we evaluate on mount use cases.
*/
- animatedNextPosition.value = position;
- animatedNextPositionIndex.value =
- animatedSnapPoints.value.indexOf(position);
+ if (!isAnimatedOnMount.value) {
+ /**
+ * if animate on mount is set to true, then we animate to the propose position,
+ * else, we set the position with out animation.
+ */
+ if (animateOnMount) {
+ animateToPosition(
+ proposedPosition,
+ ANIMATION_SOURCE.MOUNT,
+ undefined,
+ animationConfigs
+ );
+ } else {
+ setToPosition(proposedPosition);
+ isAnimatedOnMount.value = true;
+ }
+ return;
+ }
/**
- * fire `onAnimate` callback
+ * when evaluating the position while the bottom sheet is animating.
*/
- runOnJS(handleOnAnimate)(position);
+ if (animatedAnimationState.value === ANIMATION_STATE.RUNNING) {
+ /**
+ * when evaluating the position while the bottom sheet is
+ * closing, then we force closing the bottom sheet with no animation.
+ */
+ if (
+ animatedNextPositionIndex.value === -1 &&
+ !isInTemporaryPosition.value
+ ) {
+ setToPosition(animatedClosedPosition.value);
+ return;
+ }
+
+ /**
+ * when evaluating the position while it's animating to
+ * a position other than the current position, then we
+ * restart the animation.
+ */
+ if (animatedNextPositionIndex.value !== animatedCurrentIndex.value) {
+ animateToPosition(
+ animatedSnapPoints.value[animatedNextPositionIndex.value],
+ source,
+ undefined,
+ animationConfigs
+ );
+ return;
+ }
+ }
/**
- * force animation configs from parameters, if provided
+ * when evaluating the position while the bottom sheet is in closed
+ * position and not animating, we re-set the position to closed position.
*/
- if (configs !== undefined) {
- animatedPosition.value = animate({
- point: position,
- configs,
- velocity,
- onComplete: animateToPositionCompleted,
- });
- } else {
+ if (
+ animatedAnimationState.value !== ANIMATION_STATE.RUNNING &&
+ animatedCurrentIndex.value === -1
+ ) {
/**
- * use animationConfigs callback, if provided
+ * early exit if reduce motion is enabled and index is out of sync with position.
*/
- animatedPosition.value = animate({
- point: position,
- velocity,
- configs: _providedAnimationConfigs,
- onComplete: animateToPositionCompleted,
- });
+ if (
+ reduceMotion &&
+ animatedSnapPoints.value[animatedIndex.value] !==
+ animatedPosition.value
+ ) {
+ return;
+ }
+ setToPosition(animatedClosedPosition.value);
+ return;
}
+
+ /**
+ * when evaluating the position after the container resize, then we
+ * force the bottom sheet to the proposed position with no
+ * animation.
+ */
+ if (animatedContainerHeightDidChange.value) {
+ setToPosition(proposedPosition);
+ return;
+ }
+
+ /**
+ * we fall back to the proposed position.
+ */
+ animateToPosition(
+ proposedPosition,
+ source,
+ undefined,
+ animationConfigs
+ );
},
- [handleOnAnimate, _providedAnimationConfigs]
+ [getEvaluatedPosition, animateToPosition, setToPosition, reduceMotion]
);
//#endregion
//#region public methods
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
const handleSnapToIndex = useCallback(
function handleSnapToIndex(
index: number,
@@ -741,13 +1041,15 @@ const BottomSheetComponent = forwardRef(
snapPoints.length - 1
}`
);
- print({
- component: BottomSheet.name,
- method: handleSnapToIndex.name,
- params: {
- index,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleSnapToIndex.name,
+ params: {
+ index,
+ },
+ });
+ }
const nextPosition = snapPoints[index];
@@ -793,22 +1095,22 @@ const BottomSheetComponent = forwardRef(
position: number | string,
animationConfigs?: WithSpringConfig | WithTimingConfig
) {
- print({
- component: BottomSheet.name,
- method: handleSnapToPosition.name,
- params: {
- position,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleSnapToPosition.name,
+ params: {
+ position,
+ },
+ });
+ }
/**
* normalized provided position.
*/
const nextPosition = normalizeSnapPoint(
position,
- animatedContainerHeight.value,
- topInset,
- bottomInset
+ animatedContainerHeight.value
);
/**
@@ -847,14 +1149,17 @@ const BottomSheetComponent = forwardRef(
animatedPosition,
]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
const handleClose = useCallback(
function handleClose(
animationConfigs?: WithSpringConfig | WithTimingConfig
) {
- print({
- component: BottomSheet.name,
- method: handleClose.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleClose.name,
+ });
+ }
const nextPosition = animatedClosedPosition.value;
@@ -893,14 +1198,17 @@ const BottomSheetComponent = forwardRef(
animatedClosedPosition,
]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
const handleForceClose = useCallback(
function handleForceClose(
animationConfigs?: WithSpringConfig | WithTimingConfig
) {
- print({
- component: BottomSheet.name,
- method: handleForceClose.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleForceClose.name,
+ });
+ }
const nextPosition = animatedClosedPosition.value;
@@ -941,14 +1249,17 @@ const BottomSheetComponent = forwardRef(
animatedClosedPosition,
]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
const handleExpand = useCallback(
function handleExpand(
animationConfigs?: WithSpringConfig | WithTimingConfig
) {
- print({
- component: BottomSheet.name,
- method: handleExpand.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleExpand.name,
+ });
+ }
const snapPoints = animatedSnapPoints.value;
const nextPosition = snapPoints[snapPoints.length - 1];
@@ -990,14 +1301,17 @@ const BottomSheetComponent = forwardRef(
animatedNextPositionIndex,
]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheet.name): used for debug only
const handleCollapse = useCallback(
function handleCollapse(
animationConfigs?: WithSpringConfig | WithTimingConfig
) {
- print({
- component: BottomSheet.name,
- method: handleCollapse.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheet.name,
+ method: handleCollapse.name,
+ });
+ }
const nextPosition = animatedSnapPoints.value[0];
@@ -1050,9 +1364,10 @@ const BottomSheetComponent = forwardRef(
//#endregion
//#region contexts variables
- const internalContextVariables = useMemo(
+ const internalContextVariables = useMemo(
() => ({
enableContentPanningGesture,
+ enableDynamicSizing,
overDragResistanceFactor,
enableOverDrag,
enablePanDownToClose,
@@ -1079,6 +1394,8 @@ const BottomSheetComponent = forwardRef(
isInTemporaryPosition,
isContentHeightFixed,
isScrollableRefreshable,
+ isScrollableLocked,
+ isScrollEnded,
shouldHandleKeyboardEvents,
simultaneousHandlers: _providedSimultaneousHandlers,
waitFor: _providedWaitFor,
@@ -1114,12 +1431,15 @@ const BottomSheetComponent = forwardRef(
shouldHandleKeyboardEvents,
animatedScrollableContentOffsetY,
isScrollableRefreshable,
+ isScrollableLocked,
+ isScrollEnded,
isContentHeightFixed,
isInTemporaryPosition,
enableContentPanningGesture,
overDragResistanceFactor,
enableOverDrag,
enablePanDownToClose,
+ enableDynamicSizing,
_providedSimultaneousHandlers,
_providedWaitFor,
_providedActiveOffsetX,
@@ -1159,8 +1479,6 @@ const BottomSheetComponent = forwardRef(
//#region styles
const containerAnimatedStyle = useAnimatedStyle(
() => ({
- opacity:
- Platform.OS === 'android' && animatedIndex.value === -1 ? 0 : 1,
transform: [
{
translateY: animatedPosition.value,
@@ -1175,20 +1493,30 @@ const BottomSheetComponent = forwardRef(
);
const contentContainerAnimatedStyle = useAnimatedStyle(() => {
/**
- * if content height was provided, then we skip setting
- * calculated height.
+ * if dynamic sizing is enabled, and content height
+ * is still not set, then we exit method.
*/
- if (_providedContentHeight) {
+ if (
+ enableDynamicSizing &&
+ animatedContentHeight.value === INITIAL_CONTAINER_HEIGHT
+ ) {
return {};
}
return {
height: animate({
- point: animatedContentHeight.value,
+ point: animatedContentHeightMax.value,
configs: _providedAnimationConfigs,
+ overrideReduceMotion: _providedOverrideReduceMotion,
}),
};
- }, [animatedContentHeight, _providedContentHeight]);
+ }, [
+ enableDynamicSizing,
+ animatedContentHeight,
+ animatedContentHeightMax,
+ _providedOverrideReduceMotion,
+ _providedAnimationConfigs,
+ ]);
const contentContainerStyle = useMemo(
() => [styles.contentContainer, contentContainerAnimatedStyle],
[contentContainerAnimatedStyle]
@@ -1207,7 +1535,7 @@ const BottomSheetComponent = forwardRef(
return {
paddingBottom: animatedContainerHeight.value,
};
- }, [detached]);
+ }, [animatedContainerHeight, detached]);
const contentMaskContainerStyle = useMemo(
() => [styles.contentMaskContainer, contentMaskContainerAnimatedStyle],
[contentMaskContainerAnimatedStyle]
@@ -1215,218 +1543,176 @@ const BottomSheetComponent = forwardRef(
//#endregion
//#region effects
+ useAnimatedReaction(
+ () => animatedContainerHeight.value,
+ (result, previous) => {
+ if (result === INITIAL_CONTAINER_HEIGHT) {
+ return;
+ }
+
+ animatedContainerHeightDidChange.value = result !== previous;
+ }
+ );
+
/**
- * React to `isLayoutCalculated` change, to insure that the sheet will
- * appears/mounts only when all layout is been calculated.
+ * Reaction to the `snapPoints` change, to insure that the sheet position reflect
+ * to the current point correctly.
*
- * @alias OnMount
+ * @alias OnSnapPointsChange
*/
useAnimatedReaction(
- () => isLayoutCalculated.value,
- _isLayoutCalculated => {
+ () => animatedSnapPoints.value,
+ (result, previous) => {
/**
- * exit method if:
- * - layout is not calculated yet.
- * - already did animate on mount.
+ * if values did not change, and did handle on mount animation
+ * then we early exit the method.
*/
- if (!_isLayoutCalculated || isAnimatedOnMount.value) {
+ if (
+ JSON.stringify(result) === JSON.stringify(previous) &&
+ isAnimatedOnMount.value
+ ) {
return;
}
- let nextPosition;
- if (_providedIndex === -1) {
- nextPosition = animatedClosedPosition.value;
- animatedNextPositionIndex.value = -1;
- } else {
- nextPosition = animatedSnapPoints.value[_providedIndex];
- }
-
- runOnJS(print)({
- component: BottomSheet.name,
- method: 'useAnimatedReaction::OnMount',
- params: {
- isLayoutCalculated: _isLayoutCalculated,
- animatedSnapPoints: animatedSnapPoints.value,
- nextPosition,
- },
- });
-
/**
- * here we exit method early because the next position
- * is out of the screen, this happens when `snapPoints`
- * still being calculated.
+ * if layout is not calculated yet, then we exit the method.
*/
- if (
- nextPosition === INITIAL_POSITION ||
- nextPosition === animatedClosedPosition.value
- ) {
- isAnimatedOnMount.value = true;
- animatedCurrentIndex.value = _providedIndex;
+ if (!isLayoutCalculated.value) {
return;
}
- if (animateOnMount) {
- animateToPosition(nextPosition, ANIMATION_SOURCE.MOUNT);
- } else {
- animatedPosition.value = nextPosition;
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: 'useAnimatedReaction::OnSnapPointChange',
+ category: 'effect',
+ params: {
+ result,
+ },
+ });
}
- isAnimatedOnMount.value = true;
+
+ evaluatePosition(ANIMATION_SOURCE.SNAP_POINT_CHANGE);
},
- [_providedIndex, animateOnMount]
+ [isLayoutCalculated, animatedSnapPoints]
);
/**
- * React to `snapPoints` change, to insure that the sheet position reflect
- * to the current point correctly.
+ * Reaction to the keyboard state change.
*
- * @alias OnSnapPointsChange
+ * @alias OnKeyboardStateChange
*/
useAnimatedReaction(
() => ({
- snapPoints: animatedSnapPoints.value,
- containerHeight: animatedContainerHeight.value,
+ _keyboardState: animatedKeyboardState.value,
+ _keyboardHeight: animatedKeyboardHeight.value,
}),
(result, _previousResult) => {
- const { snapPoints, containerHeight } = result;
- const _previousSnapPoints = _previousResult?.snapPoints;
- const _previousContainerHeight = _previousResult?.containerHeight;
+ const { _keyboardState, _keyboardHeight } = result;
+ const _previousKeyboardState = _previousResult?._keyboardState;
+ const _previousKeyboardHeight = _previousResult?._keyboardHeight;
+ /**
+ * if keyboard state is equal to the previous state, then exit the method
+ */
if (
- JSON.stringify(snapPoints) === JSON.stringify(_previousSnapPoints) ||
- !isLayoutCalculated.value ||
- !isAnimatedOnMount.value ||
- containerHeight <= 0
+ _keyboardState === _previousKeyboardState &&
+ _keyboardHeight === _previousKeyboardHeight
) {
return;
}
- runOnJS(print)({
- component: BottomSheet.name,
- method: 'useAnimatedReaction::OnSnapPointChange',
- params: {
- snapPoints,
- },
- });
-
- let nextPosition;
- let animationConfig;
- let animationSource = ANIMATION_SOURCE.SNAP_POINT_CHANGE;
+ /**
+ * if state is undetermined, then we early exit.
+ */
+ if (_keyboardState === KEYBOARD_STATE.UNDETERMINED) {
+ return;
+ }
/**
- * if snap points changed while sheet is animating, then
- * we stop the animation and animate to the updated point.
+ * if keyboard is hidden by customer gesture, then we early exit.
*/
if (
+ _keyboardState === KEYBOARD_STATE.HIDDEN &&
animatedAnimationState.value === ANIMATION_STATE.RUNNING &&
- animatedNextPositionIndex.value !== animatedCurrentIndex.value
+ animatedAnimationSource.value === ANIMATION_SOURCE.GESTURE
) {
- nextPosition =
- animatedNextPositionIndex.value !== -1
- ? snapPoints[animatedNextPositionIndex.value]
- : animatedNextPosition.value;
- } else if (animatedCurrentIndex.value === -1) {
- nextPosition = animatedClosedPosition.value;
- } else if (isInTemporaryPosition.value) {
- nextPosition = getNextPosition();
- } else {
- nextPosition = snapPoints[animatedCurrentIndex.value];
+ return;
+ }
+
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: 'useAnimatedReaction::OnKeyboardStateChange',
+ category: 'effect',
+ params: {
+ keyboardState: _keyboardState,
+ keyboardHeight: _keyboardHeight,
+ },
+ });
+ }
+
+ /**
+ * Calculate the keyboard height in the container.
+ */
+ animatedKeyboardHeightInContainer.value =
+ _keyboardHeight === 0
+ ? 0
+ : $modal
+ ? Math.abs(
+ _keyboardHeight -
+ Math.abs(bottomInset - animatedContainerOffset.value.bottom)
+ )
+ : Math.abs(
+ _keyboardHeight - animatedContainerOffset.value.bottom
+ );
+ /**
+ * if platform is android and the input mode is resize, then exit the method
+ */
+ if (
+ (Platform.OS === 'android' &&
+ android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize) ||
/**
- * if snap points changes because of the container height change,
- * then we skip the snap animation by setting the duration to 0.
+ * if the sheet is closing, then exit then method
*/
- if (containerHeight !== _previousContainerHeight) {
- animationSource = ANIMATION_SOURCE.CONTAINER_RESIZE;
- animationConfig = {
- duration: 0,
- };
+ animatedNextPositionIndex.value === -1
+ ) {
+ animatedKeyboardHeightInContainer.value = 0;
+
+ if (keyboardBehavior === KEYBOARD_BEHAVIOR.interactive) {
+ return;
}
}
- animateToPosition(nextPosition, animationSource, 0, animationConfig);
- }
- );
-
- /**
- * React to keyboard appearance state.
- *
- * @alias OnKeyboardStateChange
- */
- useAnimatedReaction(
- () => ({
- _keyboardState: animatedKeyboardState.value,
- _keyboardHeight: animatedKeyboardHeight.value,
- }),
- (result, _previousResult) => {
- const { _keyboardState, _keyboardHeight } = result;
- const _previousKeyboardState = _previousResult?._keyboardState;
- const _previousKeyboardHeight = _previousResult?._keyboardHeight;
/**
- * Calculate the keyboard height in the container.
+ * if user is interacting with sheet, then exit the method
*/
- animatedKeyboardHeightInContainer.value = $modal
- ? Math.abs(
- _keyboardHeight -
- Math.abs(bottomInset - animatedContainerOffset.value.bottom)
- )
- : Math.abs(_keyboardHeight - animatedContainerOffset.value.bottom);
-
const hasActiveGesture =
animatedContentGestureState.value === State.ACTIVE ||
animatedContentGestureState.value === State.BEGAN ||
animatedHandleGestureState.value === State.ACTIVE ||
animatedHandleGestureState.value === State.BEGAN;
+ if (hasActiveGesture) {
+ return;
+ }
+ /**
+ * if new keyboard state is hidden and blur behavior is none, then exit the method
+ */
if (
- /**
- * if keyboard state is equal to the previous state, then exit the method
- */
- (_keyboardState === _previousKeyboardState &&
- _keyboardHeight === _previousKeyboardHeight) ||
- /**
- * if user is interacting with sheet, then exit the method
- */
- hasActiveGesture ||
- /**
- * if sheet not animated on mount yet, then exit the method
- */
- !isAnimatedOnMount.value ||
- /**
- * if new keyboard state is hidden and blur behavior is none, then exit the method
- */
- (_keyboardState === KEYBOARD_STATE.HIDDEN &&
- keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none) ||
- /**
- * if platform is android and the input mode is resize, then exit the method
- */
- (Platform.OS === 'android' &&
- keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&
- android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize)
+ _keyboardState === KEYBOARD_STATE.HIDDEN &&
+ keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none
) {
- animatedKeyboardHeightInContainer.value = 0;
return;
}
- runOnJS(print)({
- component: BottomSheet.name,
- method: 'useAnimatedReaction::OnKeyboardStateChange',
- params: {
- keyboardState: _keyboardState,
- keyboardHeight: _keyboardHeight,
- },
- });
-
- let animationConfigs = getKeyboardAnimationConfigs(
+ const animationConfigs = getKeyboardAnimationConfigs(
keyboardAnimationEasing.value,
keyboardAnimationDuration.value
);
- const nextPosition = getNextPosition();
- animateToPosition(
- nextPosition,
- ANIMATION_SOURCE.KEYBOARD,
- 0,
- animationConfigs
- );
+
+ evaluatePosition(ANIMATION_SOURCE.KEYBOARD, animationConfigs);
},
[
$modal,
@@ -1435,7 +1721,7 @@ const BottomSheetComponent = forwardRef(
keyboardBlurBehavior,
android_keyboardInputMode,
animatedContainerOffset,
- getNextPosition,
+ getEvaluatedPosition,
]
);
@@ -1448,7 +1734,8 @@ const BottomSheetComponent = forwardRef(
if (_providedAnimatedPosition) {
_providedAnimatedPosition.value = _animatedPosition + topInset;
}
- }
+ },
+ []
);
/**
@@ -1460,7 +1747,8 @@ const BottomSheetComponent = forwardRef(
if (_providedAnimatedIndex) {
_providedAnimatedIndex.value = _animatedIndex;
}
- }
+ },
+ []
);
/**
@@ -1478,6 +1766,7 @@ const BottomSheetComponent = forwardRef(
}),
({
_animatedIndex,
+ _animatedPosition,
_animationState,
_contentGestureState,
_handleGestureState,
@@ -1489,6 +1778,21 @@ const BottomSheetComponent = forwardRef(
return;
}
+ /**
+ * exit the method if index value is not synced with
+ * position value.
+ *
+ * [read more](https://github.com/gorhom/react-native-bottom-sheet/issues/1356)
+ */
+ if (
+ animatedNextPosition.value !== INITIAL_VALUE &&
+ animatedNextPositionIndex.value !== INITIAL_VALUE &&
+ (_animatedPosition !== animatedNextPosition.value ||
+ _animatedIndex !== animatedNextPositionIndex.value)
+ ) {
+ return;
+ }
+
/**
* exit the method if animated index value
* has fraction, e.g. 1.99, 0.52
@@ -1511,41 +1815,60 @@ const BottomSheetComponent = forwardRef(
return;
}
+ /**
+ * exit the method if the animated index is out of sync with the
+ * animated position. this happened when the user enable reduce
+ * motion setting only.
+ */
+ if (
+ reduceMotion &&
+ _animatedIndex === animatedCurrentIndex.value &&
+ animatedSnapPoints.value[_animatedIndex] !== _animatedPosition
+ ) {
+ return;
+ }
+
/**
* if the index is not equal to the current index,
* than the sheet position had changed and we trigger
* the `onChange` callback.
*/
if (_animatedIndex !== animatedCurrentIndex.value) {
- runOnJS(print)({
- component: BottomSheet.name,
- method: 'useAnimatedReaction::OnChange',
- params: {
- animatedCurrentIndex: animatedCurrentIndex.value,
- animatedIndex: _animatedIndex,
- },
- });
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: 'useAnimatedReaction::OnChange',
+ category: 'effect',
+ params: {
+ animatedCurrentIndex: animatedCurrentIndex.value,
+ animatedIndex: _animatedIndex,
+ },
+ });
+ }
animatedCurrentIndex.value = _animatedIndex;
- runOnJS(handleOnChange)(_animatedIndex);
+ runOnJS(handleOnChange)(_animatedIndex, _animatedPosition);
}
/**
* if index is `-1` than we fire the `onClose` callback.
*/
if (_animatedIndex === -1 && _providedOnClose) {
- runOnJS(print)({
- component: BottomSheet.name,
- method: 'useAnimatedReaction::onClose',
- params: {
- animatedCurrentIndex: animatedCurrentIndex.value,
- animatedIndex: _animatedIndex,
- },
- });
+ if (__DEV__) {
+ runOnJS(print)({
+ component: BottomSheet.name,
+ method: 'useAnimatedReaction::onClose',
+ category: 'effect',
+ params: {
+ animatedCurrentIndex: animatedCurrentIndex.value,
+ animatedIndex: _animatedIndex,
+ },
+ });
+ }
runOnJS(_providedOnClose)();
}
},
- [handleOnChange, _providedOnClose]
+ [reduceMotion, handleOnChange, _providedOnClose]
);
/**
@@ -1557,24 +1880,13 @@ const BottomSheetComponent = forwardRef(
if (isAnimatedOnMount.value) {
handleSnapToIndex(_providedIndex);
}
- }, [
- _providedIndex,
- animatedCurrentIndex,
- isAnimatedOnMount,
- handleSnapToIndex,
- ]);
+ }, [_providedIndex, isAnimatedOnMount, handleSnapToIndex]);
//#endregion
// render
- print({
- component: BottomSheet.name,
- method: 'render',
- params: {
- animatedSnapPoints: animatedSnapPoints.value,
- animatedCurrentIndex: animatedCurrentIndex.value,
- providedIndex: _providedIndex,
- },
- });
+ const DraggableView = enableContentPanningGesture
+ ? BottomSheetDraggableView
+ : Animated.View;
return (
@@ -1608,19 +1920,19 @@ const BottomSheetComponent = forwardRef(
-
- {typeof Content === 'function' ? : Content}
-
- {footerComponent && (
-
- )}
-
+ {children}
+
+ {renderFooter && (
+
+ )}
(
// topInset,
// bottomInset,
animatedSheetState,
- animatedScrollableState,
- animatedScrollableOverrideState,
+ // animatedScrollableState,
+ // animatedScrollableOverrideState,
// isScrollableRefreshable,
// animatedScrollableContentOffsetY,
// keyboardState,
- // animatedIndex,
- // animatedCurrentIndex,
- // animatedPosition,
- // animatedContainerHeight,
- // animatedSheetHeight,
- // animatedHandleHeight,
- // animatedContentHeight,
+ animatedIndex,
+ animatedCurrentIndex,
+ animatedPosition,
+ // animatedHandleGestureState,
+ // animatedContentGestureState,
+ animatedContainerHeight,
+ animatedContentHeightMax,
+ animatedSheetHeight,
+ animatedHandleHeight,
+ animatedContentHeight,
+ animatedFooterHeight,
+ animatedKeyboardHeight,
+ animatedKeyboardHeightInContainer,
// // keyboardHeight,
// isLayoutCalculated,
// isContentHeightFixed,
diff --git a/src/components/bottomSheet/constants.ts b/src/components/bottomSheet/constants.ts
index a08599191..ffc4355bd 100644
--- a/src/components/bottomSheet/constants.ts
+++ b/src/components/bottomSheet/constants.ts
@@ -13,6 +13,7 @@ const DEFAULT_ENABLE_HANDLE_PANNING_GESTURE = true;
const DEFAULT_ENABLE_OVER_DRAG = true;
const DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE = false;
const DEFAULT_ANIMATE_ON_MOUNT = true;
+const DEFAULT_DYNAMIC_SIZING = true;
// keyboard
const DEFAULT_KEYBOARD_BEHAVIOR = KEYBOARD_BEHAVIOR.interactive;
@@ -32,6 +33,11 @@ const INITIAL_CONTAINER_OFFSET = {
const INITIAL_HANDLE_HEIGHT = -999;
const INITIAL_POSITION = SCREEN_HEIGHT;
+// accessibility
+const DEFAULT_ACCESSIBLE = true;
+const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom Sheet';
+const DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';
+
export {
DEFAULT_HANDLE_HEIGHT,
DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
@@ -39,6 +45,7 @@ export {
DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
DEFAULT_ENABLE_OVER_DRAG,
DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
+ DEFAULT_DYNAMIC_SIZING,
DEFAULT_ANIMATE_ON_MOUNT,
// keyboard
DEFAULT_KEYBOARD_BEHAVIOR,
@@ -51,4 +58,8 @@ export {
INITIAL_HANDLE_HEIGHT,
INITIAL_SNAP_POINT,
INITIAL_VALUE,
+ // accessibility
+ DEFAULT_ACCESSIBLE,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_ROLE,
};
diff --git a/src/components/bottomSheet/styles.ts b/src/components/bottomSheet/styles.ts
index 35b0a3965..4d63bc5f2 100644
--- a/src/components/bottomSheet/styles.ts
+++ b/src/components/bottomSheet/styles.ts
@@ -8,7 +8,9 @@ export const styles = StyleSheet.create({
left: 0,
right: 0,
},
- contentContainer: {},
+ contentContainer: {
+ overflow: 'visible',
+ },
contentMaskContainer: {
overflow: 'hidden',
},
diff --git a/src/components/bottomSheet/types.d.ts b/src/components/bottomSheet/types.d.ts
index c489981e1..010318033 100644
--- a/src/components/bottomSheet/types.d.ts
+++ b/src/components/bottomSheet/types.d.ts
@@ -1,37 +1,33 @@
import type React from 'react';
-import type { ViewStyle, Insets, StyleProp } from 'react-native';
+import type { Insets, StyleProp, ViewStyle } from 'react-native';
+import type { PanGesture } from 'react-native-gesture-handler';
import type {
- SharedValue,
AnimateStyle,
+ ReduceMotion,
+ SharedValue,
WithSpringConfig,
WithTimingConfig,
} from 'react-native-reanimated';
-import type { PanGestureHandlerProps } from 'react-native-gesture-handler';
-import type { BottomSheetHandleProps } from '../bottomSheetHandle';
-import type { BottomSheetBackdropProps } from '../bottomSheetBackdrop';
-import type { BottomSheetBackgroundProps } from '../bottomSheetBackground';
-import type { BottomSheetFooterProps } from '../bottomSheetFooter';
import type {
ANIMATION_SOURCE,
KEYBOARD_BEHAVIOR,
KEYBOARD_BLUR_BEHAVIOR,
KEYBOARD_INPUT_MODE,
+ SNAP_POINT_TYPE,
} from '../../constants';
-import type { GestureEventsHandlersHookType } from '../../types';
+import type {
+ GestureEventsHandlersHookType,
+ NullableAccessibilityProps,
+} from '../../types';
+import type { BottomSheetBackdropProps } from '../bottomSheetBackdrop';
+import type { BottomSheetBackgroundProps } from '../bottomSheetBackground';
+import type { BottomSheetFooterProps } from '../bottomSheetFooter';
+import type { BottomSheetHandleProps } from '../bottomSheetHandle';
export interface BottomSheetProps
extends BottomSheetAnimationConfigs,
- Partial<
- Pick<
- PanGestureHandlerProps,
- | 'activeOffsetY'
- | 'activeOffsetX'
- | 'failOffsetY'
- | 'failOffsetX'
- | 'waitFor'
- | 'simultaneousHandlers'
- >
- > {
+ Partial,
+ Omit {
//#region configuration
/**
* Initial snap point index, provide `-1` to initiate bottom sheet in closed state.
@@ -42,13 +38,21 @@ export interface BottomSheetProps
/**
* Points for the bottom sheet to snap to. It accepts array of number, string or mix.
* String values should be a percentage.
+ *
+ * ⚠️ This prop is required unless you set `enableDynamicSizing` to `true`.
* @example
* snapPoints={[200, 500]}
* snapPoints={[200, '%50']}
* snapPoints={['%100']}
* @type Array
*/
- snapPoints: Array | SharedValue>;
+ snapPoints?: Array | SharedValue>;
+ /**
+ * Initial position of the sheet.
+ * @type number
+ * @default SCREEN_HEIGHT
+ */
+ initialPosition?: number;
/**
* Defines how violently sheet has to be stopped while over dragging.
* @type number
@@ -85,12 +89,28 @@ export interface BottomSheetProps
* @default false
*/
enablePanDownToClose?: boolean;
+ /**
+ * Enable dynamic sizing for content view and scrollable content size.
+ * @type boolean
+ * @default true
+ */
+ enableDynamicSizing?: boolean;
/**
* To start the sheet closed and snap to initial index when it's mounted.
* @type boolean
* @default true
*/
animateOnMount?: boolean;
+ /**
+ * To override the user reduce motion setting.
+ * - `ReduceMotion.System`: if the `Reduce motion` accessibility setting is enabled on the device, disable the animation.
+ * - `ReduceMotion.Always`: disable the animation, even if `Reduce motion` accessibility setting is not enabled.
+ * - `ReduceMotion.Never`: enable the animation, even if `Reduce motion` accessibility setting is enabled.
+ * @type ReduceMotion
+ * @see https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility
+ * @default ReduceMotion.System
+ */
+ overrideReduceMotion?: ReduceMotion;
//#endregion
//#region layout
@@ -100,7 +120,7 @@ export interface BottomSheetProps
* unless `handleHeight` is provided.
* @type number
*/
- handleHeight?: number | SharedValue;
+ handleHeight?: number;
/**
* Container height helps to calculate the internal sheet layouts,
* if `containerHeight` not provided, the library internally will calculate it,
@@ -110,9 +130,9 @@ export interface BottomSheetProps
containerHeight?: number | SharedValue;
/**
* Content height helps dynamic snap points calculation.
- * @type number | SharedValue;
+ * @type number;
*/
- contentHeight?: number | SharedValue;
+ contentHeight?: number;
/**
* Container offset helps to accurately detect container offsets.
* @type SharedValue;
@@ -133,6 +153,13 @@ export interface BottomSheetProps
* @default 0
*/
bottomInset?: number;
+ /**
+ * Max dynamic content size height to limit the bottom sheet height
+ * from exceeding a provided size.
+ * @type number
+ * @default container height
+ */
+ maxDynamicContentSize?: number;
//#endregion
//#region keyboard
@@ -240,7 +267,7 @@ export interface BottomSheetProps
*
* @type (index: number) => void;
*/
- onChange?: (index: number) => void;
+ onChange?: (index: number, position: number, type: SNAP_POINT_TYPE) => void;
/**
* Callback when the sheet close.
*
@@ -250,9 +277,13 @@ export interface BottomSheetProps
/**
* Callback when the sheet about to animate to a new position.
*
- * @type (fromIndex: number, toIndex: number) => void;
+ * @type (fromIndex: number, toIndex: number, source: ANIMATION_SOURCE) => void;
*/
- onAnimate?: (fromIndex: number, toIndex: number) => void;
+ onAnimate?: (
+ fromIndex: number,
+ toIndex: number,
+ source: ANIMATION_SOURCE
+ ) => void;
//#endregion
//#region components
@@ -276,16 +307,16 @@ export interface BottomSheetProps
*/
backgroundComponent?: React.FC | null;
/**
- * Component to be placed as a footer.
+ * Function to render as the footer.
* @see {BottomSheetFooterProps}
- * @type React.FC\
+ * @type (props: BottomSheetFooterProps) => React.ReactElement | null;
*/
- footerComponent?: React.FC;
+ renderFooter?: (props: BottomSheetFooterProps) => React.ReactElement | null;
/**
* A scrollable node or normal view.
- * @type React.ReactNode[] | React.ReactNode
+ * @type React.ReactNode
*/
- children: (() => React.ReactNode) | React.ReactNode[] | React.ReactNode;
+ children: React.ReactNode;
//#endregion
//#region private
@@ -313,3 +344,16 @@ export type AnimateToPositionType = (
velocity?: number,
configs?: WithTimingConfig | WithSpringConfig
) => void;
+
+export type BottomSheetGestureProps = {
+ activeOffsetX: Parameters[0];
+ activeOffsetY: Parameters[0];
+
+ failOffsetY: Parameters[0];
+ failOffsetX: Parameters[0];
+
+ simultaneousHandlers: Parameters<
+ PanGesture['simultaneousWithExternalGesture']
+ >[0];
+ waitFor: Parameters[0];
+};
diff --git a/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx b/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
index 35597ce60..3b9bf8797 100644
--- a/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
+++ b/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
@@ -1,23 +1,30 @@
-import React, { memo, useCallback, useMemo, useState } from 'react';
-import { ViewProps } from 'react-native';
+import React, {
+ memo,
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react';
+import type { ViewProps } from 'react-native';
+import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
interpolate,
- Extrapolate,
useAnimatedStyle,
useAnimatedReaction,
- useAnimatedGestureHandler,
runOnJS,
+ Extrapolation,
} from 'react-native-reanimated';
-import {
- TapGestureHandler,
- TapGestureHandlerGestureEvent,
-} from 'react-native-gesture-handler';
import { useBottomSheet } from '../../hooks';
import {
- DEFAULT_OPACITY,
+ DEFAULT_ACCESSIBILITY_HINT,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_ROLE,
+ DEFAULT_ACCESSIBLE,
DEFAULT_APPEARS_ON_INDEX,
DEFAULT_DISAPPEARS_ON_INDEX,
DEFAULT_ENABLE_TOUCH_THROUGH,
+ DEFAULT_OPACITY,
DEFAULT_PRESS_BEHAVIOR,
} from './constants';
import { styles } from './styles';
@@ -33,9 +40,14 @@ const BottomSheetBackdropComponent = ({
onPress,
style,
children,
+ accessible: _providedAccessible = DEFAULT_ACCESSIBLE,
+ accessibilityRole: _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
+ accessibilityLabel: _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
+ accessibilityHint: _providedAccessibilityHint = DEFAULT_ACCESSIBILITY_HINT,
}: BottomSheetDefaultBackdropProps) => {
//#region hooks
const { snapToIndex, close } = useBottomSheet();
+ const isMounted = useRef(false);
//#endregion
//#region defaults
@@ -67,34 +79,35 @@ const BottomSheetBackdropComponent = ({
}, [snapToIndex, close, disappearsOnIndex, pressBehavior, onPress]);
const handleContainerTouchability = useCallback(
(shouldDisableTouchability: boolean) => {
- setPointerEvents(shouldDisableTouchability ? 'none' : 'auto');
+ isMounted.current &&
+ setPointerEvents(shouldDisableTouchability ? 'none' : 'auto');
},
[]
);
//#endregion
//#region tap gesture
- const gestureHandler =
- useAnimatedGestureHandler(
- {
- onFinish: () => {
- runOnJS(handleOnPress)();
- },
- },
- [handleOnPress]
- );
+ const tapHandler = useMemo(() => {
+ const gesture = Gesture.Tap().onEnd(() => {
+ runOnJS(handleOnPress)();
+ });
+ return gesture;
+ }, [handleOnPress]);
//#endregion
//#region styles
- const containerAnimatedStyle = useAnimatedStyle(() => ({
- opacity: interpolate(
- animatedIndex.value,
- [-1, disappearsOnIndex, appearsOnIndex],
- [0, 0, opacity],
- Extrapolate.CLAMP
- ),
- flex: 1,
- }));
+ const containerAnimatedStyle = useAnimatedStyle(
+ () => ({
+ opacity: interpolate(
+ animatedIndex.value,
+ [-1, disappearsOnIndex, appearsOnIndex],
+ [0, 0, opacity],
+ Extrapolation.CLAMP
+ ),
+ flex: 1,
+ }),
+ [animatedIndex, appearsOnIndex, disappearsOnIndex, opacity]
+ );
const containerStyle = useMemo(
() => [styles.container, style, containerAnimatedStyle],
[style, containerAnimatedStyle]
@@ -112,28 +125,41 @@ const BottomSheetBackdropComponent = ({
},
[disappearsOnIndex]
);
+
+ // addressing updating the state after unmounting.
+ // [link](https://github.com/gorhom/react-native-bottom-sheet/issues/1376)
+ useEffect(() => {
+ isMounted.current = true;
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
//#endregion
- return pressBehavior !== 'none' ? (
-
-
- {children}
-
-
- ) : (
-
+ const AnimatedView = (
+
{children}
);
+
+ return pressBehavior !== 'none' ? (
+ {AnimatedView}
+ ) : (
+ AnimatedView
+ );
};
const BottomSheetBackdrop = memo(BottomSheetBackdropComponent);
diff --git a/src/components/bottomSheetBackdrop/constants.ts b/src/components/bottomSheetBackdrop/constants.ts
index c2388dbb7..bf6f23dd8 100644
--- a/src/components/bottomSheetBackdrop/constants.ts
+++ b/src/components/bottomSheetBackdrop/constants.ts
@@ -4,10 +4,19 @@ const DEFAULT_DISAPPEARS_ON_INDEX = 0;
const DEFAULT_ENABLE_TOUCH_THROUGH = false;
const DEFAULT_PRESS_BEHAVIOR = 'close' as const;
+const DEFAULT_ACCESSIBLE = true;
+const DEFAULT_ACCESSIBILITY_ROLE = 'button';
+const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom sheet backdrop';
+const DEFAULT_ACCESSIBILITY_HINT = 'Tap to close the bottom sheet';
+
export {
DEFAULT_OPACITY,
DEFAULT_APPEARS_ON_INDEX,
DEFAULT_DISAPPEARS_ON_INDEX,
DEFAULT_ENABLE_TOUCH_THROUGH,
DEFAULT_PRESS_BEHAVIOR,
+ DEFAULT_ACCESSIBLE,
+ DEFAULT_ACCESSIBILITY_ROLE,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_HINT,
};
diff --git a/src/components/bottomSheetBackdrop/types.d.ts b/src/components/bottomSheetBackdrop/types.d.ts
index 6a33b9a73..f03d6c3d2 100644
--- a/src/components/bottomSheetBackdrop/types.d.ts
+++ b/src/components/bottomSheetBackdrop/types.d.ts
@@ -1,6 +1,9 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
import type { ViewProps } from 'react-native';
-import type { BottomSheetVariables } from '../../types';
+import type {
+ BottomSheetVariables,
+ NullableAccessibilityProps,
+} from '../../types';
export interface BottomSheetBackdropProps
extends Pick,
@@ -9,7 +12,8 @@ export interface BottomSheetBackdropProps
export type BackdropPressBehavior = 'none' | 'close' | 'collapse' | number;
export interface BottomSheetDefaultBackdropProps
- extends BottomSheetBackdropProps {
+ extends BottomSheetBackdropProps,
+ NullableAccessibilityProps {
/**
* Backdrop opacity.
* @type number
diff --git a/src/components/bottomSheetBackdropContainer/BottomSheetBackdropContainer.tsx b/src/components/bottomSheetBackdropContainer/BottomSheetBackdropContainer.tsx
index 50daa6f57..d08e51bb6 100644
--- a/src/components/bottomSheetBackdropContainer/BottomSheetBackdropContainer.tsx
+++ b/src/components/bottomSheetBackdropContainer/BottomSheetBackdropContainer.tsx
@@ -1,6 +1,6 @@
import React, { memo } from 'react';
-import type { BottomSheetBackdropContainerProps } from './types';
import { styles } from './styles';
+import type { BottomSheetBackdropContainerProps } from './types';
const BottomSheetBackdropContainerComponent = ({
animatedIndex,
diff --git a/src/components/bottomSheetBackground/BottomSheetBackground.tsx b/src/components/bottomSheetBackground/BottomSheetBackground.tsx
index 71ce0c37a..3f165ddff 100644
--- a/src/components/bottomSheetBackground/BottomSheetBackground.tsx
+++ b/src/components/bottomSheetBackground/BottomSheetBackground.tsx
@@ -1,7 +1,7 @@
import React, { memo } from 'react';
import { View } from 'react-native';
-import type { BottomSheetBackgroundProps } from './types';
import { styles } from './styles';
+import type { BottomSheetBackgroundProps } from './types';
const BottomSheetBackgroundComponent = ({
pointerEvents,
diff --git a/src/components/bottomSheetBackgroundContainer/BottomSheetBackgroundContainer.tsx b/src/components/bottomSheetBackgroundContainer/BottomSheetBackgroundContainer.tsx
index 80a859ef6..64e9ffc9b 100644
--- a/src/components/bottomSheetBackgroundContainer/BottomSheetBackgroundContainer.tsx
+++ b/src/components/bottomSheetBackgroundContainer/BottomSheetBackgroundContainer.tsx
@@ -1,8 +1,8 @@
import React, { memo, useMemo } from 'react';
+import { StyleSheet } from 'react-native';
import BottomSheetBackground from '../bottomSheetBackground';
-import type { BottomSheetBackgroundContainerProps } from './types';
import { styles } from './styles';
-import { StyleSheet } from 'react-native';
+import type { BottomSheetBackgroundContainerProps } from './types';
const BottomSheetBackgroundContainerComponent = ({
animatedIndex,
diff --git a/src/components/bottomSheetContainer/BottomSheetContainer.tsx b/src/components/bottomSheetContainer/BottomSheetContainer.tsx
index 9d42ef185..0716ecdbc 100644
--- a/src/components/bottomSheetContainer/BottomSheetContainer.tsx
+++ b/src/components/bottomSheetContainer/BottomSheetContainer.tsx
@@ -1,10 +1,10 @@
import React, { memo, useCallback, useMemo, useRef } from 'react';
import {
- LayoutChangeEvent,
+ type LayoutChangeEvent,
StatusBar,
- StyleProp,
+ type StyleProp,
View,
- ViewStyle,
+ type ViewStyle,
} from 'react-native';
import { WINDOW_HEIGHT } from '../../constants';
import { print } from '../../utilities';
@@ -48,13 +48,17 @@ function BottomSheetContainerComponent({
containerRef.current?.measure(
(_x, _y, _width, _height, _pageX, pageY) => {
+ if (!containerOffset.value) {
+ return;
+ }
containerOffset.value = {
- top: pageY,
+ top: pageY ?? 0,
left: 0,
right: 0,
bottom: Math.max(
0,
- WINDOW_HEIGHT - (pageY + height + (StatusBar.currentHeight ?? 0))
+ WINDOW_HEIGHT -
+ ((pageY ?? 0) + height + (StatusBar.currentHeight ?? 0))
),
};
}
@@ -63,12 +67,13 @@ function BottomSheetContainerComponent({
print({
component: BottomSheetContainer.displayName,
method: 'handleContainerLayout',
+ category: 'layout',
params: {
height,
},
});
},
- [containerHeight, containerOffset, containerRef]
+ [containerHeight, containerOffset]
);
//#endregion
@@ -79,8 +84,9 @@ function BottomSheetContainerComponent({
pointerEvents="box-none"
onLayout={shouldCalculateHeight ? handleContainerLayout : undefined}
style={containerStyle}
- children={children}
- />
+ >
+ {children}
+
);
//#endregion
}
diff --git a/src/components/bottomSheetContainer/styles.ts b/src/components/bottomSheetContainer/styles.ts
index 04f247de5..4968b3731 100644
--- a/src/components/bottomSheetContainer/styles.ts
+++ b/src/components/bottomSheetContainer/styles.ts
@@ -1,7 +1,8 @@
import { StyleSheet } from 'react-native';
export const styles = StyleSheet.create({
- container: {
- ...StyleSheet.absoluteFillObject,
+ root: {
+ flex: 1,
},
+ container: StyleSheet.absoluteFillObject,
});
diff --git a/src/components/bottomSheetContainer/styles.web.ts b/src/components/bottomSheetContainer/styles.web.ts
index 086ed0d0c..42836a23f 100644
--- a/src/components/bottomSheetContainer/styles.web.ts
+++ b/src/components/bottomSheetContainer/styles.web.ts
@@ -2,8 +2,7 @@ import { StyleSheet } from 'react-native';
export const styles = StyleSheet.create({
container: {
- // @ts-ignore
- position: 'fixed',
+ position: 'absolute',
left: 0,
right: 0,
bottom: 0,
diff --git a/src/components/bottomSheetContainer/types.d.ts b/src/components/bottomSheetContainer/types.d.ts
index a2193eddb..f3bbdf2a7 100644
--- a/src/components/bottomSheetContainer/types.d.ts
+++ b/src/components/bottomSheetContainer/types.d.ts
@@ -1,15 +1,15 @@
import type { ReactNode } from 'react';
import type { Insets, StyleProp, ViewStyle } from 'react-native';
-import type Animated from 'react-native-reanimated';
+import type { SharedValue } from 'react-native-reanimated';
import type { BottomSheetProps } from '../bottomSheet/types';
export interface BottomSheetContainerProps
extends Partial<
Pick
> {
- containerHeight: Animated.SharedValue;
- containerOffset: Animated.SharedValue;
+ containerHeight: SharedValue;
+ containerOffset: SharedValue>;
shouldCalculateHeight?: boolean;
style?: StyleProp;
- children: ReactNode;
+ children?: ReactNode;
}
diff --git a/src/components/bottomSheetDebugView/BottomSheetDebugView.tsx b/src/components/bottomSheetDebugView/BottomSheetDebugView.tsx
index 8919606cb..1836465a5 100644
--- a/src/components/bottomSheetDebugView/BottomSheetDebugView.tsx
+++ b/src/components/bottomSheetDebugView/BottomSheetDebugView.tsx
@@ -1,11 +1,11 @@
import React from 'react';
import { View } from 'react-native';
-import Animated from 'react-native-reanimated';
+import type { SharedValue } from 'react-native-reanimated';
import ReText from './ReText';
import { styles } from './styles';
interface BottomSheetDebugViewProps {
- values: Record | number>;
+ values: Record | number>;
}
const BottomSheetDebugView = ({ values }: BottomSheetDebugViewProps) => {
diff --git a/src/components/bottomSheetDebugView/ReText.tsx b/src/components/bottomSheetDebugView/ReText.tsx
index 9d7b1cdb7..b49a9f5ba 100644
--- a/src/components/bottomSheetDebugView/ReText.tsx
+++ b/src/components/bottomSheetDebugView/ReText.tsx
@@ -1,32 +1,38 @@
import React from 'react';
-import { TextProps as RNTextProps, TextInput } from 'react-native';
+import { type TextProps as RNTextProps, TextInput } from 'react-native';
import Animated, {
+ type SharedValue,
+ type AnimatedProps,
useAnimatedProps,
useDerivedValue,
} from 'react-native-reanimated';
interface TextProps {
text: string;
- value: Animated.SharedValue | number;
- style?: Animated.AnimateProps['style'];
+ value: SharedValue | number;
+ style?: AnimatedProps['style'];
}
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
+Animated.addWhitelistedNativeProps({ text: true });
+
const ReText = (props: TextProps) => {
const { text, value: _providedValue, style } = { style: {}, ...props };
- const providedValue = useDerivedValue(() =>
- typeof _providedValue === 'number'
- ? _providedValue
- : typeof _providedValue.value === 'number'
- ? _providedValue.value.toFixed(2)
- : _providedValue.value
+ const providedValue = useDerivedValue(
+ () =>
+ typeof _providedValue === 'number'
+ ? _providedValue
+ : typeof _providedValue.value === 'number'
+ ? _providedValue.value.toFixed(2)
+ : _providedValue.value,
+ [_providedValue]
);
const animatedProps = useAnimatedProps(() => {
return {
text: `${text}: ${providedValue.value}`,
};
- }, [providedValue]);
+ }, [text, providedValue]);
return (
| number;
+ style?: Animated.AnimateProps['style'];
+}
+
+const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
+
+const ReText = (props: TextProps) => {
+ const { text, value: _providedValue, style } = { style: {}, ...props };
+ const textRef = useRef(null);
+
+ const providedValue = useDerivedValue(() => {
+ const value =
+ typeof _providedValue === 'number'
+ ? _providedValue
+ : typeof _providedValue.value === 'number'
+ ? _providedValue.value.toFixed(2)
+ : _providedValue.value;
+
+ return `${text}: ${value}`;
+ }, [_providedValue, text]);
+
+ //region effects
+ useAnimatedReaction(
+ () => providedValue.value,
+ result => {
+ textRef.current?.setNativeProps({
+ text: result,
+ });
+ },
+ []
+ );
+ //endregion
+
+ return (
+
+ );
+};
+
+export default ReText;
diff --git a/src/components/bottomSheetDebugView/styles.web.ts b/src/components/bottomSheetDebugView/styles.web.ts
new file mode 100644
index 000000000..d77bfdc0b
--- /dev/null
+++ b/src/components/bottomSheetDebugView/styles.web.ts
@@ -0,0 +1,20 @@
+import { StyleSheet } from 'react-native';
+
+export const styles = StyleSheet.create({
+ container: {
+ position: 'absolute',
+ left: 4,
+ top: 80,
+ padding: 2,
+ width: 400,
+ backgroundColor: 'rgba(0, 0,0,0.5)',
+ },
+ text: {
+ fontSize: 14,
+ lineHeight: 16,
+ textAlignVertical: 'center',
+ height: 20,
+ padding: 0,
+ color: 'white',
+ },
+});
diff --git a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx
index 377b2d5a8..d721fee7a 100644
--- a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx
+++ b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx
@@ -1,15 +1,14 @@
-import React, { useMemo, useRef, memo } from 'react';
+import React, { useMemo, memo } from 'react';
+import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
-import { PanGestureHandler } from 'react-native-gesture-handler';
+import { BottomSheetDraggableContext } from '../../contexts/gesture';
import {
useBottomSheetGestureHandlers,
useBottomSheetInternal,
} from '../../hooks';
-import { GESTURE_SOURCE } from '../../constants';
import type { BottomSheetDraggableViewProps } from './types';
const BottomSheetDraggableViewComponent = ({
- gestureType = GESTURE_SOURCE.CONTENT,
nativeGestureRef,
refreshControlGestureRef,
style,
@@ -26,19 +25,10 @@ const BottomSheetDraggableViewComponent = ({
failOffsetX,
failOffsetY,
} = useBottomSheetInternal();
- const { contentPanGestureHandler, scrollablePanGestureHandler } =
- useBottomSheetGestureHandlers();
+ const { contentPanGestureHandler } = useBottomSheetGestureHandlers();
//#endregion
//#region variables
- const panGestureRef = useRef(null);
- const gestureHandler = useMemo(
- () =>
- gestureType === GESTURE_SOURCE.CONTENT
- ? contentPanGestureHandler
- : scrollablePanGestureHandler,
- [gestureType, contentPanGestureHandler, scrollablePanGestureHandler]
- );
const simultaneousHandlers = useMemo(() => {
const refs = [];
@@ -64,25 +54,66 @@ const BottomSheetDraggableViewComponent = ({
nativeGestureRef,
refreshControlGestureRef,
]);
+ const draggableGesture = useMemo(() => {
+ let gesture = Gesture.Pan()
+ .enabled(enableContentPanningGesture)
+ .shouldCancelWhenOutside(false)
+ .runOnJS(false)
+ .onStart(contentPanGestureHandler.handleOnStart)
+ .onChange(contentPanGestureHandler.handleOnChange)
+ .onEnd(contentPanGestureHandler.handleOnEnd)
+ .onFinalize(contentPanGestureHandler.handleOnFinalize);
+
+ if (waitFor) {
+ gesture = gesture.requireExternalGestureToFail(waitFor);
+ }
+
+ if (simultaneousHandlers) {
+ gesture = gesture.simultaneousWithExternalGesture(
+ simultaneousHandlers as never
+ );
+ }
+
+ if (activeOffsetX) {
+ gesture = gesture.activeOffsetX(activeOffsetX);
+ }
+
+ if (activeOffsetY) {
+ gesture = gesture.activeOffsetY(activeOffsetY);
+ }
+
+ if (failOffsetX) {
+ gesture = gesture.failOffsetX(failOffsetX);
+ }
+
+ if (failOffsetY) {
+ gesture = gesture.failOffsetY(failOffsetY);
+ }
+
+ return gesture;
+ }, [
+ activeOffsetX,
+ activeOffsetY,
+ enableContentPanningGesture,
+ failOffsetX,
+ failOffsetY,
+ simultaneousHandlers,
+ waitFor,
+ contentPanGestureHandler.handleOnChange,
+ contentPanGestureHandler.handleOnEnd,
+ contentPanGestureHandler.handleOnFinalize,
+ contentPanGestureHandler.handleOnStart,
+ ]);
//#endregion
return (
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
);
};
diff --git a/src/components/bottomSheetDraggableView/types.d.ts b/src/components/bottomSheetDraggableView/types.d.ts
index 8d38987e2..5ed61d78c 100644
--- a/src/components/bottomSheetDraggableView/types.d.ts
+++ b/src/components/bottomSheetDraggableView/types.d.ts
@@ -1,17 +1,9 @@
-import type { ReactNode, Ref } from 'react';
+import type { ReactNode } from 'react';
import type { ViewProps as RNViewProps } from 'react-native';
-import type { NativeViewGestureHandler } from 'react-native-gesture-handler';
-import type { GESTURE_SOURCE } from '../../constants';
+import type { GestureRef } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture';
export type BottomSheetDraggableViewProps = RNViewProps & {
- /**
- * Defines the gesture type of the draggable view.
- *
- * @default GESTURE_SOURCE.CONTENT
- * @type GESTURE_SOURCE
- */
- gestureType?: GESTURE_SOURCE;
- nativeGestureRef?: Ref | null;
- refreshControlGestureRef?: Ref | null;
+ nativeGestureRef?: Exclude;
+ refreshControlGestureRef?: Exclude;
children: ReactNode[] | ReactNode;
};
diff --git a/src/components/bottomSheetFooter/BottomSheetFooter.tsx b/src/components/bottomSheetFooter/BottomSheetFooter.tsx
index fff8d6448..584030f7a 100644
--- a/src/components/bottomSheetFooter/BottomSheetFooter.tsx
+++ b/src/components/bottomSheetFooter/BottomSheetFooter.tsx
@@ -1,10 +1,10 @@
import React, { memo, useCallback, useMemo } from 'react';
-import { LayoutChangeEvent } from 'react-native';
+import type { LayoutChangeEvent } from 'react-native';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';
import { KEYBOARD_STATE } from '../../constants';
import { useBottomSheetInternal } from '../../hooks';
-import type { BottomSheetDefaultFooterProps } from './types';
import { styles } from './styles';
+import type { BottomSheetDefaultFooterProps } from './types';
function BottomSheetFooterComponent({
animatedFooterPosition,
@@ -56,12 +56,8 @@ function BottomSheetFooterComponent({
//#endregion
return children !== null ? (
-
- {typeof children === 'function' ? children() : children}
+
+ {children}
) : null;
}
diff --git a/src/components/bottomSheetFooter/styles.ts b/src/components/bottomSheetFooter/styles.ts
index 8d7db06a3..278f702e3 100644
--- a/src/components/bottomSheetFooter/styles.ts
+++ b/src/components/bottomSheetFooter/styles.ts
@@ -7,5 +7,6 @@ export const styles = StyleSheet.create({
left: 0,
right: 0,
zIndex: 9999,
+ pointerEvents: 'box-none',
},
});
diff --git a/src/components/bottomSheetFooter/types.d.ts b/src/components/bottomSheetFooter/types.d.ts
index f523065f7..597e10996 100644
--- a/src/components/bottomSheetFooter/types.d.ts
+++ b/src/components/bottomSheetFooter/types.d.ts
@@ -1,14 +1,14 @@
import type { ReactNode } from 'react';
-import { ViewStyle } from 'react-native';
-import type Animated from 'react-native-reanimated';
+import type { ViewStyle } from 'react-native';
+import type { SharedValue } from 'react-native-reanimated';
export interface BottomSheetFooterProps {
/**
* Calculated footer animated position.
*
- * @type Animated.SharedValue
+ * @type SharedValue
*/
- animatedFooterPosition: Animated.SharedValue;
+ animatedFooterPosition: SharedValue;
}
export interface BottomSheetDefaultFooterProps extends BottomSheetFooterProps {
@@ -31,7 +31,7 @@ export interface BottomSheetDefaultFooterProps extends BottomSheetFooterProps {
/**
* Component to be placed in the footer.
*
- * @type {ReactNode | ReactNode[]}
+ * @type {ReactNode|ReactNode[]}
*/
children?: ReactNode | ReactNode[];
}
diff --git a/src/components/bottomSheetFooterContainer/BottomSheetFooterContainer.tsx b/src/components/bottomSheetFooterContainer/BottomSheetFooterContainer.tsx
index 0ddd8e01a..0d83c7390 100644
--- a/src/components/bottomSheetFooterContainer/BottomSheetFooterContainer.tsx
+++ b/src/components/bottomSheetFooterContainer/BottomSheetFooterContainer.tsx
@@ -1,11 +1,11 @@
-import React, { memo } from 'react';
+import { memo } from 'react';
import { useDerivedValue } from 'react-native-reanimated';
-import { useBottomSheetInternal } from '../../hooks';
import { KEYBOARD_STATE } from '../../constants';
+import { useBottomSheetInternal } from '../../hooks';
import type { BottomSheetFooterContainerProps } from './types';
const BottomSheetFooterContainerComponent = ({
- footerComponent: FooterComponent,
+ renderFooter,
}: BottomSheetFooterContainerProps) => {
//#region hooks
const {
@@ -46,7 +46,7 @@ const BottomSheetFooterContainerComponent = ({
]);
//#endregion
- return ;
+ return renderFooter({ animatedFooterPosition });
};
const BottomSheetFooterContainer = memo(BottomSheetFooterContainerComponent);
diff --git a/src/components/bottomSheetFooterContainer/types.d.ts b/src/components/bottomSheetFooterContainer/types.d.ts
index 2ba8cf705..742c560ae 100644
--- a/src/components/bottomSheetFooterContainer/types.d.ts
+++ b/src/components/bottomSheetFooterContainer/types.d.ts
@@ -1,4 +1,4 @@
import type { BottomSheetProps } from '../bottomSheet';
export interface BottomSheetFooterContainerProps
- extends Required> {}
+ extends Required> {}
diff --git a/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx b/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx
index e3314b812..d1860b98c 100644
--- a/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx
+++ b/src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx
@@ -1,13 +1,13 @@
import React, { useMemo } from 'react';
+import { useSharedValue } from 'react-native-reanimated';
import { GESTURE_SOURCE } from '../../constants';
+import { BottomSheetGestureHandlersContext } from '../../contexts';
import {
- useGestureHandler,
useBottomSheetInternal,
useGestureEventsHandlersDefault,
+ useGestureHandler,
} from '../../hooks';
-import { BottomSheetGestureHandlersContext } from '../../contexts';
import type { BottomSheetGestureHandlersProviderProps } from './types';
-import { useSharedValue } from 'react-native-reanimated';
const BottomSheetGestureHandlersProvider = ({
gestureEventsHandlersHook:
@@ -23,7 +23,7 @@ const BottomSheetGestureHandlersProvider = ({
//#region hooks
const { animatedContentGestureState, animatedHandleGestureState } =
useBottomSheetInternal();
- const { handleOnStart, handleOnActive, handleOnEnd } =
+ const { handleOnStart, handleOnChange, handleOnEnd, handleOnFinalize } =
useGestureEventsHandlers();
//#endregion
@@ -33,17 +33,9 @@ const BottomSheetGestureHandlersProvider = ({
animatedContentGestureState,
animatedGestureSource,
handleOnStart,
- handleOnActive,
- handleOnEnd
- );
-
- const scrollablePanGestureHandler = useGestureHandler(
- GESTURE_SOURCE.SCROLLABLE,
- animatedContentGestureState,
- animatedGestureSource,
- handleOnStart,
- handleOnActive,
- handleOnEnd
+ handleOnChange,
+ handleOnEnd,
+ handleOnFinalize
);
const handlePanGestureHandler = useGestureHandler(
@@ -51,8 +43,9 @@ const BottomSheetGestureHandlersProvider = ({
animatedHandleGestureState,
animatedGestureSource,
handleOnStart,
- handleOnActive,
- handleOnEnd
+ handleOnChange,
+ handleOnEnd,
+ handleOnFinalize
);
//#endregion
@@ -61,15 +54,9 @@ const BottomSheetGestureHandlersProvider = ({
() => ({
contentPanGestureHandler,
handlePanGestureHandler,
- scrollablePanGestureHandler,
animatedGestureSource,
}),
- [
- contentPanGestureHandler,
- handlePanGestureHandler,
- scrollablePanGestureHandler,
- animatedGestureSource,
- ]
+ [contentPanGestureHandler, handlePanGestureHandler, animatedGestureSource]
);
//#endregion
return (
diff --git a/src/components/bottomSheetHandle/BottomSheetHandle.tsx b/src/components/bottomSheetHandle/BottomSheetHandle.tsx
index ea9800571..5e85ec6ae 100644
--- a/src/components/bottomSheetHandle/BottomSheetHandle.tsx
+++ b/src/components/bottomSheetHandle/BottomSheetHandle.tsx
@@ -1,5 +1,11 @@
import React, { memo, useMemo } from 'react';
import Animated from 'react-native-reanimated';
+import {
+ DEFAULT_ACCESSIBILITY_HINT,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_ROLE,
+ DEFAULT_ACCESSIBLE,
+} from './constants';
import { styles } from './styles';
import type { BottomSheetDefaultHandleProps } from './types';
@@ -7,6 +13,10 @@ const BottomSheetHandleComponent = ({
style,
indicatorStyle: _indicatorStyle,
children,
+ accessible = DEFAULT_ACCESSIBLE,
+ accessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,
+ accessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,
+ accessibilityHint = DEFAULT_ACCESSIBILITY_HINT,
}: BottomSheetDefaultHandleProps) => {
// styles
const containerStyle = useMemo(
@@ -23,7 +33,13 @@ const BottomSheetHandleComponent = ({
// render
return (
-
+
{children}
diff --git a/src/components/bottomSheetHandle/constants.ts b/src/components/bottomSheetHandle/constants.ts
new file mode 100644
index 000000000..98d76c1a8
--- /dev/null
+++ b/src/components/bottomSheetHandle/constants.ts
@@ -0,0 +1,12 @@
+const DEFAULT_ACCESSIBLE = true;
+const DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';
+const DEFAULT_ACCESSIBILITY_LABEL = 'Bottom sheet handle';
+const DEFAULT_ACCESSIBILITY_HINT =
+ 'Drag up or down to extend or minimize the bottom sheet';
+
+export {
+ DEFAULT_ACCESSIBLE,
+ DEFAULT_ACCESSIBILITY_ROLE,
+ DEFAULT_ACCESSIBILITY_LABEL,
+ DEFAULT_ACCESSIBILITY_HINT,
+};
diff --git a/src/components/bottomSheetHandle/types.d.ts b/src/components/bottomSheetHandle/types.d.ts
index 20cc2bc20..b36cf5968 100644
--- a/src/components/bottomSheetHandle/types.d.ts
+++ b/src/components/bottomSheetHandle/types.d.ts
@@ -1,11 +1,16 @@
import type React from 'react';
import type { ViewProps } from 'react-native';
import type { AnimateProps } from 'react-native-reanimated';
-import type { BottomSheetVariables } from '../../types';
+import type {
+ BottomSheetVariables,
+ NullableAccessibilityProps,
+} from '../../types';
export interface BottomSheetHandleProps extends BottomSheetVariables {}
-export interface BottomSheetDefaultHandleProps extends BottomSheetHandleProps {
+export interface BottomSheetDefaultHandleProps
+ extends BottomSheetHandleProps,
+ NullableAccessibilityProps {
/**
* View style to be applied to the handle container.
* @type Animated.AnimateStyle | ViewStyle
diff --git a/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx b/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx
index 2219e0f1d..691ab7112 100644
--- a/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx
+++ b/src/components/bottomSheetHandleContainer/BottomSheetHandleContainer.tsx
@@ -1,20 +1,22 @@
import React, { memo, useCallback, useMemo } from 'react';
import type { LayoutChangeEvent } from 'react-native';
-import { PanGestureHandler } from 'react-native-gesture-handler';
+import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
-import BottomSheetHandle from '../bottomSheetHandle';
import {
useBottomSheetGestureHandlers,
useBottomSheetInternal,
} from '../../hooks';
import { print } from '../../utilities';
+import { DEFAULT_ENABLE_HANDLE_PANNING_GESTURE } from '../bottomSheet/constants';
+import BottomSheetHandle from '../bottomSheetHandle';
+import { styles } from './styles';
import type { BottomSheetHandleContainerProps } from './types';
function BottomSheetHandleContainerComponent({
animatedIndex,
animatedPosition,
simultaneousHandlers: _internalSimultaneousHandlers,
- enableHandlePanningGesture,
+ enableHandlePanningGesture = DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,
handleHeight,
handleComponent: _providedHandleComponent,
handleStyle: _providedHandleStyle,
@@ -33,7 +35,7 @@ function BottomSheetHandleContainerComponent({
//#endregion
//#region variables
- const simultaneousHandlers = useMemo(() => {
+ const simultaneousHandlers = useMemo(() => {
const refs = [];
if (_internalSimultaneousHandlers) {
@@ -50,6 +52,57 @@ function BottomSheetHandleContainerComponent({
return refs;
}, [_providedSimultaneousHandlers, _internalSimultaneousHandlers]);
+
+ const panGesture = useMemo(() => {
+ let gesture = Gesture.Pan()
+ .enabled(enableHandlePanningGesture)
+ .shouldCancelWhenOutside(false)
+ .runOnJS(false)
+ .onStart(handlePanGestureHandler.handleOnStart)
+ .onChange(handlePanGestureHandler.handleOnChange)
+ .onEnd(handlePanGestureHandler.handleOnEnd)
+ .onFinalize(handlePanGestureHandler.handleOnFinalize);
+
+ if (waitFor) {
+ gesture = gesture.requireExternalGestureToFail(waitFor);
+ }
+
+ if (simultaneousHandlers) {
+ gesture = gesture.simultaneousWithExternalGesture(
+ simultaneousHandlers as never
+ );
+ }
+
+ if (activeOffsetX) {
+ gesture = gesture.activeOffsetX(activeOffsetX);
+ }
+
+ if (activeOffsetY) {
+ gesture = gesture.activeOffsetY(activeOffsetY);
+ }
+
+ if (failOffsetX) {
+ gesture = gesture.failOffsetX(failOffsetX);
+ }
+
+ if (failOffsetY) {
+ gesture = gesture.failOffsetY(failOffsetY);
+ }
+
+ return gesture;
+ }, [
+ activeOffsetX,
+ activeOffsetY,
+ enableHandlePanningGesture,
+ failOffsetX,
+ failOffsetY,
+ simultaneousHandlers,
+ waitFor,
+ handlePanGestureHandler.handleOnChange,
+ handlePanGestureHandler.handleOnEnd,
+ handlePanGestureHandler.handleOnFinalize,
+ handlePanGestureHandler.handleOnStart,
+ ]);
//#endregion
//#region callbacks
@@ -61,13 +114,16 @@ function BottomSheetHandleContainerComponent({
}: LayoutChangeEvent) {
handleHeight.value = height;
- print({
- component: BottomSheetHandleContainer.displayName,
- method: 'handleContainerLayout',
- params: {
- height,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetHandleContainer.displayName,
+ method: 'handleContainerLayout',
+ category: 'layout',
+ params: {
+ height,
+ },
+ });
+ }
},
[handleHeight]
);
@@ -79,24 +135,11 @@ function BottomSheetHandleContainerComponent({
? BottomSheetHandle
: _providedHandleComponent;
return HandleComponent !== null ? (
-
+
-
+
) : null;
//#endregion
}
diff --git a/src/components/bottomSheetHandleContainer/styles.ts b/src/components/bottomSheetHandleContainer/styles.ts
new file mode 100644
index 000000000..c20ba5fca
--- /dev/null
+++ b/src/components/bottomSheetHandleContainer/styles.ts
@@ -0,0 +1,5 @@
+import { StyleSheet } from 'react-native';
+
+export const styles = StyleSheet.create({
+ container: {},
+});
diff --git a/src/components/bottomSheetHandleContainer/styles.web.ts b/src/components/bottomSheetHandleContainer/styles.web.ts
new file mode 100644
index 000000000..30edc7fd7
--- /dev/null
+++ b/src/components/bottomSheetHandleContainer/styles.web.ts
@@ -0,0 +1,8 @@
+import { StyleSheet } from 'react-native';
+
+export const styles = StyleSheet.create({
+ container: {
+ // @ts-ignore
+ cursor: 'grab',
+ },
+});
diff --git a/src/components/bottomSheetHandleContainer/types.d.ts b/src/components/bottomSheetHandleContainer/types.d.ts
index c3c2ae928..fb535c17e 100644
--- a/src/components/bottomSheetHandleContainer/types.d.ts
+++ b/src/components/bottomSheetHandleContainer/types.d.ts
@@ -1,8 +1,8 @@
import type { PanGestureHandlerProperties } from 'react-native-gesture-handler';
-import type Animated from 'react-native-reanimated';
+import type { SharedValue } from 'react-native-reanimated';
+import type { useInteractivePanGestureHandlerConfigs } from '../../hooks/useGestureHandler';
import type { BottomSheetProps } from '../bottomSheet';
import type { BottomSheetHandleProps } from '../bottomSheetHandle';
-import type { useInteractivePanGestureHandlerConfigs } from '../../hooks/useGestureHandler';
export interface BottomSheetHandleContainerProps
extends Pick,
@@ -21,5 +21,5 @@ export interface BottomSheetHandleContainerProps
| 'keyboardBehavior'
>,
BottomSheetHandleProps {
- handleHeight: Animated.SharedValue;
+ handleHeight: SharedValue;
}
diff --git a/src/components/bottomSheetModal/BottomSheetModal.tsx b/src/components/bottomSheetModal/BottomSheetModal.tsx
index e0070c5ce..99bdeb294 100644
--- a/src/components/bottomSheetModal/BottomSheetModal.tsx
+++ b/src/components/bottomSheetModal/BottomSheetModal.tsx
@@ -1,50 +1,57 @@
+import { Portal, usePortal } from '@gorhom/portal';
import React, {
forwardRef,
memo,
+ type RefObject,
useCallback,
useImperativeHandle,
useMemo,
useRef,
useState,
} from 'react';
-import { Portal, usePortal } from '@gorhom/portal';
-import BottomSheet from '../bottomSheet';
+import type { ANIMATION_SOURCE, SNAP_POINT_TYPE } from '../../constants';
import { useBottomSheetModalInternal } from '../../hooks';
+import type { BottomSheetMethods, BottomSheetModalMethods } from '../../types';
import { print } from '../../utilities';
+import { id } from '../../utilities/id';
+import BottomSheet from '../bottomSheet';
import {
- DEFAULT_STACK_BEHAVIOR,
DEFAULT_ENABLE_DISMISS_ON_CLOSE,
+ DEFAULT_STACK_BEHAVIOR,
} from './constants';
-import type { BottomSheetModalMethods, BottomSheetMethods } from '../../types';
-import type { BottomSheetModalProps } from './types';
-import { id } from '../../utilities/id';
+import type {
+ BottomSheetModalPrivateMethods,
+ BottomSheetModalProps,
+ BottomSheetModalState,
+} from './types';
-type BottomSheetModal = BottomSheetModalMethods;
-
-const INITIAL_STATE: {
- mount: boolean;
- data: any;
-} = {
+const INITIAL_STATE: BottomSheetModalState = {
mount: false,
data: undefined,
};
-const BottomSheetModalComponent = forwardRef<
- BottomSheetModal,
- BottomSheetModalProps
->(function BottomSheetModal(props, ref) {
+// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.
+type BottomSheetModal = BottomSheetModalMethods;
+
+// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.
+function BottomSheetModalComponent(
+ props: BottomSheetModalProps,
+ ref: React.ForwardedRef>
+) {
const {
// modal props
name,
stackBehavior = DEFAULT_STACK_BEHAVIOR,
enableDismissOnClose = DEFAULT_ENABLE_DISMISS_ON_CLOSE,
onDismiss: _providedOnDismiss,
+ onAnimate: _providedOnAnimate,
// bottom sheet props
index = 0,
snapPoints,
enablePanDownToClose = true,
animateOnMount = true,
+ containerComponent: ContainerComponent = React.Fragment,
// callbacks
onChange: _providedOnChange,
@@ -55,7 +62,8 @@ const BottomSheetModalComponent = forwardRef<
} = props;
//#region state
- const [{ mount, data }, setState] = useState(INITIAL_STATE);
+ const [{ mount, data }, setState] =
+ useState>(INITIAL_STATE);
//#endregion
//#region hooks
@@ -72,6 +80,7 @@ const BottomSheetModalComponent = forwardRef<
//#region refs
const bottomSheetRef = useRef(null);
const currentIndexRef = useRef(!animateOnMount ? index : -1);
+ const nextIndexRef = useRef(null);
const restoreIndexRef = useRef(-1);
const minimized = useRef(false);
const forcedDismissed = useRef(false);
@@ -84,6 +93,7 @@ const BottomSheetModalComponent = forwardRef<
//#endregion
//#region private methods
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const resetVariables = useCallback(function resetVariables() {
print({
component: BottomSheetModal.name,
@@ -95,12 +105,15 @@ const BottomSheetModalComponent = forwardRef<
mounted.current = false;
forcedDismissed.current = false;
}, []);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const unmount = useCallback(
function unmount() {
- print({
- component: BottomSheetModal.name,
- method: unmount.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: unmount.name,
+ });
+ }
const _mounted = mounted.current;
// reset variables
@@ -142,71 +155,100 @@ const BottomSheetModalComponent = forwardRef<
}
bottomSheetRef.current?.snapToPosition(...args);
}, []);
- const handleExpand = useCallback((...args) => {
+ const handleExpand: BottomSheetMethods['expand'] = useCallback((...args) => {
if (minimized.current) {
return;
}
bottomSheetRef.current?.expand(...args);
}, []);
- const handleCollapse = useCallback((...args) => {
- if (minimized.current) {
- return;
- }
- bottomSheetRef.current?.collapse(...args);
- }, []);
- const handleClose = useCallback((...args) => {
+ const handleCollapse: BottomSheetMethods['collapse'] = useCallback(
+ (...args) => {
+ if (minimized.current) {
+ return;
+ }
+ bottomSheetRef.current?.collapse(...args);
+ },
+ []
+ );
+ const handleClose: BottomSheetMethods['close'] = useCallback((...args) => {
if (minimized.current) {
return;
}
bottomSheetRef.current?.close(...args);
}, []);
- const handleForceClose = useCallback((...args) => {
- if (minimized.current) {
- return;
- }
- bottomSheetRef.current?.forceClose(...args);
- }, []);
+ const handleForceClose: BottomSheetMethods['forceClose'] = useCallback(
+ (...args) => {
+ if (minimized.current) {
+ return;
+ }
+ bottomSheetRef.current?.forceClose(...args);
+ },
+ []
+ );
//#endregion
//#region bottom sheet modal methods
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
+ // biome-ignore lint/correctness/useExhaustiveDependencies(ref): ref is a stable object
const handlePresent = useCallback(
- function handlePresent(_data?: any) {
+ function handlePresent(_data?: T) {
requestAnimationFrame(() => {
setState({
mount: true,
data: _data,
});
- mountSheet(key, ref, stackBehavior);
+ mountSheet(
+ key,
+ ref as unknown as RefObject,
+ stackBehavior
+ );
+ ref;
- print({
- component: BottomSheetModal.name,
- method: handlePresent.name,
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handlePresent.name,
+ });
+ }
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[key, stackBehavior, mountSheet]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handleDismiss = useCallback(
function handleDismiss(animationConfigs) {
- print({
- component: BottomSheetModal.name,
- method: handleDismiss.name,
- params: {
- currentIndexRef: currentIndexRef.current,
- minimized: minimized.current,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handleDismiss.name,
+ params: {
+ currentIndexRef: currentIndexRef.current,
+ minimized: minimized.current,
+ },
+ });
+ }
+
+ const animating = nextIndexRef.current != null;
+
/**
- * if modal is already been dismiss, we exit the method.
+ * early exit, if not minimized, it is in closed position and not animating
*/
- if (currentIndexRef.current === -1 && minimized.current === false) {
+ if (
+ currentIndexRef.current === -1 &&
+ minimized.current === false &&
+ !animating
+ ) {
return;
}
+ /**
+ * unmount and early exit, if minimized or it is in closed position and not animating
+ */
if (
- minimized.current ||
- (currentIndexRef.current === -1 && enablePanDownToClose)
+ !animating &&
+ (minimized.current ||
+ (currentIndexRef.current === -1 && enablePanDownToClose))
) {
unmount();
return;
@@ -217,15 +259,18 @@ const BottomSheetModalComponent = forwardRef<
},
[willUnmountSheet, unmount, key, enablePanDownToClose]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handleMinimize = useCallback(
function handleMinimize() {
- print({
- component: BottomSheetModal.name,
- method: handleMinimize.name,
- params: {
- minimized: minimized.current,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handleMinimize.name,
+ params: {
+ minimized: minimized.current,
+ },
+ });
+ }
if (minimized.current) {
return;
}
@@ -245,15 +290,18 @@ const BottomSheetModalComponent = forwardRef<
},
[index]
);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handleRestore = useCallback(function handleRestore() {
- print({
- component: BottomSheetModal.name,
- method: handleRestore.name,
- params: {
- minimized: minimized.current,
- forcedDismissed: forcedDismissed.current,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handleRestore.name,
+ params: {
+ minimized: minimized.current,
+ forcedDismissed: forcedDismissed.current,
+ },
+ });
+ }
if (!minimized.current || forcedDismissed.current) {
return;
}
@@ -263,16 +311,19 @@ const BottomSheetModalComponent = forwardRef<
//#endregion
//#region callbacks
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handlePortalOnUnmount = useCallback(
function handlePortalOnUnmount() {
- print({
- component: BottomSheetModal.name,
- method: handlePortalOnUnmount.name,
- params: {
- minimized: minimized.current,
- forcedDismissed: forcedDismissed.current,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handlePortalOnUnmount.name,
+ params: {
+ minimized: minimized.current,
+ forcedDismissed: forcedDismissed.current,
+ },
+ });
+ }
/**
* if modal is already been dismiss, we exit the method.
*/
@@ -298,36 +349,58 @@ const BottomSheetModalComponent = forwardRef<
if (mounted.current) {
render();
}
- },
- []);
+ }, []);
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handleBottomSheetOnChange = useCallback(
- function handleBottomSheetOnChange(_index: number) {
- print({
- component: BottomSheetModal.name,
- method: handleBottomSheetOnChange.name,
- params: {
- minimized: minimized.current,
- forcedDismissed: forcedDismissed.current,
- },
- });
+ function handleBottomSheetOnChange(
+ _index: number,
+ _position: number,
+ _type: SNAP_POINT_TYPE
+ ) {
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handleBottomSheetOnChange.name,
+ category: 'callback',
+ params: {
+ minimized: minimized.current,
+ forcedDismissed: forcedDismissed.current,
+ },
+ });
+ }
currentIndexRef.current = _index;
+ nextIndexRef.current = null;
if (_providedOnChange) {
- _providedOnChange(_index);
+ _providedOnChange(_index, _position, _type);
}
},
[_providedOnChange]
);
+ const handleBottomSheetOnAnimate = useCallback(
+ (fromIndex: number, toIndex: number, source: ANIMATION_SOURCE) => {
+ nextIndexRef.current = toIndex;
+
+ if (_providedOnAnimate) {
+ _providedOnAnimate(fromIndex, toIndex, source);
+ }
+ },
+ [_providedOnAnimate]
+ );
+ // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only
const handleBottomSheetOnClose = useCallback(
function handleBottomSheetOnClose() {
- print({
- component: BottomSheetModal.name,
- method: handleBottomSheetOnClose.name,
- params: {
- minimized: minimized.current,
- forcedDismissed: forcedDismissed.current,
- },
- });
+ if (__DEV__) {
+ print({
+ component: BottomSheetModal.name,
+ method: handleBottomSheetOnClose.name,
+ category: 'callback',
+ params: {
+ minimized: minimized.current,
+ forcedDismissed: forcedDismissed.current,
+ },
+ });
+ }
if (minimized.current) {
return;
@@ -360,7 +433,6 @@ const BottomSheetModalComponent = forwardRef<
//#endregion
// render
- // console.log('BottomSheetModal', index, mount, data);
return mount ? (
- : Content
- }
- $modal={true}
- />
+
+
+ {typeof Content === 'function' ? : Content}
+
+
) : null;
-});
+}
-const BottomSheetModal = memo(BottomSheetModalComponent);
-BottomSheetModal.displayName = 'BottomSheetModal';
+const BottomSheetModal = memo(forwardRef(BottomSheetModalComponent)) as <
+ // biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.
+ T = any,
+>(
+ props: BottomSheetModalProps & {
+ ref?: React.ForwardedRef>;
+ }
+) => ReturnType>;
+(
+ BottomSheetModal as React.MemoExoticComponent<
+ (props: BottomSheetModalProps) => React.JSX.Element
+ >
+).displayName = 'BottomSheetModal';
export default BottomSheetModal;
diff --git a/src/components/bottomSheetModal/constants.ts b/src/components/bottomSheetModal/constants.ts
index 5fdcd0992..d4c34486b 100644
--- a/src/components/bottomSheetModal/constants.ts
+++ b/src/components/bottomSheetModal/constants.ts
@@ -1,4 +1,4 @@
-const DEFAULT_STACK_BEHAVIOR = 'replace';
+const DEFAULT_STACK_BEHAVIOR = 'switch';
const DEFAULT_ENABLE_DISMISS_ON_CLOSE = true;
export { DEFAULT_STACK_BEHAVIOR, DEFAULT_ENABLE_DISMISS_ON_CLOSE };
diff --git a/src/components/bottomSheetModal/types.d.ts b/src/components/bottomSheetModal/types.d.ts
index 9d104e74b..9e8e3eeac 100644
--- a/src/components/bottomSheetModal/types.d.ts
+++ b/src/components/bottomSheetModal/types.d.ts
@@ -1,6 +1,7 @@
import type React from 'react';
-import type { BottomSheetProps } from '../bottomSheet';
+import type { View } from 'react-native';
import type { MODAL_STACK_BEHAVIOR } from '../../constants';
+import type { BottomSheetProps } from '../bottomSheet';
export interface BottomSheetModalPrivateMethods {
dismiss: (force?: boolean) => void;
@@ -10,21 +11,23 @@ export interface BottomSheetModalPrivateMethods {
export type BottomSheetModalStackBehavior = keyof typeof MODAL_STACK_BEHAVIOR;
-export interface BottomSheetModalProps
+// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.
+export interface BottomSheetModalProps
extends Omit {
/**
* Modal name to help identify the modal for later on.
* @type string
- * @default nanoid generated unique key.
+ * @default generated unique key.
*/
name?: string;
/**
* Defines the stack behavior when modal mount.
- * - `push` it will mount the modal on top of current modal.
- * - `replace` it will minimize the current modal then mount the modal.
- * @type `push` | `replace`
- * @default replace
+ * - `push` it will mount the modal on top of the current one.
+ * - `switch` it will minimize the current modal then mount the new one.
+ * - `replace` it will dismiss the current modal then mount the new one.
+ * @type `push` | `switch` | `replace`
+ * @default switch
*/
stackBehavior?: BottomSheetModalStackBehavior;
@@ -35,6 +38,14 @@ export interface BottomSheetModalProps
*/
enableDismissOnClose?: boolean;
+ /**
+ * Add a custom container like FullWindowOverlay
+ * allow to fix issue like https://github.com/gorhom/react-native-bottom-sheet/issues/832
+ * @type React.ComponentType
+ * @default undefined
+ */
+ containerComponent?: React.ComponentType;
+
// callbacks
/**
* Callback when the modal dismissed.
@@ -44,10 +55,13 @@ export interface BottomSheetModalProps
/**
* A scrollable node or normal view.
- * @type React.ReactNode[] | React.ReactNode
+ * @type React.ReactNode[] | React.ReactNode | (({ data: any }?) => React.ReactElement)
*/
- children:
- | (({ data: any }?) => React.ReactNode)
- | React.ReactNode[]
- | React.ReactNode;
+ children: React.FC<{ data?: T }> | React.ReactNode[] | React.ReactNode;
+}
+
+// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.
+export interface BottomSheetModalState {
+ mount: boolean;
+ data: T | undefined;
}
diff --git a/src/components/bottomSheetModalProvider/BottomSheetModalProvider.tsx b/src/components/bottomSheetModalProvider/BottomSheetModalProvider.tsx
index 23a9f4dc9..2327d8a65 100644
--- a/src/components/bottomSheetModalProvider/BottomSheetModalProvider.tsx
+++ b/src/components/bottomSheetModalProvider/BottomSheetModalProvider.tsx
@@ -1,17 +1,20 @@
+import { PortalProvider } from '@gorhom/portal';
import React, { useCallback, useMemo, useRef } from 'react';
import { useSharedValue } from 'react-native-reanimated';
-import { PortalProvider } from '@gorhom/portal';
+import { MODAL_STACK_BEHAVIOR } from '../../constants';
import {
- BottomSheetModalProvider,
BottomSheetModalInternalProvider,
+ BottomSheetModalProvider,
} from '../../contexts';
-import BottomSheetContainer from '../bottomSheetContainer';
-import { MODAL_STACK_BEHAVIOR } from '../../constants';
import {
INITIAL_CONTAINER_HEIGHT,
INITIAL_CONTAINER_OFFSET,
} from '../bottomSheet/constants';
-import type { BottomSheetModalStackBehavior } from '../bottomSheetModal';
+import BottomSheetContainer from '../bottomSheetContainer';
+import type {
+ BottomSheetModalPrivateMethods,
+ BottomSheetModalStackBehavior,
+} from '../bottomSheetModal';
import type {
BottomSheetModalProviderProps,
BottomSheetModalRef,
@@ -31,7 +34,11 @@ const BottomSheetModalProviderWrapper = ({
//#region private methods
const handleMountSheet = useCallback(
- (key: string, ref: any, stackBehavior: BottomSheetModalStackBehavior) => {
+ (
+ key: string,
+ ref: React.RefObject,
+ stackBehavior: BottomSheetModalStackBehavior
+ ) => {
const _sheetsQueue = sheetsQueueRef.current.slice();
const sheetIndex = _sheetsQueue.findIndex(item => item.key === key);
const sheetOnTop = sheetIndex === _sheetsQueue.length - 1;
@@ -50,13 +57,19 @@ const BottomSheetModalProviderWrapper = ({
* - it is not unmounting.
* - stack behavior is 'replace'.
*/
+
+ /**
+ * Handle switch or replace stack behaviors, if:
+ * - a modal is currently presented.
+ * - it is not unmounting
+ */
const currentMountedSheet = _sheetsQueue[_sheetsQueue.length - 1];
- if (
- currentMountedSheet &&
- !currentMountedSheet.willUnmount &&
- stackBehavior === MODAL_STACK_BEHAVIOR.replace
- ) {
- currentMountedSheet.ref?.current?.minimize();
+ if (currentMountedSheet && !currentMountedSheet.willUnmount) {
+ if (stackBehavior === MODAL_STACK_BEHAVIOR.replace) {
+ currentMountedSheet.ref?.current?.dismiss();
+ } else if (stackBehavior === MODAL_STACK_BEHAVIOR.switch) {
+ currentMountedSheet.ref?.current?.minimize();
+ }
}
/**
@@ -185,7 +198,6 @@ const BottomSheetModalProviderWrapper = ({
{children}
diff --git a/src/components/bottomSheetModalProvider/types.d.ts b/src/components/bottomSheetModalProvider/types.d.ts
index 78f2464c6..5f44c310b 100644
--- a/src/components/bottomSheetModalProvider/types.d.ts
+++ b/src/components/bottomSheetModalProvider/types.d.ts
@@ -1,11 +1,9 @@
-import type { ReactNode } from 'react';
+import type { ReactNode, RefObject } from 'react';
import type { BottomSheetModalPrivateMethods } from '../bottomSheetModal';
export interface BottomSheetModalRef {
key: string;
- ref: {
- current: BottomSheetModalPrivateMethods;
- };
+ ref: RefObject;
willUnmount: boolean;
}
diff --git a/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx b/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx
index be502259c..395fcc5ad 100644
--- a/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx
+++ b/src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx
@@ -1,35 +1,80 @@
-import React, { forwardRef, memo } from 'react';
-import { RefreshControl, RefreshControlProps } from 'react-native';
-import { NativeViewGestureHandler } from 'react-native-gesture-handler';
+import React, { memo, useContext, useMemo } from 'react';
+import { RefreshControl, type RefreshControlProps } from 'react-native';
+import {
+ Gesture,
+ GestureDetector,
+ type SimultaneousGesture,
+} from 'react-native-gesture-handler';
import Animated, { useAnimatedProps } from 'react-native-reanimated';
import { SCROLLABLE_STATE } from '../../constants';
+import { BottomSheetDraggableContext } from '../../contexts/gesture';
import { useBottomSheetInternal } from '../../hooks';
const AnimatedRefreshControl = Animated.createAnimatedComponent(RefreshControl);
-const BottomSheetRefreshControlComponent = forwardRef<
- NativeViewGestureHandler,
- RefreshControlProps
->(({ onRefresh, ...rest }, ref) => {
- // hooks
- const { animatedScrollableState } = useBottomSheetInternal();
+interface BottomSheetRefreshControlProps extends RefreshControlProps {
+ scrollableGesture: SimultaneousGesture;
+}
- // variables
- const animatedProps = useAnimatedProps(() => ({
- enabled: animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED,
- }));
+function BottomSheetRefreshControlComponent({
+ onRefresh,
+ scrollableGesture,
+ ...rest
+}: BottomSheetRefreshControlProps) {
+ //#region hooks
+ const draggableGesture = useContext(BottomSheetDraggableContext);
+ const { animatedScrollableState, enableContentPanningGesture } =
+ useBottomSheetInternal();
+ //#endregion
+
+ if (!draggableGesture && enableContentPanningGesture) {
+ throw "'BottomSheetRefreshControl' cannot be used out of the BottomSheet!";
+ }
+
+ //#region variables
+ const animatedProps = useAnimatedProps(
+ () => ({
+ enabled: animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED,
+ }),
+ [animatedScrollableState.value]
+ );
+
+ const gesture = useMemo(
+ () =>
+ draggableGesture
+ ? Gesture.Native()
+ // @ts-ignore
+ .simultaneousWithExternalGesture(
+ ...draggableGesture.toGestureArray(),
+ ...scrollableGesture.toGestureArray()
+ )
+ .shouldCancelWhenOutside(true)
+ : undefined,
+ [draggableGesture, scrollableGesture]
+ );
+
+ //#endregion
// render
+ if (gesture) {
+ return (
+
+
+
+ );
+ }
return (
-
-
-
+
);
-});
+}
const BottomSheetRefreshControl = memo(BottomSheetRefreshControlComponent);
BottomSheetRefreshControl.displayName = 'BottomSheetRefreshControl';
diff --git a/src/components/bottomSheetRefreshControl/index.ts b/src/components/bottomSheetRefreshControl/index.ts
index ac07963d2..b716fa281 100644
--- a/src/components/bottomSheetRefreshControl/index.ts
+++ b/src/components/bottomSheetRefreshControl/index.ts
@@ -1,15 +1,19 @@
import type React from 'react';
import type { RefreshControlProps } from 'react-native';
-import type { NativeViewGestureHandlerProps } from 'react-native-gesture-handler';
+import type {
+ NativeViewGestureHandlerProps,
+ SimultaneousGesture,
+} from 'react-native-gesture-handler';
import BottomSheetRefreshControl from './BottomSheetRefreshControl';
-export default BottomSheetRefreshControl as any as React.MemoExoticComponent<
+export default BottomSheetRefreshControl as never as React.MemoExoticComponent<
React.ForwardRefExoticComponent<
RefreshControlProps & {
+ scrollableGesture: SimultaneousGesture;
children: React.ReactNode | React.ReactNode[];
} & React.RefAttributes<
React.ComponentType<
- NativeViewGestureHandlerProps & React.RefAttributes
+ NativeViewGestureHandlerProps & React.RefAttributes
>
>
>
diff --git a/src/components/bottomSheetScrollable/BottomSheetDraggableScrollable.tsx b/src/components/bottomSheetScrollable/BottomSheetDraggableScrollable.tsx
new file mode 100644
index 000000000..92d035a9a
--- /dev/null
+++ b/src/components/bottomSheetScrollable/BottomSheetDraggableScrollable.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import {
+ GestureDetector,
+ type SimultaneousGesture,
+} from 'react-native-gesture-handler';
+
+interface BottomSheetDraggableScrollableProps {
+ scrollableGesture?: SimultaneousGesture;
+ children: React.ReactNode;
+}
+
+export function BottomSheetDraggableScrollable({
+ scrollableGesture,
+ children,
+}: BottomSheetDraggableScrollableProps) {
+ if (scrollableGesture) {
+ return (
+ {children}
+ );
+ }
+
+ return children;
+}
diff --git a/src/components/bottomSheetScrollable/BottomSheetFlashList.tsx b/src/components/bottomSheetScrollable/BottomSheetFlashList.tsx
new file mode 100644
index 000000000..542460316
--- /dev/null
+++ b/src/components/bottomSheetScrollable/BottomSheetFlashList.tsx
@@ -0,0 +1,82 @@
+// @ts-ignore
+import type { FlashListProps } from '@shopify/flash-list';
+import React, { forwardRef, memo, useMemo } from 'react';
+import { type ScrollViewProps, StyleSheet } from 'react-native';
+import BottomSheetScrollView from './BottomSheetScrollView';
+import type {
+ BottomSheetFlashListProps,
+ BottomSheetScrollViewMethods,
+} from './types';
+
+let FlashList: {
+ FlashList: React.FC;
+};
+// since FlashList is not a dependency for the library
+// we try to import it using metro optional import
+try {
+ FlashList = require('@shopify/flash-list') as never;
+} catch (_) {}
+
+const BottomSheetFlashListComponent = forwardRef<
+ React.FC,
+ // biome-ignore lint/suspicious/noExplicitAny: to be addressed
+ BottomSheetFlashListProps
+>((props, ref) => {
+ //#region props
+ const {
+ focusHook,
+ scrollEventsHandlersHook,
+ enableFooterMarginAdjustment,
+ ...rest
+ // biome-ignore lint: to be addressed!
+ }: any = props;
+ //#endregion
+
+ useMemo(() => {
+ if (!FlashList) {
+ throw 'You need to install FlashList first, `yarn install @shopify/flash-list`';
+ }
+ }, []);
+
+ //#region render
+ const renderScrollComponent = useMemo(
+ () =>
+ forwardRef(
+ // @ts-ignore
+ ({ data, ...props }, ref) => {
+ return (
+ // @ts-ignore
+
+ );
+ }
+ ),
+ [focusHook, scrollEventsHandlersHook, enableFooterMarginAdjustment]
+ );
+ return (
+
+ );
+ //#endregion
+});
+
+export const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ overflow: 'visible',
+ },
+});
+
+export const BottomSheetFlashList = memo(BottomSheetFlashListComponent);
+
+export default BottomSheetFlashList as (
+ props: BottomSheetFlashListProps
+) => ReturnType;
diff --git a/src/components/bottomSheetScrollable/BottomSheetFlatList.tsx b/src/components/bottomSheetScrollable/BottomSheetFlatList.tsx
index 6d3c1b797..9bc7c5f6b 100644
--- a/src/components/bottomSheetScrollable/BottomSheetFlatList.tsx
+++ b/src/components/bottomSheetScrollable/BottomSheetFlatList.tsx
@@ -1,8 +1,5 @@
-import { memo } from 'react';
-import {
- FlatList as RNFlatList,
- FlatListProps as RNFlatListProps,
-} from 'react-native';
+import { type ComponentProps, memo } from 'react';
+import { FlatList as RNFlatList } from 'react-native';
import Animated from 'react-native-reanimated';
import { SCROLLABLE_TYPE } from '../../constants';
import { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';
@@ -12,11 +9,13 @@ import type {
} from './types';
const AnimatedFlatList =
- Animated.createAnimatedComponent>(RNFlatList);
+ Animated.createAnimatedComponent>(
+ RNFlatList
+ );
const BottomSheetFlatListComponent = createBottomSheetScrollableComponent<
BottomSheetFlatListMethods,
- BottomSheetFlatListProps
+ BottomSheetFlatListProps
>(SCROLLABLE_TYPE.FLATLIST, AnimatedFlatList);
const BottomSheetFlatList = memo(BottomSheetFlatListComponent);
diff --git a/src/components/bottomSheetScrollable/BottomSheetScrollView.tsx b/src/components/bottomSheetScrollable/BottomSheetScrollView.tsx
index 6463c4ddf..68be6ef5b 100644
--- a/src/components/bottomSheetScrollable/BottomSheetScrollView.tsx
+++ b/src/components/bottomSheetScrollable/BottomSheetScrollView.tsx
@@ -1,7 +1,7 @@
import { memo } from 'react';
import {
ScrollView as RNScrollView,
- ScrollViewProps as RNScrollViewProps,
+ type ScrollViewProps as RNScrollViewProps,
} from 'react-native';
import Animated from 'react-native-reanimated';
import { SCROLLABLE_TYPE } from '../../constants';
diff --git a/src/components/bottomSheetScrollable/BottomSheetSectionList.tsx b/src/components/bottomSheetScrollable/BottomSheetSectionList.tsx
index 6e046f192..968be38cf 100644
--- a/src/components/bottomSheetScrollable/BottomSheetSectionList.tsx
+++ b/src/components/bottomSheetScrollable/BottomSheetSectionList.tsx
@@ -1,8 +1,7 @@
-import { memo } from 'react';
+import { type ComponentProps, memo } from 'react';
import {
- DefaultSectionT,
+ type DefaultSectionT,
SectionList as RNSectionList,
- SectionListProps as RNSectionListProps,
} from 'react-native';
import Animated from 'react-native-reanimated';
import { SCROLLABLE_TYPE } from '../../constants';
@@ -13,11 +12,13 @@ import type {
} from './types';
const AnimatedSectionList =
- Animated.createAnimatedComponent>(RNSectionList);
+ Animated.createAnimatedComponent>(
+ RNSectionList
+ );
const BottomSheetSectionListComponent = createBottomSheetScrollableComponent<
BottomSheetSectionListMethods,
- BottomSheetSectionListProps
+ BottomSheetSectionListProps
>(SCROLLABLE_TYPE.SECTIONLIST, AnimatedSectionList);
const BottomSheetSectionList = memo(BottomSheetSectionListComponent);
diff --git a/src/components/bottomSheetScrollable/BottomSheetVirtualizedList.tsx b/src/components/bottomSheetScrollable/BottomSheetVirtualizedList.tsx
index df2ad015e..db636bb5c 100644
--- a/src/components/bottomSheetScrollable/BottomSheetVirtualizedList.tsx
+++ b/src/components/bottomSheetScrollable/BottomSheetVirtualizedList.tsx
@@ -1,8 +1,5 @@
-import { memo } from 'react';
-import {
- VirtualizedList as RNVirtualizedList,
- VirtualizedListProps as RNVirtualizedListProps,
-} from 'react-native';
+import { type ComponentProps, memo } from 'react';
+import { VirtualizedList as RNVirtualizedList } from 'react-native';
import Animated from 'react-native-reanimated';
import { SCROLLABLE_TYPE } from '../../constants';
import { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';
@@ -12,14 +9,14 @@ import type {
} from './types';
const AnimatedVirtualizedList =
- Animated.createAnimatedComponent>(
+ Animated.createAnimatedComponent>(
RNVirtualizedList
);
const BottomSheetVirtualizedListComponent =
createBottomSheetScrollableComponent<
BottomSheetVirtualizedListMethods,
- BottomSheetVirtualizedListProps
+ BottomSheetVirtualizedListProps
>(SCROLLABLE_TYPE.VIRTUALIZEDLIST, AnimatedVirtualizedList);
const BottomSheetVirtualizedList = memo(BottomSheetVirtualizedListComponent);
diff --git a/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx b/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx
new file mode 100644
index 000000000..1f944e06f
--- /dev/null
+++ b/src/components/bottomSheetScrollable/ScrollableContainer.android.tsx
@@ -0,0 +1,55 @@
+import React, { forwardRef } from 'react';
+import type { SimultaneousGesture } from 'react-native-gesture-handler';
+import BottomSheetRefreshControl from '../bottomSheetRefreshControl';
+import { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';
+import { styles } from './styles';
+
+interface ScrollableContainerProps {
+ nativeGesture: SimultaneousGesture;
+ // biome-ignore lint: to be addressed
+ refreshControl: any;
+ // biome-ignore lint: to be addressed
+ progressViewOffset: any;
+ // biome-ignore lint: to be addressed
+ refreshing: any;
+ // biome-ignore lint: to be addressed
+ onRefresh: any;
+ // biome-ignore lint: to be addressed
+ ScrollableComponent: any;
+}
+
+// biome-ignore lint: to be addressed
+export const ScrollableContainer = forwardRef(
+ function ScrollableContainer(
+ {
+ nativeGesture,
+ refreshControl: _refreshControl,
+ refreshing,
+ progressViewOffset,
+ onRefresh,
+ ScrollableComponent,
+ ...rest
+ },
+ ref
+ ) {
+ const Scrollable = (
+
+
+
+ );
+
+ return onRefresh ? (
+
+ {Scrollable}
+
+ ) : (
+ Scrollable
+ );
+ }
+);
diff --git a/src/components/bottomSheetScrollable/ScrollableContainer.tsx b/src/components/bottomSheetScrollable/ScrollableContainer.tsx
new file mode 100644
index 000000000..ab3bc59b2
--- /dev/null
+++ b/src/components/bottomSheetScrollable/ScrollableContainer.tsx
@@ -0,0 +1,22 @@
+import React, { type FC, forwardRef } from 'react';
+import type { SimultaneousGesture } from 'react-native-gesture-handler';
+import { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';
+
+interface ScrollableContainerProps {
+ nativeGesture?: SimultaneousGesture;
+ // biome-ignore lint/suspicious/noExplicitAny: 🤷♂️
+ ScrollableComponent: FC;
+}
+
+export const ScrollableContainer = forwardRef(
+ function ScrollableContainer(
+ { nativeGesture, ScrollableComponent, ...rest },
+ ref
+ ) {
+ return (
+
+
+
+ );
+ }
+);
diff --git a/src/components/bottomSheetScrollable/ScrollableContainer.web.tsx b/src/components/bottomSheetScrollable/ScrollableContainer.web.tsx
new file mode 100644
index 000000000..7b56c9742
--- /dev/null
+++ b/src/components/bottomSheetScrollable/ScrollableContainer.web.tsx
@@ -0,0 +1,89 @@
+import React, {
+ type ComponentProps,
+ forwardRef,
+ useCallback,
+ useRef,
+} from 'react';
+import type { LayoutChangeEvent, ViewProps } from 'react-native';
+import type { SimultaneousGesture } from 'react-native-gesture-handler';
+import Animated from 'react-native-reanimated';
+import { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';
+
+interface ScrollableContainerProps {
+ nativeGesture: SimultaneousGesture;
+ setContentSize: (contentHeight: number) => void;
+ // biome-ignore lint/suspicious/noExplicitAny: 🤷♂️
+ ScrollableComponent: any;
+ onLayout: ViewProps['onLayout'];
+}
+
+/**
+ * Detect if the current browser is Safari or not.
+ */
+const isWebkit = () => {
+ // @ts-ignore
+ return navigator.userAgent.indexOf('Safari') > -1;
+};
+
+export const ScrollableContainer = forwardRef<
+ never,
+ ScrollableContainerProps & { animatedProps: never }
+>(function ScrollableContainer(
+ {
+ nativeGesture,
+ ScrollableComponent,
+ animatedProps,
+ setContentSize,
+ onLayout,
+ ...rest
+ },
+ ref
+) {
+ //#region refs
+ const isInitialContentHeightCaptured = useRef(false);
+ //#endregion
+
+ //#region callbacks
+ const renderScrollComponent = useCallback(
+ (props: ComponentProps) => (
+
+ ),
+ [animatedProps]
+ );
+
+ /**
+ * A workaround a bug in React Native Web [#1502](https://github.com/necolas/react-native-web/issues/1502),
+ * where the `onContentSizeChange` won't be call on initial render.
+ */
+ const handleOnLayout = useCallback(
+ (event: LayoutChangeEvent) => {
+ if (onLayout) {
+ onLayout(event);
+ }
+
+ if (!isInitialContentHeightCaptured.current) {
+ isInitialContentHeightCaptured.current = true;
+ if (!isWebkit()) {
+ return;
+ }
+ // @ts-ignore
+ window.requestAnimationFrame(() => {
+ // @ts-ignore
+ setContentSize(event.nativeEvent.target.clientHeight);
+ });
+ }
+ },
+ [onLayout, setContentSize]
+ );
+ //#endregion
+ return (
+
+
+
+ );
+});
diff --git a/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx b/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx
index 49237cb9d..8e7cffafb 100644
--- a/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx
+++ b/src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx
@@ -1,28 +1,33 @@
-import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
-import { Platform } from 'react-native';
+import React, {
+ forwardRef,
+ useContext,
+ useImperativeHandle,
+ useMemo,
+} from 'react';
+import { Gesture } from 'react-native-gesture-handler';
import { useAnimatedProps, useAnimatedStyle } from 'react-native-reanimated';
-import { NativeViewGestureHandler } from 'react-native-gesture-handler';
-import BottomSheetDraggableView from '../bottomSheetDraggableView';
-import BottomSheetRefreshControl from '../bottomSheetRefreshControl';
import {
- useScrollHandler,
- useScrollableSetter,
- useBottomSheetInternal,
-} from '../../hooks';
-import {
- GESTURE_SOURCE,
SCROLLABLE_DECELERATION_RATE_MAPPER,
SCROLLABLE_STATE,
- SCROLLABLE_TYPE,
+ type SCROLLABLE_TYPE,
} from '../../constants';
-import { styles } from './styles';
+import { BottomSheetDraggableContext } from '../../contexts/gesture';
+import {
+ useBottomSheetInternal,
+ useScrollHandler,
+ useScrollableSetter,
+ useStableCallback,
+} from '../../hooks';
+import { ScrollableContainer } from './ScrollableContainer';
+import { useBottomSheetContentSizeSetter } from './useBottomSheetContentSizeSetter';
export function createBottomSheetScrollableComponent(
type: SCROLLABLE_TYPE,
+ // biome-ignore lint: to be addressed!
ScrollableComponent: any
) {
return forwardRef((props, ref) => {
- // props
+ //#region props
const {
// hooks
focusHook,
@@ -37,43 +42,75 @@ export function createBottomSheetScrollableComponent(
onRefresh,
progressViewOffset,
refreshControl,
+ scrollBuffer,
+ preserveScrollMomentum,
+ lockableScrollableContentOffsetY,
// events
onScroll,
onScrollBeginDrag,
onScrollEndDrag,
+ onContentSizeChange,
...rest
+ // biome-ignore lint: to be addressed!
}: any = props;
-
- //#region refs
- const nativeGestureRef = useRef(null);
- const refreshControlGestureRef = useRef(null);
//#endregion
//#region hooks
+ const draggableGesture = useContext(BottomSheetDraggableContext);
const { scrollableRef, scrollableContentOffsetY, scrollHandler } =
useScrollHandler(
scrollEventsHandlersHook,
onScroll,
onScrollBeginDrag,
- onScrollEndDrag
+ onScrollEndDrag,
+ scrollBuffer,
+ preserveScrollMomentum,
+ lockableScrollableContentOffsetY
);
const {
- enableContentPanningGesture,
animatedFooterHeight,
animatedScrollableState,
+ enableContentPanningGesture,
} = useBottomSheetInternal();
+ const { setContentSize } = useBottomSheetContentSizeSetter();
//#endregion
+ if (!draggableGesture && enableContentPanningGesture) {
+ throw "'Scrollable' cannot be used out of the BottomSheet!";
+ }
+
//#region variables
const scrollableAnimatedProps = useAnimatedProps(
() => ({
- decelerationRate:
- SCROLLABLE_DECELERATION_RATE_MAPPER[animatedScrollableState.value],
+ ...(preserveScrollMomentum ? {} : {decelerationRate: SCROLLABLE_DECELERATION_RATE_MAPPER[animatedScrollableState.value]}),
showsVerticalScrollIndicator: showsVerticalScrollIndicator
? animatedScrollableState.value === SCROLLABLE_STATE.UNLOCKED
: showsVerticalScrollIndicator,
}),
- [showsVerticalScrollIndicator]
+ [animatedScrollableState, showsVerticalScrollIndicator]
+ );
+
+ const scrollableGesture = useMemo(
+ () =>
+ draggableGesture
+ ? Gesture.Native()
+ // @ts-ignore
+ .simultaneousWithExternalGesture(draggableGesture)
+ .shouldCancelWhenOutside(false)
+ : undefined,
+ [draggableGesture]
+ );
+ //#endregion
+
+ //#region callbacks
+ const handleContentSizeChange = useStableCallback(
+ (contentWidth: number, contentHeight: number) => {
+ setContentSize(contentHeight);
+
+ if (onContentSizeChange) {
+ onContentSizeChange(contentWidth, contentHeight);
+ }
+ }
);
//#endregion
@@ -84,7 +121,7 @@ export function createBottomSheetScrollableComponent(
? animatedFooterHeight.value
: 0,
}),
- [enableFooterMarginAdjustment]
+ [animatedFooterHeight, enableFooterMarginAdjustment]
);
const containerStyle = useMemo(() => {
return enableFooterMarginAdjustment
@@ -104,80 +141,32 @@ export function createBottomSheetScrollableComponent(
type,
scrollableContentOffsetY,
onRefresh !== undefined,
+ scrollBuffer,
+ preserveScrollMomentum,
focusHook
);
//#endregion
//#region render
- if (Platform.OS === 'android') {
- const scrollableContent = (
-
-
-
- );
- return (
-
- {onRefresh ? (
-
- {scrollableContent}
-
- ) : (
- scrollableContent
- )}
-
- );
- }
return (
-
-
-
-
-
+
);
//#endregion
});
diff --git a/src/components/bottomSheetScrollable/index.ts b/src/components/bottomSheetScrollable/index.ts
index c2aad37a5..e07fcaa40 100644
--- a/src/components/bottomSheetScrollable/index.ts
+++ b/src/components/bottomSheetScrollable/index.ts
@@ -4,6 +4,8 @@ export { default as BottomSheetFlatList } from './BottomSheetFlatList';
export { default as BottomSheetScrollView } from './BottomSheetScrollView';
export { default as BottomSheetVirtualizedList } from './BottomSheetVirtualizedList';
+export { default as BottomSheetFlashList } from './BottomSheetFlashList';
+
export type {
BottomSheetFlatListMethods,
BottomSheetScrollViewMethods,
diff --git a/src/components/bottomSheetScrollable/types.d.ts b/src/components/bottomSheetScrollable/types.d.ts
index 2822dbafc..a9ca5c602 100644
--- a/src/components/bottomSheetScrollable/types.d.ts
+++ b/src/components/bottomSheetScrollable/types.d.ts
@@ -6,18 +6,19 @@ import type {
RefObject,
} from 'react';
import type {
- ScrollView,
- VirtualizedListProps,
- ScrollViewProps,
FlatListProps,
+ NodeHandle,
+ ScrollResponderMixin,
+ ScrollViewComponent,
+ ScrollViewProps,
SectionListProps,
SectionListScrollParams,
View,
- ScrollViewComponent,
- NodeHandle,
+ VirtualizedListProps,
} from 'react-native';
import type Animated from 'react-native-reanimated';
import type { ScrollEventsHandlersHookType } from '../../types';
+import type { FlashListProps } from '@shopify/flash-list';
export interface BottomSheetScrollableProps {
/**
@@ -47,17 +48,33 @@ export interface BottomSheetScrollableProps {
* @default useScrollEventsHandlersDefault
*/
scrollEventsHandlersHook?: ScrollEventsHandlersHookType;
+
+ /**
+ * An initial scroll buffer to prevent the bottom sheet from immediately following the scroll gesture.
+ */
+ scrollBuffer?: number;
+
+ /**
+ * Whether or not to preserve scroll momentum when expanding a scrollable bottom sheet component.
+ */
+ preserveScrollMomentum?: boolean;
+
+ /**
+ * The optional lockable scrollable content offset ref, which will remain the same value when scrollable is locked.
+ */
+ lockableScrollableContentOffsetY?: Animated.SharedValue;
}
export type ScrollableProps =
| ScrollViewProps
| FlatListProps
+ | FlashListProps
| SectionListProps;
//#region FlatList
export type BottomSheetFlatListProps = Omit<
Animated.AnimateProps>,
- 'decelerationRate' | 'onScroll' | 'scrollEventThrottle'
+ 'decelerationRate' | 'scrollEventThrottle'
> &
BottomSheetScrollableProps & {
ref?: Ref;
@@ -81,6 +98,88 @@ export interface BottomSheetFlatListMethods {
viewPosition?: number;
}) => void;
+ /**
+ * Requires linear scan through data - use `scrollToIndex` instead if possible.
+ * May be janky without `getItemLayout` prop.
+ */
+ scrollToItem: (params: {
+ animated?: boolean | null;
+ // biome-ignore lint: to be addressed!
+ item: any;
+ viewPosition?: number;
+ }) => void;
+
+ /**
+ * Scroll to a specific content pixel offset, like a normal `ScrollView`.
+ */
+ scrollToOffset: (params: {
+ animated?: boolean | null;
+ offset: number;
+ }) => void;
+
+ /**
+ * Tells the list an interaction has occured, which should trigger viewability calculations,
+ * e.g. if waitForInteractions is true and the user has not scrolled. This is typically called
+ * by taps on items or by navigation actions.
+ */
+ recordInteraction: () => void;
+
+ /**
+ * Displays the scroll indicators momentarily.
+ */
+ flashScrollIndicators: () => void;
+
+ /**
+ * Provides a handle to the underlying scroll responder.
+ */
+ getScrollResponder: () => ScrollResponderMixin | null | undefined;
+
+ /**
+ * Provides a reference to the underlying host component
+ */
+ getNativeScrollRef: () =>
+ | RefObject
+ | RefObject
+ | null
+ | undefined;
+
+ // biome-ignore lint: to be addressed!
+ getScrollableNode: () => any;
+
+ // biome-ignore lint: to be addressed!
+ setNativeProps: (props: { [key: string]: any }) => void;
+}
+//#endregion
+
+//#region FlatList
+export type BottomSheetFlashListProps = Omit<
+ FlashListProps,
+ | 'decelerationRate'
+ | 'scrollEventThrottle'
+ | 'renderScrollComponent'
+> &
+ BottomSheetScrollableProps & {
+ ref?: Ref;
+ };
+
+export interface BottomSheetFlashListMethods {
+ /**
+ * Scrolls to the end of the content. May be janky without `getItemLayout` prop.
+ */
+ scrollToEnd: (params?: { animated?: boolean | null }) => void;
+
+ /**
+ * Scrolls to the item at the specified index such that it is positioned in the viewable area
+ * such that viewPosition 0 places it at the top, 1 at the bottom, and 0.5 centered in the middle.
+ * Cannot scroll to locations outside the render window without specifying the getItemLayout prop.
+ */
+ scrollToIndex: (params: {
+ animated?: boolean | null;
+ index: number;
+ viewOffset?: number;
+ viewPosition?: number;
+ }) => void;
+
/**
* Requires linear scan through data - use `scrollToIndex` instead if possible.
* May be janky without `getItemLayout` prop.
@@ -114,7 +213,7 @@ export interface BottomSheetFlatListMethods {
/**
* Provides a handle to the underlying scroll responder.
*/
- getScrollResponder: () => ReactNode | null | undefined;
+ getScrollResponder: () => ScrollResponderMixin | null | undefined;
/**
* Provides a reference to the underlying host component
@@ -127,6 +226,11 @@ export interface BottomSheetFlatListMethods {
getScrollableNode: () => any;
+ /**
+ * Recalculates viewable items.
+ */
+ updateViewableItems: () => void;
+
// TODO: use `unknown` instead of `any` for Typescript >= 3.0
setNativeProps: (props: { [key: string]: any }) => void;
}
@@ -175,11 +279,12 @@ export interface BottomSheetScrollViewMethods {
* implement this method so that they can be composed while providing access
* to the underlying scroll responder's methods.
*/
- getScrollResponder(): ReactNode;
+ getScrollResponder(): ScrollResponderMixin;
+ // biome-ignore lint: to be addressed!
getScrollableNode(): any;
- // Undocumented
+ // biome-ignore lint: to be addressed!
getInnerViewNode(): any;
/**
@@ -198,7 +303,7 @@ export interface BottomSheetScrollViewMethods {
//#endregion
//#region SectionList
-type BottomSheetSectionListProps = Omit<
+export type BottomSheetSectionListProps = Omit<
Animated.AnimateProps>,
'decelerationRate' | 'scrollEventThrottle'
> &
@@ -231,7 +336,7 @@ export interface BottomSheetSectionListMethods {
/**
* Provides a handle to the underlying scroll responder.
*/
- getScrollResponder(): ScrollView | undefined;
+ getScrollResponder(): ScrollResponderMixin | undefined;
/**
* Provides a handle to the underlying scroll node.
@@ -259,6 +364,7 @@ export interface BottomSheetVirtualizedListMethods {
}) => void;
scrollToItem: (params: {
animated?: boolean;
+ // biome-ignore lint: to be addressed!
item: any;
viewPosition?: number;
}) => void;
diff --git a/src/components/bottomSheetScrollable/useBottomSheetContentSizeSetter.ts b/src/components/bottomSheetScrollable/useBottomSheetContentSizeSetter.ts
new file mode 100644
index 000000000..1d3380e3f
--- /dev/null
+++ b/src/components/bottomSheetScrollable/useBottomSheetContentSizeSetter.ts
@@ -0,0 +1,29 @@
+import { useCallback } from 'react';
+import { useBottomSheetInternal } from '../../hooks';
+
+/**
+ * A hook to set the content size properly into the bottom sheet,
+ * internals.
+ */
+export function useBottomSheetContentSizeSetter() {
+ //#region hooks
+ const { enableDynamicSizing, animatedContentHeight } =
+ useBottomSheetInternal();
+ //#endregion
+
+ //#region methods
+ const setContentSize = useCallback(
+ (contentHeight: number) => {
+ if (!enableDynamicSizing) {
+ return;
+ }
+ animatedContentHeight.value = contentHeight;
+ },
+ [enableDynamicSizing, animatedContentHeight]
+ );
+ //#endregion
+
+ return {
+ setContentSize,
+ };
+}
diff --git a/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx b/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx
index eae09f7d4..aef8ab7f5 100644
--- a/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx
+++ b/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx
@@ -1,4 +1,8 @@
-import React, { memo, useCallback, forwardRef } from 'react';
+import React, { memo, useCallback, forwardRef, useEffect } from 'react';
+import type {
+ NativeSyntheticEvent,
+ TextInputFocusEventData,
+} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { useBottomSheetInternal } from '../../hooks';
import type { BottomSheetTextInputProps } from './types';
@@ -13,7 +17,7 @@ const BottomSheetTextInputComponent = forwardRef<
//#region callbacks
const handleOnFocus = useCallback(
- args => {
+ (args: NativeSyntheticEvent) => {
shouldHandleKeyboardEvents.value = true;
if (onFocus) {
onFocus(args);
@@ -22,7 +26,7 @@ const BottomSheetTextInputComponent = forwardRef<
[onFocus, shouldHandleKeyboardEvents]
);
const handleOnBlur = useCallback(
- args => {
+ (args: NativeSyntheticEvent) => {
shouldHandleKeyboardEvents.value = false;
if (onBlur) {
onBlur(args);
@@ -32,6 +36,14 @@ const BottomSheetTextInputComponent = forwardRef<
);
//#endregion
+ //#region effects
+ useEffect(() => {
+ return () => {
+ // Reset the flag on unmount
+ shouldHandleKeyboardEvents.value = false;
+ };
+ }, [shouldHandleKeyboardEvents]);
+ //#endregion
return (
{
- const flattenStyle = StyleSheet.flatten(style);
- const paddingBottom =
- flattenStyle && 'paddingBottom' in flattenStyle
- ? flattenStyle.paddingBottom
- : 0;
- return typeof paddingBottom === 'number' ? paddingBottom : 0;
- }, [style]);
- const containerAnimatedStyle = useAnimatedStyle(
- () => ({
- paddingBottom: enableFooterMarginAdjustment
- ? animatedFooterHeight.value + containerStylePaddingBottom
- : containerStylePaddingBottom,
- }),
- [containerStylePaddingBottom, enableFooterMarginAdjustment]
- );
- const containerStyle = useMemo(
- () => [style, containerAnimatedStyle],
- [style, containerAnimatedStyle]
+ //#region styles
+ const flattenStyle = useMemo(
+ () => StyleSheet.flatten(style),
+ [style]
);
+ const containerStyle = useAnimatedStyle(() => {
+ if (!enableFooterMarginAdjustment) {
+ return flattenStyle ?? {};
+ }
+
+ const marginBottom =
+ typeof flattenStyle?.marginBottom === 'number'
+ ? flattenStyle.marginBottom
+ : 0;
- // callback
+ return {
+ ...(flattenStyle ?? {}),
+ marginBottom: marginBottom + animatedFooterHeight.value,
+ };
+ }, [flattenStyle, enableFooterMarginAdjustment, animatedFooterHeight]);
+ //#endregion
+
+ //#region callbacks
const handleSettingScrollable = useCallback(() => {
animatedScrollableContentOffsetY.value = 0;
animatedScrollableType.value = SCROLLABLE_TYPE.VIEW;
}, [animatedScrollableContentOffsetY, animatedScrollableType]);
+ const handleLayout = useCallback(
+ (event: LayoutChangeEvent) => {
+ if (enableDynamicSizing) {
+ animatedContentHeight.value = event.nativeEvent.layout.height;
+ }
+
+ if (onLayout) {
+ onLayout(event);
+ }
+
+ if (__DEV__) {
+ print({
+ component: BottomSheetView.displayName,
+ method: 'handleLayout',
+ category: 'layout',
+ params: {
+ height: event.nativeEvent.layout.height,
+ },
+ });
+ }
+ },
+ [onLayout, animatedContentHeight, enableDynamicSizing]
+ );
+ //#endregion
// effects
useFocusHook(handleSettingScrollable);
//render
return (
-