` | - |
29 | | onHeaderLayout | function - `(e: LayoutChangeEvent) => void` | - |
30 | | onMomentumScrollBegin | worklet function - `(e: NativeScrollEvent) => void` | - |
31 | | onMomentumScrollEnd | worklet function - `(e: NativeScrollEvent) => void` | - |
32 | | onScroll | worklet function - `(e: NativeScrollEvent) => void` | - |
33 | | onScrollBeginDrag | worklet function - `(e: NativeScrollEvent) => void` | - |
34 | | onScrollEndDrag | worklet function - `(e: NativeScrollEvent) => void` | - |
35 | | onTabsLayout | function - `(e: LayoutChangeEvent) => void` | - |
36 | | renderHeader | render function | - |
37 | | renderTabs | render function | - |
38 | | stickyTabs | boolean | true |
39 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-1.0.x/headers/flashlist-headers.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 6
3 | ---
4 |
5 | # FlashList Headers
6 |
7 | To make [FlashList](https://shopify.github.io/flash-list/docs/) work with react-native-sticky-parallax-header predefined layouts, there are 3 HOCs provided:
8 |
9 | - `withAvatarHeaderFlashList`
10 | - `withDetailsHeaderFlashList`
11 | - `withTabbedHeaderFlashList`
12 |
13 | ## Example usage
14 |
15 | For full examples check:
16 |
17 | - [AvatarHeaderFlashList](https://github.com/netguru/sticky-parallax-header/blob/master/example/src/screens/additionalExamples/AvatarHeaderFlashListExample.tsx)
18 | - [DetailsHeaderFlashList](https://github.com/netguru/sticky-parallax-header/blob/master/example/src/screens/additionalExamples/DetailsHeaderFlashListExample.tsx)
19 | - [TabbedHeaderFlashList](https://github.com/netguru/sticky-parallax-header/blob/master/example/src/screens/additionalExamples/TabbedHeaderFlashListExample.tsx)
20 |
21 | ## Props
22 |
23 | ### AvatarHeaderFlashList props
24 |
25 | Inherits [FlashListProps](https://shopify.github.io/flash-list/docs/usage) and [Shared AvatarHeader props](./avatar-header.md#shared-avatarheader-props)
26 |
27 | ### DetailsHeaderFlashList props
28 |
29 | Inherits [FlashListProps](https://shopify.github.io/flash-list/docs/usage) and [Shared DetailsHeader props](./details-header.md#shared-detailsheader-props)
30 |
31 | ### TabbedHeaderFlashList props
32 |
33 | Inherits [FlashListProps](https://shopify.github.io/flash-list/docs/usage) and [TabbedHeaderList props](./tabbed-header-list.md#props)
34 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-1.0.x/introduction/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Introduction",
3 | "position": 1
4 | }
5 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-1.0.x/introduction/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Installation
6 |
7 | ## Installation & requirements
8 |
9 | :::info
10 | Library supports react-native version 0.64+
11 | :::
12 |
13 | ### Install latest library version
14 |
15 | ```sh
16 | $ yarn add react-native-sticky-parallax-header@rc
17 | ```
18 |
19 | ### Prerequisites
20 |
21 | ```sh
22 | yarn add react-native-reanimated react-native-safe-area-context
23 | ```
24 |
25 | After installation:
26 | - check Reanimated installation [guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation)
27 | - handle Pods installation with `npx pod-install`
28 | - wrap your root component with `SafeAreaProvider` from `react-native-safe-area-context`
29 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-1.0.x/introduction/web-support.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 5
3 | ---
4 |
5 | # Web support
6 |
7 | `react-native-sticky-parallax-header` is supported in web projects built with [`react-native-web`](https://github.com/necolas/react-native-web) with 2 limitations:
8 |
9 | - "snap effect" props are not supported on web, because of lack support for [momentum scroll events](https://github.com/necolas/react-native-web/issues/1021) on `react-native-web`
10 | - using `RefreshControl` on web, can break sticky header layout, because web implementation is just stubbed and doubles ScrollView's margin/padding - [check pull-to-refresh guide](../guides/pull-to-refresh.md)
11 |
--------------------------------------------------------------------------------
/docs/versioned_sidebars/version-0.4.x-sidebars.json:
--------------------------------------------------------------------------------
1 | {
2 | "tutorialSidebar": [{ "type": "autogenerated", "dirName": "." }]
3 | }
4 |
--------------------------------------------------------------------------------
/docs/versioned_sidebars/version-1.0.x-sidebars.json:
--------------------------------------------------------------------------------
1 | {
2 | "tutorialSidebar": [{ "type": "autogenerated", "dirName": "." }]
3 | }
4 |
--------------------------------------------------------------------------------
/docs/versions.json:
--------------------------------------------------------------------------------
1 | [
2 | "1.0.x",
3 | "0.4.x"
4 | ]
5 |
--------------------------------------------------------------------------------
/example/.bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/example/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.4
2 |
--------------------------------------------------------------------------------
/example/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
3 | ruby '2.7.4'
4 | gem 'cocoapods', '~> 1.11', '>= 1.11.2'
5 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Sticky Header Example
2 |
3 | To run example app:
4 |
5 | ## Android
6 |
7 | ```sh
8 | yarn android
9 | ```
10 |
11 | ## iOS
12 |
13 | ```sh
14 | yarn ios
15 | ```
16 |
17 | ## Web
18 |
19 | ```sh
20 | yarn web
21 | ```
22 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Android/IntelliJ
6 | #
7 | build/
8 | .idea
9 | .gradle
10 | local.properties
11 | *.iml
12 | *.hprof
13 |
14 | # BUCK
15 | buck-out/
16 | \.buckd/
17 | *.keystore
18 | !debug.keystore
19 |
20 | # Bundle artifacts
21 | *.jsbundle
22 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.reactnativestickyparallaxheaderexample",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.reactnativestickyparallaxheaderexample",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/example/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/example/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/debug.keystore
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # react-native-reanimated
11 | -keep class com.swmansion.reanimated.** { *; }
12 | -keep class com.facebook.react.turbomodule.** { *; }
13 |
14 | # Add any project specific keep options here:
15 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/reactnativestickyparallaxheaderexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.reactnativestickyparallaxheaderexample;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 |
6 | import com.facebook.react.ReactActivity;
7 | import com.facebook.react.ReactActivityDelegate;
8 | import com.facebook.react.ReactRootView;
9 |
10 | import expo.modules.ReactActivityDelegateWrapper;
11 |
12 | public class MainActivity extends ReactActivity {
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | // Set the theme to AppTheme BEFORE onCreate to support
16 | // coloring the background, status bar, and navigation bar.
17 | // This is required for expo-splash-screen.
18 | setTheme(R.style.AppTheme);
19 | super.onCreate(null);
20 | }
21 |
22 | /**
23 | * Returns the name of the main component registered from JavaScript.
24 | * This is used to schedule rendering of the component.
25 | */
26 | @Override
27 | protected String getMainComponentName() {
28 | return "main";
29 | }
30 |
31 | @Override
32 | protected ReactActivityDelegate createReactActivityDelegate() {
33 | return new ReactActivityDelegateWrapper(this,
34 | new ReactActivityDelegate(this, getMainComponentName())
35 | );
36 | }
37 |
38 | /**
39 | * Align the back button behavior with Android S
40 | * where moving root activities to background instead of finishing activities.
41 | * @see onBackPressed
42 | */
43 | @Override
44 | public void invokeDefaultOnBackPressed() {
45 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
46 | if (!moveTaskToBack(false)) {
47 | // For non-root activities, use the default implementation to finish them.
48 | super.invokeDefaultOnBackPressed();
49 | }
50 | return;
51 | }
52 |
53 | // Use the default back button implementation on Android S
54 | // because it's doing more than {@link Activity#moveTaskToBack} in fact.
55 | super.invokeDefaultOnBackPressed();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/reactnativestickyparallaxheaderexample/newarchitecture/components/MainComponentsRegistry.java:
--------------------------------------------------------------------------------
1 | package com.reactnativestickyparallaxheaderexample.newarchitecture.components;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.proguard.annotations.DoNotStrip;
5 | import com.facebook.react.fabric.ComponentFactory;
6 | import com.facebook.soloader.SoLoader;
7 |
8 | /**
9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a
10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
11 | * folder for you).
12 | *
13 | * Please note that this class is used ONLY if you opt-in for the New Architecture (see the
14 | * `newArchEnabled` property). Is ignored otherwise.
15 | */
16 | @DoNotStrip
17 | public class MainComponentsRegistry {
18 | static {
19 | SoLoader.loadLibrary("fabricjni");
20 | }
21 |
22 | @DoNotStrip private final HybridData mHybridData;
23 |
24 | @DoNotStrip
25 | private native HybridData initHybrid(ComponentFactory componentFactory);
26 |
27 | @DoNotStrip
28 | private MainComponentsRegistry(ComponentFactory componentFactory) {
29 | mHybridData = initHybrid(componentFactory);
30 | }
31 |
32 | @DoNotStrip
33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) {
34 | return new MainComponentsRegistry(componentFactory);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/reactnativestickyparallaxheaderexample/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.reactnativestickyparallaxheaderexample.newarchitecture.modules;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.soloader.SoLoader;
8 | import java.util.List;
9 |
10 | /**
11 | * Class responsible to load the TurboModules. This class has native methods and needs a
12 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
13 | * folder for you).
14 | *
15 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
16 | * `newArchEnabled` property). Is ignored otherwise.
17 | */
18 | public class MainApplicationTurboModuleManagerDelegate
19 | extends ReactPackageTurboModuleManagerDelegate {
20 |
21 | private static volatile boolean sIsSoLibraryLoaded;
22 |
23 | protected MainApplicationTurboModuleManagerDelegate(
24 | ReactApplicationContext reactApplicationContext, List packages) {
25 | super(reactApplicationContext, packages);
26 | }
27 |
28 | protected native HybridData initHybrid();
29 |
30 | native boolean canCreateTurboModule(String moduleName);
31 |
32 | public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
33 | protected MainApplicationTurboModuleManagerDelegate build(
34 | ReactApplicationContext context, List packages) {
35 | return new MainApplicationTurboModuleManagerDelegate(context, packages);
36 | }
37 | }
38 |
39 | @Override
40 | protected synchronized void maybeLoadOtherSoLibraries() {
41 | if (!sIsSoLibraryLoaded) {
42 | // If you change the name of your application .so file in the Android.mk file,
43 | // make sure you update the name here as well.
44 | SoLoader.loadLibrary("reactnativestickyparallaxheaderexample_appmodules");
45 | sIsSoLibraryLoaded = true;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/Android.mk:
--------------------------------------------------------------------------------
1 | THIS_DIR := $(call my-dir)
2 |
3 | include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
4 |
5 | # If you wish to add a custom TurboModule or Fabric component in your app you
6 | # will have to include the following autogenerated makefile.
7 | # include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
8 | include $(CLEAR_VARS)
9 |
10 | LOCAL_PATH := $(THIS_DIR)
11 |
12 | # You can customize the name of your application .so file here.
13 | LOCAL_MODULE := reactnativestickyparallaxheaderexample_appmodules
14 |
15 | LOCAL_C_INCLUDES := $(LOCAL_PATH)
16 | LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
17 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
18 |
19 | # If you wish to add a custom TurboModule or Fabric component in your app you
20 | # will have to uncomment those lines to include the generated source
21 | # files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
22 | #
23 | # LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
24 | # LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
25 | # LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
26 |
27 | # Here you should add any native library you wish to depend on.
28 | LOCAL_SHARED_LIBRARIES := \
29 | libfabricjni \
30 | libfbjni \
31 | libfolly_futures \
32 | libfolly_json \
33 | libglog \
34 | libjsi \
35 | libreact_codegen_rncore \
36 | libreact_debug \
37 | libreact_nativemodule_core \
38 | libreact_render_componentregistry \
39 | libreact_render_core \
40 | libreact_render_debug \
41 | libreact_render_graphics \
42 | librrc_view \
43 | libruntimeexecutor \
44 | libturbomodulejsijni \
45 | libyoga
46 |
47 | LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
48 |
49 | include $(BUILD_SHARED_LIBRARY)
50 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainApplicationModuleProvider.cpp:
--------------------------------------------------------------------------------
1 | #include "MainApplicationModuleProvider.h"
2 |
3 | #include
4 |
5 | namespace facebook {
6 | namespace react {
7 |
8 | std::shared_ptr MainApplicationModuleProvider(
9 | const std::string moduleName,
10 | const JavaTurboModule::InitParams ¶ms) {
11 | // Here you can provide your own module provider for TurboModules coming from
12 | // either your application or from external libraries. The approach to follow
13 | // is similar to the following (for a library called `samplelibrary`:
14 | //
15 | // auto module = samplelibrary_ModuleProvider(moduleName, params);
16 | // if (module != nullptr) {
17 | // return module;
18 | // }
19 | // return rncore_ModuleProvider(moduleName, params);
20 | return rncore_ModuleProvider(moduleName, params);
21 | }
22 |
23 | } // namespace react
24 | } // namespace facebook
25 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainApplicationModuleProvider.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | std::shared_ptr MainApplicationModuleProvider(
12 | const std::string moduleName,
13 | const JavaTurboModule::InitParams ¶ms);
14 |
15 | } // namespace react
16 | } // namespace facebook
17 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp:
--------------------------------------------------------------------------------
1 | #include "MainApplicationTurboModuleManagerDelegate.h"
2 | #include "MainApplicationModuleProvider.h"
3 |
4 | namespace facebook {
5 | namespace react {
6 |
7 | jni::local_ref
8 | MainApplicationTurboModuleManagerDelegate::initHybrid(
9 | jni::alias_ref) {
10 | return makeCxxInstance();
11 | }
12 |
13 | void MainApplicationTurboModuleManagerDelegate::registerNatives() {
14 | registerHybrid({
15 | makeNativeMethod(
16 | "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
17 | makeNativeMethod(
18 | "canCreateTurboModule",
19 | MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
20 | });
21 | }
22 |
23 | std::shared_ptr
24 | MainApplicationTurboModuleManagerDelegate::getTurboModule(
25 | const std::string name,
26 | const std::shared_ptr jsInvoker) {
27 | // Not implemented yet: provide pure-C++ NativeModules here.
28 | return nullptr;
29 | }
30 |
31 | std::shared_ptr
32 | MainApplicationTurboModuleManagerDelegate::getTurboModule(
33 | const std::string name,
34 | const JavaTurboModule::InitParams ¶ms) {
35 | return MainApplicationModuleProvider(name, params);
36 | }
37 |
38 | bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
39 | std::string name) {
40 | return getTurboModule(name, nullptr) != nullptr ||
41 | getTurboModule(name, {.moduleName = name}) != nullptr;
42 | }
43 |
44 | } // namespace react
45 | } // namespace facebook
46 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | namespace facebook {
8 | namespace react {
9 |
10 | class MainApplicationTurboModuleManagerDelegate
11 | : public jni::HybridClass<
12 | MainApplicationTurboModuleManagerDelegate,
13 | TurboModuleManagerDelegate> {
14 | public:
15 | // Adapt it to the package you used for your Java class.
16 | static constexpr auto kJavaDescriptor =
17 | "Lcom/reactnativestickyparallaxheaderexample/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
18 |
19 | static jni::local_ref initHybrid(jni::alias_ref);
20 |
21 | static void registerNatives();
22 |
23 | std::shared_ptr getTurboModule(
24 | const std::string name,
25 | const std::shared_ptr jsInvoker) override;
26 | std::shared_ptr getTurboModule(
27 | const std::string name,
28 | const JavaTurboModule::InitParams ¶ms) override;
29 |
30 | /**
31 | * Test-only method. Allows user to verify whether a TurboModule can be
32 | * created by instances of this class.
33 | */
34 | bool canCreateTurboModule(std::string name);
35 | };
36 |
37 | } // namespace react
38 | } // namespace facebook
39 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainComponentsRegistry.cpp:
--------------------------------------------------------------------------------
1 | #include "MainComponentsRegistry.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
12 |
13 | std::shared_ptr
14 | MainComponentsRegistry::sharedProviderRegistry() {
15 | auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
16 |
17 | // Custom Fabric Components go here. You can register custom
18 | // components coming from your App or from 3rd party libraries here.
19 | //
20 | // providerRegistry->add(concreteComponentDescriptorProvider<
21 | // AocViewerComponentDescriptor>());
22 | return providerRegistry;
23 | }
24 |
25 | jni::local_ref
26 | MainComponentsRegistry::initHybrid(
27 | jni::alias_ref,
28 | ComponentFactory *delegate) {
29 | auto instance = makeCxxInstance(delegate);
30 |
31 | auto buildRegistryFunction =
32 | [](EventDispatcher::Weak const &eventDispatcher,
33 | ContextContainer::Shared const &contextContainer)
34 | -> ComponentDescriptorRegistry::Shared {
35 | auto registry = MainComponentsRegistry::sharedProviderRegistry()
36 | ->createComponentDescriptorRegistry(
37 | {eventDispatcher, contextContainer});
38 |
39 | auto mutableRegistry =
40 | std::const_pointer_cast(registry);
41 |
42 | mutableRegistry->setFallbackComponentDescriptor(
43 | std::make_shared(
44 | ComponentDescriptorParameters{
45 | eventDispatcher, contextContainer, nullptr}));
46 |
47 | return registry;
48 | };
49 |
50 | delegate->buildRegistryFunction = buildRegistryFunction;
51 | return instance;
52 | }
53 |
54 | void MainComponentsRegistry::registerNatives() {
55 | registerHybrid({
56 | makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
57 | });
58 | }
59 |
60 | } // namespace react
61 | } // namespace facebook
62 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/MainComponentsRegistry.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | class MainComponentsRegistry
12 | : public facebook::jni::HybridClass {
13 | public:
14 | // Adapt it to the package you used for your Java class.
15 | constexpr static auto kJavaDescriptor =
16 | "Lcom/reactnativestickyparallaxheaderexample/newarchitecture/components/MainComponentsRegistry;";
17 |
18 | static void registerNatives();
19 |
20 | MainComponentsRegistry(ComponentFactory *delegate);
21 |
22 | private:
23 | static std::shared_ptr
24 | sharedProviderRegistry();
25 |
26 | static jni::local_ref initHybrid(
27 | jni::alias_ref,
28 | ComponentFactory *delegate);
29 | };
30 |
31 | } // namespace react
32 | } // namespace facebook
33 |
--------------------------------------------------------------------------------
/example/android/app/src/main/jni/OnLoad.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "MainApplicationTurboModuleManagerDelegate.h"
3 | #include "MainComponentsRegistry.h"
4 |
5 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
6 | return facebook::jni::initialize(vm, [] {
7 | facebook::react::MainApplicationTurboModuleManagerDelegate::
8 | registerNatives();
9 | facebook::react::MainComponentsRegistry::registerNatives();
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
21 |
22 |
23 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/splashscreen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #023c69
3 | #ffffff
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | react-native-sticky-parallax-header-example
3 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
17 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | import org.apache.tools.ant.taskdefs.condition.Os
2 |
3 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
4 |
5 | buildscript {
6 | ext {
7 | buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0'
8 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
9 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31')
10 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31')
11 | if (findProperty('android.kotlinVersion')) {
12 | kotlinVersion = findProperty('android.kotlinVersion')
13 | }
14 | frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'
15 |
16 | if (System.properties['os.arch'] == 'aarch64') {
17 | // For M1 Users we need to use the NDK 24 which added support for aarch64
18 | ndkVersion = '24.0.8215888'
19 | } else {
20 | // Otherwise we default to the side-by-side NDK version from AGP.
21 | ndkVersion = '21.4.7075529'
22 | }
23 | }
24 | repositories {
25 | google()
26 | mavenCentral()
27 | }
28 | dependencies {
29 | classpath('com.android.tools.build:gradle:7.0.4')
30 | classpath('com.facebook.react:react-native-gradle-plugin')
31 | classpath('de.undercouch:gradle-download-task:4.1.2')
32 | // NOTE: Do not place your application dependencies here; they belong
33 | // in the individual module build.gradle files
34 | }
35 | }
36 |
37 | allprojects {
38 | repositories {
39 | mavenLocal()
40 | maven {
41 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
42 | url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
43 | }
44 | maven {
45 | // Android JSC is installed from npm
46 | url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist'))
47 | }
48 |
49 | google()
50 | mavenCentral {
51 | // We don't want to fetch react-native from Maven Central as there are
52 | // older versions over there.
53 | content {
54 | excludeGroup 'com.facebook.react'
55 | }
56 | }
57 | maven { url 'https://www.jitpack.io' }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 |
25 | # Automatically convert third-party libraries to use AndroidX
26 | android.enableJetifier=true
27 |
28 | # Version of flipper SDK to use with React Native
29 | FLIPPER_VERSION=0.125.0
30 |
31 | # Use this property to specify which architecture you want to build.
32 | # You can also override it from the CLI using
33 | # ./gradlew -PreactNativeArchitectures=x86_64
34 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
35 |
36 | # Use this property to enable support to the new architecture.
37 | # This will allow you to use TurboModules and the Fabric render in
38 | # your application. You should enable this flag either if you want
39 | # to write custom TurboModules/Fabric components OR use libraries that
40 | # are providing them.
41 | newArchEnabled=false
42 |
43 | # The hosted JavaScript engine
44 | # Supported values: expo.jsEngine = "hermes" | "jsc"
45 | expo.jsEngine=jsc
46 |
47 | # Enable GIF support in React Native images (~200 B increase)
48 | expo.gif.enabled=true
49 | # Enable webp support in React Native images (~85 KB increase)
50 | expo.webp.enabled=true
51 | # Enable animated webp support (~3.4 MB increase)
52 | # Disabled by default because iOS doesn't support animated webp
53 | expo.webp.animated=false
54 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'react-native-sticky-parallax-header-example'
2 |
3 | apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
4 | useExpoModules()
5 |
6 | apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
7 | applyNativeModulesSettingsGradle(settings)
8 |
9 | include ':app'
10 | includeBuild(new File(["node", "--print", "require.resolve('react-native-gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
11 |
12 | if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
13 | include(":ReactAndroid")
14 | project(":ReactAndroid").projectDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../ReactAndroid");
15 | }
16 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-sticky-parallax-header-example",
3 | "displayName": "StickyParallaxHeader Example",
4 | "expo": {
5 | "name": "react-native-sticky-parallax-header-example",
6 | "slug": "react-native-sticky-parallax-header-example",
7 | "description": "Example app for react-native-sticky-parallax-header",
8 | "privacy": "public",
9 | "version": "1.0.0",
10 | "platforms": [
11 | "ios",
12 | "android",
13 | "web"
14 | ],
15 | "ios": {
16 | "supportsTablet": true,
17 | "bundleIdentifier": "com.react-native-sticky-parallax-header-example"
18 | },
19 | "assetBundlePatterns": [
20 | "**/*"
21 | ],
22 | "android": {
23 | "package": "com.reactnativestickyparallaxheaderexample"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const pak = require('../package.json');
4 |
5 | module.exports = function (api) {
6 | api.cache(true);
7 |
8 | return {
9 | presets: ['babel-preset-expo'],
10 | plugins: [
11 | [
12 | 'module-resolver',
13 | {
14 | extensions: ['.tsx', '.ts', '.js', '.json'],
15 | alias: {
16 | // For development, we want to alias the library to the source
17 | [pak.name]: path.join(__dirname, '..', pak.source),
18 | },
19 | },
20 | ],
21 | 'react-native-reanimated/plugin',
22 | ],
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from 'expo';
2 |
3 | import App from './src/App';
4 |
5 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App);
6 | // It also ensures that whether you load the app in the Expo client or in a native build,
7 | // the environment is set up appropriately
8 | registerRootComponent(App);
9 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Bundle artifacts
26 | *.jsbundle
27 |
28 | # CocoaPods
29 | /Pods/
30 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
2 | require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
3 | require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
4 |
5 | require 'json'
6 | podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
7 |
8 | platform :ios, podfile_properties['ios.deploymentTarget'] || '12.0'
9 | install! 'cocoapods',
10 | :deterministic_uuids => false
11 |
12 | target 'reactnativestickyparallaxheaderexample' do
13 | use_expo_modules!
14 | config = use_native_modules!
15 |
16 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
17 |
18 | # Flags change depending on the env values.
19 | flags = get_default_flags()
20 |
21 | use_react_native!(
22 | :path => config[:reactNativePath],
23 | :hermes_enabled => flags[:hermes_enabled] || podfile_properties['expo.jsEngine'] == 'hermes',
24 | :fabric_enabled => flags[:fabric_enabled],
25 | # An absolute path to your application root.
26 | :app_path => "#{Dir.pwd}/.."
27 | )
28 |
29 | # Uncomment to opt-in to using Flipper
30 | # Note that if you have use_frameworks! enabled, Flipper will not work
31 | #
32 | # if !ENV['CI']
33 | # use_flipper!()
34 | # end
35 |
36 | post_install do |installer|
37 | react_native_post_install(installer)
38 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
39 | end
40 |
41 | post_integrate do |installer|
42 | begin
43 | expo_patch_react_imports!(installer)
44 | rescue => e
45 | Pod::UI.warn e
46 | end
47 | end
48 |
49 | end
50 |
--------------------------------------------------------------------------------
/example/ios/Podfile.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo.jsEngine": "jsc"
3 | }
4 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | #import
6 |
7 | @interface AppDelegate : EXAppDelegateWrapper
8 |
9 | @end
10 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "expo"
37 | }
38 | }
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "expo"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/Images.xcassets/SplashScreenBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "universal",
5 | "filename": "image.png",
6 | "scale": "1x"
7 | },
8 | {
9 | "idiom": "universal",
10 | "scale": "2x"
11 | },
12 | {
13 | "idiom": "universal",
14 | "scale": "3x"
15 | }
16 | ],
17 | "info": {
18 | "version": 1,
19 | "author": "expo"
20 | }
21 | }
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/Images.xcassets/SplashScreenBackground.imageset/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/ios/reactnativestickyparallaxheaderexample/Images.xcassets/SplashScreenBackground.imageset/image.png
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/Supporting/Expo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | EXUpdatesCheckOnLaunch
6 | ALWAYS
7 | EXUpdatesEnabled
8 |
9 | EXUpdatesLaunchWaitMs
10 | 0
11 | EXUpdatesSDKVersion
12 | 45.0.0
13 | EXUpdatesURL
14 | https://exp.host/@mateusz.medrek/react-native-sticky-parallax-header-example
15 |
16 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char * argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/noop-file.swift:
--------------------------------------------------------------------------------
1 | //
2 | // @generated
3 | // A blank Swift file must be created for native modules with Swift files to work correctly.
4 | //
5 |
--------------------------------------------------------------------------------
/example/ios/reactnativestickyparallaxheaderexample/reactnativestickyparallaxheaderexample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const exclusionList = require('metro-config/src/defaults/exclusionList');
3 | const escape = require('escape-string-regexp');
4 | const pak = require('../package.json');
5 |
6 | const root = path.resolve(__dirname, '..');
7 |
8 | const modules = Object.keys({
9 | ...pak.peerDependencies,
10 | });
11 |
12 | module.exports = {
13 | projectRoot: __dirname,
14 | watchFolders: [root],
15 |
16 | // We need to make sure that only one version is loaded for peerDependencies
17 | // So we block them at the root, and alias them to the versions in example's node_modules
18 | resolver: {
19 | blockList: exclusionList(
20 | modules.map(
21 | (m) =>
22 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
23 | )
24 | ),
25 |
26 | extraNodeModules: modules.reduce((acc, name) => {
27 | acc[name] = path.join(__dirname, 'node_modules', name);
28 | return acc;
29 | }, {}),
30 | },
31 |
32 | transformer: {
33 | getTransformOptions: async () => ({
34 | transform: {
35 | experimentalImportSupport: false,
36 | inlineRequires: true,
37 | },
38 | }),
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-sticky-parallax-header-example",
3 | "description": "Example app for react-native-sticky-parallax-header",
4 | "version": "0.0.1",
5 | "private": true,
6 | "main": "index",
7 | "scripts": {
8 | "android": "expo run:android",
9 | "ios": "expo run:ios",
10 | "web": "expo start --web",
11 | "start": "react-native start",
12 | "test": "jest"
13 | },
14 | "dependencies": {
15 | "@react-native-masked-view/masked-view": "0.2.6",
16 | "@react-navigation/native": "6.0.10",
17 | "@react-navigation/stack": "6.2.1",
18 | "@shopify/flash-list": "^1.2.0",
19 | "expo": "^45.0.0",
20 | "expo-blur": "~11.1.0",
21 | "expo-font": "~10.1.0",
22 | "expo-splash-screen": "~0.15.1",
23 | "expo-status-bar": "~1.3.0",
24 | "react": "17.0.2",
25 | "react-dom": "17.0.2",
26 | "react-native": "0.68.2",
27 | "react-native-gesture-handler": "~2.2.1",
28 | "react-native-reanimated": "~2.8.0",
29 | "react-native-safe-area-context": "4.2.4",
30 | "react-native-screens": "~3.11.1",
31 | "react-native-web": "0.17.7"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.12.9",
35 | "@babel/runtime": "^7.12.5",
36 | "@types/react": "17.0.39",
37 | "@types/react-native": "0.68.0",
38 | "babel-loader": "^8.2.4",
39 | "babel-plugin-module-resolver": "^4.0.0",
40 | "babel-preset-expo": "9.0.2",
41 | "expo-cli": "5.4.11",
42 | "typescript": "4.7.4"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as Font from 'expo-font';
2 | import * as React from 'react';
3 | import { I18nManager } from 'react-native';
4 | import { SafeAreaProvider } from 'react-native-safe-area-context';
5 |
6 | import AppNavigator from './navigation/AppNavigator';
7 |
8 | export default function App() {
9 | const [loaded, setLoaded] = React.useState(false);
10 |
11 | const loadFonts = React.useCallback(async () => {
12 | await Font.loadAsync({
13 | 'AvertaStd-Semibold': require('./assets/fonts/AvertaStd-Semibold.otf'),
14 | 'AvertaStd-Regular': require('./assets/fonts/AvertaStd-Regular.otf'),
15 | });
16 | setLoaded(true);
17 | }, []);
18 |
19 | React.useEffect(() => {
20 | loadFonts();
21 | I18nManager.allowRTL(true);
22 | }, [loadFonts]);
23 |
24 | return {loaded ? : <>>};
25 | }
26 |
--------------------------------------------------------------------------------
/example/src/assets/data/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const tabbedSectionsTestIDs = Object.freeze({
2 | pizza: 'PizzaTestID',
3 | burgers: 'BurgersTestID',
4 | kebab: 'KebabTestID',
5 | chineseFood: 'ChineseFoodTestID',
6 | sushi: 'SushiTestID',
7 | pasta: 'PastaTestID',
8 | });
9 |
--------------------------------------------------------------------------------
/example/src/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/favicon.png
--------------------------------------------------------------------------------
/example/src/assets/fonts/AvertaStd-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/fonts/AvertaStd-Regular.otf
--------------------------------------------------------------------------------
/example/src/assets/fonts/AvertaStd-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/fonts/AvertaStd-Semibold.otf
--------------------------------------------------------------------------------
/example/src/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icon.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Check.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Check@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Check@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Check@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Check@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Close.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Close@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Close@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Close@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Arrow.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Arrow@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Arrow@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Arrow@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Menu.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Menu@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Menu@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/Icon-Menu@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/Icon-Menu@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards_black.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards_black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards_black@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/cards_black@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/cards_black@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconApp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconApp.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconApp@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconApp@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconApp@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconApp@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconCloseWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconCloseWhite.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconCloseWhite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconCloseWhite@2x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/iconCloseWhite@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/iconCloseWhite@3x.png
--------------------------------------------------------------------------------
/example/src/assets/icons/index.ts:
--------------------------------------------------------------------------------
1 | export const cards = require('./cards.png');
2 | export const Check = require('./Check.png');
3 | export const Close = require('./Close.png');
4 | export const iconCloseWhite = require('./iconCloseWhite.png');
5 | export const IconMenu = require('./Icon-Menu.png');
6 | export const CardsBlack = require('./cards_black.png');
7 | export const share = require('./share.png');
8 |
--------------------------------------------------------------------------------
/example/src/assets/icons/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/icons/share.png
--------------------------------------------------------------------------------
/example/src/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/icon.png
--------------------------------------------------------------------------------
/example/src/assets/images/index.ts:
--------------------------------------------------------------------------------
1 | export const photosPortraitBrandon = require('./photosPortraitBrandon.png');
2 | export const photosPortraitEwa = require('./photosPortraitEwa.png');
3 | export const photosPortraitJennifer = require('./photosPortraitJennifer.png');
4 | export const photosPortraitMe = require('./photosPortraitMe.png');
5 | export const logo = require('./logo.png');
6 |
--------------------------------------------------------------------------------
/example/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/logo.png
--------------------------------------------------------------------------------
/example/src/assets/images/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/logo@2x.png
--------------------------------------------------------------------------------
/example/src/assets/images/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/logo@3x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitBrandon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitBrandon.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitBrandon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitBrandon@2x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitBrandon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitBrandon@3x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitEwa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitEwa.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitEwa@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitEwa@2x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitEwa@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitEwa@3x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitJennifer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitJennifer.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitJennifer@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitJennifer@2x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitJennifer@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitJennifer@3x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitMe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitMe.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitMe@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitMe@2x.png
--------------------------------------------------------------------------------
/example/src/assets/images/photosPortraitMe@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/images/photosPortraitMe@3x.png
--------------------------------------------------------------------------------
/example/src/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/example/src/assets/splash.png
--------------------------------------------------------------------------------
/example/src/components/index.ts:
--------------------------------------------------------------------------------
1 | import QuizCard from './exampleComponents/QuizCard';
2 | import QuizListElement from './exampleComponents/QuizListElement';
3 | import QuizOption from './exampleComponents/QuizOption';
4 | import UserModal from './exampleComponents/UserModal';
5 |
6 | export { QuizListElement, UserModal, QuizCard, QuizOption };
7 |
--------------------------------------------------------------------------------
/example/src/components/predefinedComponents/TabbedSectionHeader.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, Text } from 'react-native';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 |
5 | import type { SectionType } from '../../assets/data/tabbedSections';
6 | import { colors } from '../../constants';
7 |
8 | export const TabbedSectionHeader: React.FC = ({ title }) => {
9 | return (
10 |
11 | {title}
12 |
13 | );
14 | };
15 |
16 | const styles = StyleSheet.create({
17 | sectionContainer: {
18 | alignItems: 'flex-start',
19 | alignSelf: 'stretch',
20 | backgroundColor: colors.activeOrange,
21 | elevation: 1.4,
22 | justifyContent: 'center',
23 | paddingHorizontal: 15,
24 | paddingVertical: 5,
25 | shadowColor: colors.shadowColor,
26 | shadowOffset: { width: 0, height: 1.4 },
27 | shadowOpacity: 0.8,
28 | shadowRadius: 2.2,
29 | },
30 | sectionTitle: {
31 | color: colors.white,
32 | fontFamily: 'AvertaStd-Semibold',
33 | fontSize: 30,
34 | textAlign: 'center',
35 | textTransform: 'uppercase',
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/example/src/components/primitiveComponents/Header.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Image, PixelRatio, StyleSheet, View } from 'react-native';
3 |
4 | export const Header: React.FC = () => {
5 | return (
6 |
7 |
11 |
12 | );
13 | };
14 |
15 | const styles = StyleSheet.create({
16 | headerContainer: {
17 | alignItems: 'center',
18 | alignSelf: 'stretch',
19 | justifyContent: 'center',
20 | padding: 50 / PixelRatio.get(),
21 | },
22 | headerImage: {
23 | height: 200 / PixelRatio.get(),
24 | width: 200 / PixelRatio.get(),
25 | },
26 | });
27 |
--------------------------------------------------------------------------------
/example/src/components/primitiveComponents/Paragraph.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Platform, Pressable, StyleSheet, Text } from 'react-native';
3 |
4 | import { colors, screenStyles } from '../../constants';
5 |
6 | export const Paragraph: React.FC<{ text: string }> = ({ text }) => {
7 | return (
8 | [styles.paragraphContainer, pressed && styles.pressedTab]}>
14 | {text}
15 |
16 | );
17 | };
18 |
19 | const styles = StyleSheet.create({
20 | paragraph: {
21 | color: colors.primaryGreen,
22 | fontSize: 18,
23 | textAlign: 'left',
24 | },
25 | paragraphContainer: {
26 | alignItems: 'flex-start',
27 | borderColor: colors.paleGrey,
28 | borderRadius: 10,
29 | borderWidth: StyleSheet.hairlineWidth,
30 | elevation: 2,
31 | margin: 10,
32 | padding: 10,
33 | shadowColor: Platform.select({
34 | ios: colors.paleGrey,
35 | default: undefined,
36 | }),
37 | shadowOffset: { width: 2, height: 0 },
38 | shadowOpacity: 0.7,
39 | shadowRadius: 0.8,
40 | },
41 | pressedTab: {
42 | opacity: Platform.select({
43 | android: 1,
44 | default: 0.4,
45 | }),
46 | },
47 | });
48 |
--------------------------------------------------------------------------------
/example/src/components/primitiveComponents/SectionFooter.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 |
4 | import { colors } from '../../constants';
5 |
6 | export const SectionFooter: React.FC = () => {
7 | return (
8 |
9 | Section footer
10 |
11 | );
12 | };
13 |
14 | const styles = StyleSheet.create({
15 | sectionFooterContainer: {
16 | alignItems: 'flex-start',
17 | alignSelf: 'stretch',
18 | padding: 12,
19 | },
20 | sectionFooterLabel: {
21 | color: colors.primaryGreen,
22 | fontFamily: 'AvertaStd-Semibold',
23 | fontSize: 20,
24 | textAlign: 'left',
25 | textTransform: 'uppercase',
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/example/src/components/primitiveComponents/SectionHeader.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, Text, View } from 'react-native';
3 |
4 | import { colors } from '../../constants';
5 |
6 | export const SectionHeader: React.FC = () => {
7 | return (
8 |
9 | Section header
10 |
11 | );
12 | };
13 |
14 | const styles = StyleSheet.create({
15 | sectionHeaderContainer: {
16 | alignItems: 'flex-start',
17 | alignSelf: 'stretch',
18 | backgroundColor: colors.secondaryGreen,
19 | elevation: 2.5,
20 | shadowColor: colors.primaryGreen,
21 | shadowOffset: { height: 0, width: 2.5 },
22 | shadowOpacity: 0.8,
23 | shadowRadius: 0.8,
24 | padding: 20,
25 | },
26 | sectionHeaderLabel: {
27 | color: colors.primaryGreen,
28 | fontFamily: 'AvertaStd-Semibold',
29 | fontSize: 24,
30 | textAlign: 'left',
31 | textTransform: 'uppercase',
32 | },
33 | });
34 |
--------------------------------------------------------------------------------
/example/src/components/primitiveComponents/Tabs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { PixelRatio, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
3 |
4 | import { colors, screenStyles } from '../../constants';
5 |
6 | export const Tabs: React.FC = () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | const Tab: React.FC<{ title: string }> = ({ title }) => {
19 | return (
20 | [styles.tab, pressed && styles.pressedTab]}>
26 | {title}
27 |
28 | );
29 | };
30 |
31 | const styles = StyleSheet.create({
32 | pressedTab: {
33 | opacity: Platform.select({
34 | android: 1,
35 | default: 0.4,
36 | }),
37 | },
38 | tab: {
39 | alignItems: 'flex-start',
40 | margin: 10 / PixelRatio.get(),
41 | padding: 10 / PixelRatio.get(),
42 | },
43 | tabTitle: {
44 | fontSize: 16 / PixelRatio.getFontScale(),
45 | fontWeight: 'bold',
46 | padding: 10 / PixelRatio.get(),
47 | textAlign: 'left',
48 | },
49 | tabsContainer: {
50 | alignItems: 'center',
51 | backgroundColor: colors.purpleishBlue,
52 | elevation: 2,
53 | flexDirection: 'row',
54 | justifyContent: 'space-evenly',
55 | padding: 10,
56 | shadowColor: Platform.select({
57 | ios: 'gray',
58 | default: undefined,
59 | }),
60 | shadowOffset: { width: 2, height: 0 },
61 | shadowOpacity: 0.7,
62 | shadowRadius: 0.8,
63 | },
64 | });
65 |
--------------------------------------------------------------------------------
/example/src/constants/colors.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | blue: 'blue',
3 | black: 'black',
4 | primaryGreen: '#1ca75d',
5 | secondaryGreen: 'rgb(61,179,106)',
6 | darkMint: 'rgb(72,189,126)',
7 | white: 'white',
8 | shadowColor: 'rgb(35,35,35)',
9 | transparent: 'transparent',
10 | semitransparentBlack: 'rgba(0,0,0,0.6)',
11 | purplishBlue: 'rgb(78, 15, 255)',
12 | purpleishBlue: 'rgb(89,80,249)',
13 | paleGrey: 'rgb(246,245,248)',
14 | greyishBrown: 'rgb(71,71,71)',
15 | coralPink: 'rgb(255,94,107)',
16 | jade: 'rgb(29,167,93)',
17 | backBlue: '#2488FF',
18 | detailsBlue: '#3479F6',
19 | activeOrange: '#FFC106',
20 | };
21 |
--------------------------------------------------------------------------------
/example/src/constants/constants.ts:
--------------------------------------------------------------------------------
1 | import { Dimensions, Platform } from 'react-native';
2 |
3 | const { height, width } = Dimensions.get('window');
4 |
5 | const breakpoints = {
6 | smallPhoneWidth: 320,
7 | smallPhoneHeight: 600,
8 | mediumPhoneWidth: 414,
9 | bigPhoneWidth: 480,
10 | };
11 | const isSmallScreen =
12 | width <= breakpoints.smallPhoneWidth || height <= breakpoints.smallPhoneHeight;
13 | const isNormalScreen = width > breakpoints.smallPhoneWidth && width < breakpoints.mediumPhoneWidth;
14 | const isBigScreen = width >= breakpoints.mediumPhoneWidth;
15 | const isBiggestPhoneScreen = width >= breakpoints.bigPhoneWidth;
16 | const isAndroid = Platform.OS === 'android';
17 |
18 | export default {
19 | isAndroid,
20 | isSmallScreen,
21 | isNormalScreen,
22 | isBigScreen,
23 | isBiggestPhoneScreen,
24 | };
25 |
--------------------------------------------------------------------------------
/example/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | import colors from './colors';
2 | import constants from './constants';
3 | import screenStyles from './screenStyles';
4 |
5 | export { constants, colors, screenStyles };
6 |
--------------------------------------------------------------------------------
/example/src/constants/screenStyles.ts:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import colors from './colors';
4 |
5 | const screenStyles = StyleSheet.create({
6 | content: {
7 | flex: 1,
8 | paddingHorizontal: 24,
9 | alignItems: 'center',
10 | marginBottom: 25,
11 | },
12 | contentText: {
13 | alignSelf: 'flex-start',
14 | color: colors.black,
15 | fontFamily: 'AvertaStd-Semibold',
16 | fontSize: 24,
17 | letterSpacing: -0.2,
18 | lineHeight: 28,
19 | paddingBottom: 20,
20 | paddingTop: 40,
21 | },
22 | darkBackground: {
23 | backgroundColor: colors.black,
24 | },
25 | lightBackground: {
26 | backgroundColor: colors.white,
27 | },
28 | screenContainer: {
29 | alignItems: 'center',
30 | alignSelf: 'stretch',
31 | flex: 1,
32 | justifyContent: 'center',
33 | },
34 | stretch: {
35 | alignSelf: 'stretch',
36 | },
37 | stretchContainer: {
38 | alignSelf: 'stretch',
39 | flex: 1,
40 | },
41 | text: {
42 | fontFamily: 'AvertaStd-Regular',
43 | },
44 | });
45 |
46 | export default screenStyles;
47 |
--------------------------------------------------------------------------------
/example/src/navigation/routes.ts:
--------------------------------------------------------------------------------
1 | export const ROUTES = {
2 | HOME: 'Home' as const,
3 | CARD: 'Card' as const,
4 | SIMS: 'Sims' as const,
5 | YODA: 'Yoda' as const,
6 | STICKY_HEADER_FLATLIST: 'StickyHeaderFlatList' as const,
7 | STICKY_HEADER_SCROLLVIEW: 'StickyHeaderScrollView' as const,
8 | STICKY_HEADER_SECTIONLIST: 'StickyHeaderSectionList' as const,
9 | TABBED_HEADER_LIST: 'TabbedHeaderList' as const,
10 | TABBED_HEADER_PAGER: 'TabbedHeaderPager' as const,
11 | AVATAR_HEADER_FLATLIST: 'AvatarHeaderFlatList' as const,
12 | AVATAR_HEADER_SCROLLVIEW: 'AvatarHeaderScrollView' as const,
13 | AVATAR_HEADER_SECTIONLIST: 'AvatarHeaderSectionList' as const,
14 | DETAILS_HEADER_FLATLIST: 'DetailsHeaderFlatList' as const,
15 | DETAILS_HEADER_SCROLLVIEW: 'DetailsHeaderScrollView' as const,
16 | DETAILS_HEADER_SECTIONLIST: 'DetailsHeaderSectionList' as const,
17 | TABBED_HEADER_WITH_SECTION_LISTS: 'TabbedHeaderWithSectionLists' as const,
18 | TABBED_HEADER_FLASHLIST: 'TabbedHeaderFlashList' as const,
19 | AVATAR_HEADER_FLASHLIST: 'AvatarHeaderFlashList' as const,
20 | DETAILS_HEADER_FLASHLIST: 'DetailsHeaderFlashList' as const,
21 | STICKY_HEADER_FLASHLIST: 'StickyHeaderFlashList' as const,
22 | TABBED_HEADER_WITH_ANIMATED_COLORS: 'TabbedHeaderWithAnimatedColors' as const,
23 | };
24 |
--------------------------------------------------------------------------------
/example/src/navigation/types.ts:
--------------------------------------------------------------------------------
1 | import type { RouteProp } from '@react-navigation/native';
2 | import type { StackNavigationProp } from '@react-navigation/stack';
3 |
4 | import type { User } from '../assets/data/cards';
5 |
6 | import type { ROUTES } from './routes';
7 |
8 | export type RootStackParamList = {
9 | [ROUTES.HOME]: undefined;
10 | [ROUTES.CARD]: { user?: User };
11 | [ROUTES.SIMS]: undefined;
12 | [ROUTES.YODA]: undefined;
13 | [ROUTES.STICKY_HEADER_FLATLIST]: undefined;
14 | [ROUTES.STICKY_HEADER_SCROLLVIEW]: undefined;
15 | [ROUTES.STICKY_HEADER_SECTIONLIST]: undefined;
16 | [ROUTES.TABBED_HEADER_LIST]: undefined;
17 | [ROUTES.TABBED_HEADER_PAGER]: undefined;
18 | [ROUTES.AVATAR_HEADER_FLATLIST]: undefined;
19 | [ROUTES.AVATAR_HEADER_SCROLLVIEW]: undefined;
20 | [ROUTES.AVATAR_HEADER_SECTIONLIST]: undefined;
21 | [ROUTES.DETAILS_HEADER_FLATLIST]: undefined;
22 | [ROUTES.DETAILS_HEADER_SCROLLVIEW]: undefined;
23 | [ROUTES.DETAILS_HEADER_SECTIONLIST]: undefined;
24 | [ROUTES.TABBED_HEADER_WITH_SECTION_LISTS]: undefined;
25 | [ROUTES.TABBED_HEADER_FLASHLIST]: undefined;
26 | [ROUTES.AVATAR_HEADER_FLASHLIST]: undefined;
27 | [ROUTES.DETAILS_HEADER_FLASHLIST]: undefined;
28 | [ROUTES.STICKY_HEADER_FLASHLIST]: undefined;
29 | [ROUTES.TABBED_HEADER_WITH_ANIMATED_COLORS]: undefined;
30 | };
31 |
32 | export type RootStackNavigationProp = StackNavigationProp;
33 |
34 | export type CardRouteProp = RouteProp;
35 |
--------------------------------------------------------------------------------
/example/src/screens/CardScreen/index.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation, useRoute } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { StatusBar, View } from 'react-native';
4 | import { DetailsHeaderScrollView } from 'react-native-sticky-parallax-header';
5 |
6 | import { Brandon } from '../../assets/data/cards';
7 | import { CardsBlack, IconMenu, iconCloseWhite } from '../../assets/icons';
8 | import { QuizCard } from '../../components';
9 | import { screenStyles } from '../../constants';
10 | import type { CardRouteProp, RootStackNavigationProp } from '../../navigation/types';
11 |
12 | import { cardScreenTestIDs } from './testIDs';
13 |
14 | const CardScreen: React.FC = () => {
15 | const navigation = useNavigation();
16 | const route = useRoute();
17 | const user = route.params?.user ?? Brandon;
18 |
19 | function goBack() {
20 | navigation.goBack();
21 | }
22 |
23 | return (
24 | <>
25 |
42 |
43 | {user.cards.map((data, i, arr) => (
44 |
45 | ))}
46 |
47 |
48 |
49 | >
50 | );
51 | };
52 |
53 | export default CardScreen;
54 |
--------------------------------------------------------------------------------
/example/src/screens/CardScreen/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const cardScreenTestIDs = Object.freeze({
2 | headerTitle: 'CardHeaderTitleTestID',
3 | headerTag: 'CardHeaderTagTestID',
4 | headerContentIconNumber: 'CardHeaderContentIconNumberTestID',
5 | headerLeftTopIcon: 'CardHeaderLeftTopIconTestID',
6 | headerRightTopIcon: 'CardHeaderRightTopIconTestID',
7 | });
8 |
--------------------------------------------------------------------------------
/example/src/screens/HomeScreen/data.ts:
--------------------------------------------------------------------------------
1 | import { Brandon, Ewa, Jennifer } from '../../assets/data/cards';
2 |
3 | import { homeScreenTestIDs } from './testIDs';
4 |
5 | export const TABS = [
6 | {
7 | title: 'Popular',
8 | contentTitle: 'Popular Quizes',
9 | testID: homeScreenTestIDs.popularQuizesTab,
10 | contentTestID: homeScreenTestIDs.popularQuizesHeader,
11 | },
12 | {
13 | title: 'Product Design',
14 | contentTitle: 'Product Design',
15 | testID: homeScreenTestIDs.productDesignTab,
16 | contentTestID: homeScreenTestIDs.productDesignHeader,
17 | },
18 | {
19 | title: 'Development',
20 | contentTitle: 'Development',
21 | testID: homeScreenTestIDs.developmentTab,
22 | contentTestID: homeScreenTestIDs.developmentHeader,
23 | },
24 | {
25 | title: 'Project Management',
26 | contentTitle: 'Project Management',
27 | testID: homeScreenTestIDs.projectManagementTab,
28 | contentTestID: homeScreenTestIDs.projectManagementHeader,
29 | },
30 | ];
31 |
32 | export const users = [Brandon, Jennifer, Ewa];
33 |
--------------------------------------------------------------------------------
/example/src/screens/HomeScreen/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const homeScreenTestIDs = Object.freeze({
2 | headerTitle: 'HeaderTitleTestID',
3 | popularQuizesTab: 'PopularQuizesTabTestID',
4 | popularQuizesHeader: 'PopularQuizesHeaderTestID',
5 | productDesignTab: 'ProductDesignTabTestID',
6 | productDesignHeader: 'ProductDesignHeaderTestID',
7 | developmentTab: 'DevelopmentTabTestID',
8 | developmentHeader: 'DevelopmentHeaderTestID',
9 | projectManagementTab: 'ProjectManagementTabTestID',
10 | projectManagementHeader: 'ProjectManagementHeaderTestID',
11 | yodaLink: 'YodaLinkTestID',
12 | simsLink: 'SimsLinkTestID',
13 | stickyHeaderFlatListLink: 'StickyHeaderFlatListLinkTestID',
14 | stickyHeaderScrollViewLink: 'StickyHeaderScrollViewLinkTestID',
15 | stickyHeaderSectionListLink: 'StickyHeaderSectionListLinkTestID',
16 | tabbedHeaderListLink: 'TabbedHeaderListLinkTestID',
17 | tabbedHeaderPagerLink: 'TabbedHeaderPagerLinkTestID',
18 | avatarHeaderFlatListLink: 'AvatarHeaderFlatListLinkTestID',
19 | avatarHeaderScrollViewLink: 'AvatarHeaderScrollViewLinkTestID',
20 | avatarHeaderSectionListLink: 'AvatarHeaderSectionListLinkTestID',
21 | detailsHeaderFlatListLink: 'DetailsHeaderFlatListLinkTestID',
22 | detailsHeaderScrollViewLink: 'DetailsHeaderScrollViewLinkTestID',
23 | detailsHeaderSectionListLink: 'DetailsHeaderSectionListLinkTestID',
24 | tabbedHeaderWithSectionListsLink: 'TabbedHeaderWithSectionListsLinkTestID',
25 | tabbedHeaderFlashListLink: 'TabbedHeaderFlashListLinkTestID',
26 | avatarHeaderFlashListLink: 'AvatarHeaderFlashListLinkTestID',
27 | detailsHeaderFlashListLink: 'DetailsHeaderFlashListLinkTestID',
28 | stickyHeaderFlashListLink: 'StickyHeaderFlashListLinkTestID',
29 | tabbedHeaderWithAnimatedColorsLink: 'TabbedHeaderWithAnimatedColorsLinkTestID',
30 | });
31 |
--------------------------------------------------------------------------------
/example/src/screens/SimsScreen/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const simsScreenTestIDs = Object.freeze({
2 | foregroundDetailsHeader: 'SimsForegroundDetailsHeaderTestID',
3 | headerBarBackButtonTestID: 'SimsHeaderBarBackButtonTestID',
4 | headerBarSearchButtonTestID: 'SimsHeaderBarSearchButtonTestID',
5 | contentTestID: 'SimsContentTestID',
6 | });
7 |
--------------------------------------------------------------------------------
/example/src/screens/YodaScreen/HeaderBar.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
4 | import Animated, { Extrapolate, interpolate, useAnimatedStyle } from 'react-native-reanimated';
5 | import { SafeAreaView } from 'react-native-safe-area-context';
6 |
7 | import { colors } from '../../constants';
8 |
9 | import { yodaScreenTestIDs } from './testIDs';
10 |
11 | interface HeaderBarProps {
12 | scrollValue: Animated.SharedValue;
13 | }
14 |
15 | export const HeaderBar: React.FC = ({ scrollValue }) => {
16 | const navigation = useNavigation();
17 | const goBack = React.useCallback(() => {
18 | navigation.goBack();
19 | }, [navigation]);
20 |
21 | const animatedStyle = useAnimatedStyle(() => {
22 | return { opacity: interpolate(scrollValue.value, [0, 60, 90], [0, 0, 1], Extrapolate.CLAMP) };
23 | }, [scrollValue]);
24 |
25 | return (
26 |
27 |
28 |
29 |
36 |
37 |
38 |
39 | Baby Yoda
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | const styles = StyleSheet.create({
48 | headerContainer: {
49 | width: '100%',
50 | paddingHorizontal: 24,
51 | paddingVertical: 12,
52 | flexDirection: 'row',
53 | justifyContent: 'space-between',
54 | alignItems: 'center',
55 | backgroundColor: colors.black,
56 | },
57 | headerWrapper: {
58 | flexDirection: 'row',
59 | alignItems: 'center',
60 | },
61 | headerImage: {
62 | width: 20,
63 | height: 20,
64 | },
65 | headerText: {
66 | color: colors.white,
67 | fontFamily: 'AvertaStd-Semibold',
68 | fontSize: 20,
69 | paddingLeft: 20,
70 | },
71 | });
72 |
--------------------------------------------------------------------------------
/example/src/screens/YodaScreen/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const yodaScreenTestIDs = Object.freeze({
2 | headerBarBackButton: 'YodaHeaderBarBackButtonTestID',
3 | headerBarText: 'YodaHeaderBarTextTestID',
4 | headerTitle: 'YodaHeaderTitleTestID',
5 | tabBiography: 'YodaTabBiographyTestID',
6 | contentBiography: 'YodaContentBiographyTestID',
7 | tabPowers: 'YodaTabPowersTestID',
8 | contentPowers: 'YodaContentPowersTestID',
9 | tabAppearances: 'YodaTabAppearancesTestID',
10 | contentAppearances: 'YodaContentAppearancesTestID',
11 | });
12 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/AvatarHeaderFlatListExample.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { StatusBar, StyleSheet, useColorScheme } from 'react-native';
4 | import { AvatarHeaderFlatList } from 'react-native-sticky-parallax-header';
5 |
6 | import { Brandon } from '../../assets/data/cards';
7 | import { IconMenu, iconCloseWhite } from '../../assets/icons';
8 | import { QuizCard } from '../../components';
9 | import { screenStyles } from '../../constants';
10 |
11 | import { avatarHeaderTestIDs } from './testIDs';
12 |
13 | export const AvatarHeaderFlatListExample: React.FC = () => {
14 | const navigation = useNavigation();
15 |
16 | function goBack() {
17 | navigation.goBack();
18 | }
19 |
20 | const isDarkTheme = useColorScheme() === 'dark';
21 |
22 | return (
23 | <>
24 | item.question}
45 | renderItem={({ item, index }) => (
46 |
47 | )}
48 | showsVerticalScrollIndicator={false}
49 | />
50 |
51 | >
52 | );
53 | };
54 |
55 | const styles = StyleSheet.create({
56 | content: {
57 | alignItems: 'center',
58 | alignSelf: 'stretch',
59 | paddingHorizontal: 24,
60 | },
61 | });
62 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/AvatarHeaderScrollViewExample.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { StatusBar, StyleSheet, View, useColorScheme } from 'react-native';
4 | import { AvatarHeaderScrollView } from 'react-native-sticky-parallax-header';
5 |
6 | import { Brandon } from '../../assets/data/cards';
7 | import { IconMenu, iconCloseWhite } from '../../assets/icons';
8 | import { QuizCard } from '../../components';
9 | import { screenStyles } from '../../constants';
10 |
11 | import { avatarHeaderTestIDs } from './testIDs';
12 |
13 | export const AvatarHeaderScrollViewExample: React.FC = () => {
14 | const navigation = useNavigation();
15 |
16 | function goBack() {
17 | navigation.goBack();
18 | }
19 |
20 | const isDarkTheme = useColorScheme() === 'dark';
21 |
22 | return (
23 | <>
24 |
43 |
44 | {Brandon.cards.map((data, i, arr) => (
45 |
46 | ))}
47 |
48 |
49 |
50 | >
51 | );
52 | };
53 |
54 | const styles = StyleSheet.create({
55 | content: {
56 | alignItems: 'center',
57 | flex: 1,
58 | paddingHorizontal: 24,
59 | },
60 | });
61 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/DetailsHeaderFlatListExample.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { StatusBar, StyleSheet, useColorScheme } from 'react-native';
4 | import { DetailsHeaderFlatList } from 'react-native-sticky-parallax-header';
5 |
6 | import { Brandon } from '../../assets/data/cards';
7 | import { CardsBlack, IconMenu, iconCloseWhite } from '../../assets/icons';
8 | import { QuizCard } from '../../components';
9 | import { screenStyles } from '../../constants';
10 |
11 | import { detailsHeaderTestIDs } from './testIDs';
12 |
13 | export const DetailsHeaderFlatListExample: React.FC = () => {
14 | const navigation = useNavigation();
15 |
16 | function goBack() {
17 | navigation.goBack();
18 | }
19 |
20 | const isDarkTheme = useColorScheme() === 'dark';
21 |
22 | return (
23 | <>
24 | item.question}
48 | renderItem={({ item, index }) => (
49 |
50 | )}
51 | showsVerticalScrollIndicator={false}
52 | />
53 |
54 | >
55 | );
56 | };
57 |
58 | const styles = StyleSheet.create({
59 | content: {
60 | alignItems: 'center',
61 | alignSelf: 'stretch',
62 | paddingHorizontal: 24,
63 | },
64 | });
65 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/DetailsHeaderScrollViewExample.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import * as React from 'react';
3 | import { StatusBar, StyleSheet, View, useColorScheme } from 'react-native';
4 | import { DetailsHeaderScrollView } from 'react-native-sticky-parallax-header';
5 |
6 | import { Brandon } from '../../assets/data/cards';
7 | import { CardsBlack, IconMenu, iconCloseWhite } from '../../assets/icons';
8 | import { QuizCard } from '../../components';
9 | import { screenStyles } from '../../constants';
10 |
11 | import { detailsHeaderTestIDs } from './testIDs';
12 |
13 | export const DetailsHeaderScrollViewExample: React.FC = () => {
14 | const navigation = useNavigation();
15 |
16 | function goBack() {
17 | navigation.goBack();
18 | }
19 |
20 | const isDarkTheme = useColorScheme() === 'dark';
21 |
22 | return (
23 | <>
24 |
46 |
47 | {Brandon.cards.map((data, i, arr) => (
48 |
49 | ))}
50 |
51 |
52 |
53 | >
54 | );
55 | };
56 |
57 | const styles = StyleSheet.create({
58 | content: {
59 | alignItems: 'center',
60 | flex: 1,
61 | paddingHorizontal: 24,
62 | },
63 | });
64 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/StickyHeaderFlatListExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Platform, StatusBar } from 'react-native';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 | import { StickyHeaderFlatList } from 'react-native-sticky-parallax-header';
5 |
6 | import { DATA } from '../../assets/data/paragraphs';
7 | import { Header } from '../../components/primitiveComponents/Header';
8 | import { Paragraph } from '../../components/primitiveComponents/Paragraph';
9 | import { Tabs } from '../../components/primitiveComponents/Tabs';
10 | import { screenStyles } from '../../constants';
11 |
12 | export const StickyHeaderFlatListExample: React.FC = () => {
13 | const [refreshing, setRefreshing] = React.useState(false);
14 |
15 | async function onRefresh() {
16 | setRefreshing(true);
17 | await new Promise((res) => setTimeout(res, 2000));
18 | setRefreshing(false);
19 | }
20 |
21 | return (
22 |
23 | item}
27 | /**
28 | * Refresh control is not implemented on web, which causes styles as margin or padding
29 | * to be duplicated - ignore it on web, it will be no-op anyway
30 | *
31 | * TODO: describe it as a web limitation
32 | */
33 | {...Platform.select({ native: { onRefresh } })}
34 | refreshing={refreshing}
35 | renderHeader={() => }
36 | renderItem={({ item }) => {
37 | return ;
38 | }}
39 | renderTabs={() => }
40 | scrollEventThrottle={16}
41 | />
42 |
43 |
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/StickyHeaderScrollViewExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StatusBar } from 'react-native';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 | import { StickyHeaderScrollView } from 'react-native-sticky-parallax-header';
5 |
6 | import { DATA } from '../../assets/data/paragraphs';
7 | import { Header } from '../../components/primitiveComponents/Header';
8 | import { Paragraph } from '../../components/primitiveComponents/Paragraph';
9 | import { Tabs } from '../../components/primitiveComponents/Tabs';
10 | import { screenStyles } from '../../constants';
11 |
12 | export const StickyHeaderScrollViewExample: React.FC = () => {
13 | return (
14 |
15 | }
18 | renderTabs={() => }>
19 | {DATA.map((item, i) => (
20 |
21 | ))}
22 |
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/StickyHeaderSectionListExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Platform, StatusBar } from 'react-native';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 | import { StickyHeaderSectionList } from 'react-native-sticky-parallax-header';
5 |
6 | import { SECTIONS } from '../../assets/data/paragraphs';
7 | import { Header } from '../../components/primitiveComponents/Header';
8 | import { SectionFooter } from '../../components/primitiveComponents/SectionFooter';
9 | import { SectionHeader } from '../../components/primitiveComponents/SectionHeader';
10 | import { Tabs } from '../../components/primitiveComponents/Tabs';
11 | import { screenStyles } from '../../constants';
12 |
13 | export const StickyHeaderSectionListExample: React.FC = () => {
14 | const [refreshing, setRefreshing] = React.useState(false);
15 |
16 | async function onRefresh() {
17 | setRefreshing(true);
18 | await new Promise((res) => setTimeout(res, 2000));
19 | setRefreshing(false);
20 | }
21 |
22 | return (
23 |
24 | }
36 | renderSectionHeader={() => {
37 | return ;
38 | }}
39 | renderSectionFooter={() => {
40 | return ;
41 | }}
42 | renderTabs={() => }
43 | scrollEventThrottle={16}
44 | stickySectionHeadersEnabled
45 | />
46 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/TabbedHeaderListExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StatusBar } from 'react-native';
3 | import { TabbedHeaderList } from 'react-native-sticky-parallax-header';
4 |
5 | import { TABBED_SECTIONS } from '../../assets/data/tabbedSections';
6 | import { TabbedSectionHeader } from '../../components/predefinedComponents/TabbedSectionHeader';
7 | import {
8 | TABBED_SECTION_ITEM_HEIGHT,
9 | TabbedSectionItem,
10 | } from '../../components/predefinedComponents/TabbedSectionItem';
11 | import { colors, screenStyles } from '../../constants';
12 |
13 | import { tabbedHeaderTestIDs } from './testIDs';
14 |
15 | export const TabbedHeaderListExample: React.FC = () => {
16 | return (
17 | <>
18 | ({ title, testID: tabTestID }))}
28 | tabTextStyle={screenStyles.text}
29 | sections={TABBED_SECTIONS}
30 | tabTextContainerActiveStyle={{ backgroundColor: colors.activeOrange }}
31 | keyExtractor={(_, i) => `${i}`}
32 | renderItem={({ item }) => }
33 | renderSectionHeader={({ section }) => (
34 |
35 | )}
36 | getItemLayout={(_, index) => ({
37 | length: TABBED_SECTION_ITEM_HEIGHT,
38 | offset: TABBED_SECTION_ITEM_HEIGHT * index,
39 | index,
40 | })}
41 | updateCellsBatchingPeriod={100}
42 | showsVerticalScrollIndicator={false}
43 | />
44 |
45 | >
46 | );
47 | };
48 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/index.ts:
--------------------------------------------------------------------------------
1 | export { AvatarHeaderFlatListExample } from './AvatarHeaderFlatListExample';
2 | export { AvatarHeaderScrollViewExample } from './AvatarHeaderScrollViewExample';
3 | export { AvatarHeaderSectionListExample } from './AvatarHeaderSectionListExample';
4 | export { DetailsHeaderFlatListExample } from './DetailsHeaderFlatListExample';
5 | export { DetailsHeaderScrollViewExample } from './DetailsHeaderScrollViewExample';
6 | export { DetailsHeaderSectionListExample } from './DetailsHeaderSectionListExample';
7 | export { StickyHeaderFlatListExample } from './StickyHeaderFlatListExample';
8 | export { StickyHeaderScrollViewExample } from './StickyHeaderScrollViewExample';
9 | export { StickyHeaderSectionListExample } from './StickyHeaderSectionListExample';
10 | export { TabbedHeaderListExample } from './TabbedHeaderListExample';
11 | export { TabbedHeaderPagerExample } from './TabbedHeaderPagerExample';
12 |
--------------------------------------------------------------------------------
/example/src/screens/additionalExamples/testIDs.ts:
--------------------------------------------------------------------------------
1 | export const avatarHeaderTestIDs = Object.freeze({
2 | headerLeftTopIcon: 'AvatarHeaderLeftTopIconTestID',
3 | headerRightTopIcon: 'AvatarHeaderRightTopIconTestID',
4 | subtitle: 'AvatarHeaderSubtitleTestID',
5 | title: 'AvatarHeaderTitleTestID',
6 | });
7 |
8 | export const detailsHeaderTestIDs = Object.freeze({
9 | headerLeftTopIcon: 'DetailsHeaderLeftTopIconTestID',
10 | headerRightTopIcon: 'DetailsHeaderRightTopIconTestID',
11 | contentIconNumber: 'DetailsHeaderContentIconNumberTestID',
12 | tag: 'DetailsHeaderTagTestID',
13 | title: 'DetailsHeaderTitleTestID',
14 | });
15 |
16 | export const tabbedHeaderTestIDs = Object.freeze({
17 | title: 'TabbedHeaderTitleTestID',
18 | });
19 |
--------------------------------------------------------------------------------
/example/src/screens/index.ts:
--------------------------------------------------------------------------------
1 | import CardScreen from './CardScreen';
2 | import HomeScreen from './HomeScreen';
3 | import SimsScreen from './SimsScreen';
4 | import YodaScreen from './YodaScreen';
5 |
6 | export { HomeScreen, CardScreen, SimsScreen, YodaScreen };
7 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "react-native-sticky-parallax-header": ["./../src/index"]
6 | },
7 | "allowJs": true,
8 | "allowUnreachableCode": false,
9 | "allowUnusedLabels": false,
10 | "esModuleInterop": true,
11 | "importsNotUsedAsValues": "error",
12 | "forceConsistentCasingInFileNames": true,
13 | "jsx": "react",
14 | "lib": ["esnext"],
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "noFallthroughCasesInSwitch": true,
18 | "noImplicitReturns": true,
19 | "noImplicitUseStrict": false,
20 | "noStrictGenericChecks": false,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "resolveJsonModule": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "target": "esnext"
27 | },
28 | "extends": "expo/tsconfig.base"
29 | }
30 |
--------------------------------------------------------------------------------
/example/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const createExpoWebpackConfigAsync = require('@expo/webpack-config');
4 |
5 | const { resolver } = require('./metro.config');
6 |
7 | const root = path.resolve(__dirname, '..');
8 | const node_modules = path.join(__dirname, 'node_modules');
9 |
10 | module.exports = async function (env, argv) {
11 | const config = await createExpoWebpackConfigAsync(env, argv);
12 |
13 | config.module.rules.push({
14 | test: /\.(js|jsx|ts|tsx)$/,
15 | include: path.resolve(root, 'src'),
16 | use: {
17 | loader: 'babel-loader',
18 | options: {
19 | plugins: ['react-native-reanimated/plugin'],
20 | },
21 | },
22 | });
23 |
24 | // We need to make sure that only one version is loaded for peerDependencies
25 | // So we alias them to the versions in example's node_modules
26 | Object.assign(config.resolve.alias, {
27 | ...resolver.extraNodeModules,
28 | 'react': path.resolve(node_modules, 'react'),
29 | 'react-native': path.resolve(node_modules, 'react-native-web'),
30 | 'react-native-web': path.resolve(node_modules, 'react-native-web'),
31 | });
32 |
33 | return config;
34 | };
35 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'react-native',
3 | modulePathIgnorePatterns: ['/example/', '/lib/'],
4 | setupFilesAfterEnv: ['./jest/setupTests.js'],
5 | };
6 |
--------------------------------------------------------------------------------
/jest/setupTests.js:
--------------------------------------------------------------------------------
1 | jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
2 |
--------------------------------------------------------------------------------
/scripts/bootstrap.js:
--------------------------------------------------------------------------------
1 | const child_process = require('child_process');
2 | const path = require('path');
3 |
4 | const root = path.resolve(__dirname, '..');
5 | const args = process.argv.slice(2);
6 | const options = {
7 | cwd: process.cwd(),
8 | env: process.env,
9 | stdio: 'inherit',
10 | encoding: 'utf-8',
11 | };
12 |
13 | let result;
14 |
15 | if (process.cwd() !== root || args.length) {
16 | // We're not in the root of the project, or additional arguments were passed
17 | // In this case, forward the command to `yarn`
18 | result = child_process.spawnSync('yarn', args, options);
19 | } else {
20 | // If `yarn` is run without arguments, perform bootstrap
21 | result = child_process.spawnSync('yarn', ['bootstrap'], options);
22 | }
23 |
24 | process.exitCode = result.status;
25 |
--------------------------------------------------------------------------------
/src/constants/colors.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | blue: 'blue',
3 | black: 'black',
4 | primaryGreen: '#1ca75d',
5 | secondaryGreen: 'rgb(61,179,106)',
6 | darkMint: 'rgb(72,189,126)',
7 | white: 'white',
8 | shadowColor: 'rgb(35,35,35)',
9 | transparent: 'transparent',
10 | purplishBlue: 'rgb(78, 15, 255)',
11 | purpleishBlue: 'rgb(89,80,249)',
12 | paleGrey: 'rgb(246,245,248)',
13 | greyishBrown: 'rgb(71,71,71)',
14 | coralPink: 'rgb(255,94,107)',
15 | jade: 'rgb(29,167,93)',
16 | whiteTransparent10: 'rgba(255, 255, 255, 0.1)',
17 | };
18 |
--------------------------------------------------------------------------------
/src/constants/commonStyles.ts:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import colors from './colors';
4 |
5 | const commonStyles = StyleSheet.create({
6 | column: {
7 | flexDirection: 'column',
8 | },
9 | container: {
10 | flex: 1,
11 | justifyContent: 'center',
12 | alignItems: 'center',
13 | alignSelf: 'stretch',
14 | },
15 | foreground: {
16 | flex: 1,
17 | paddingHorizontal: 24,
18 | justifyContent: 'flex-end',
19 | },
20 | foregroundRow: {
21 | flex: 1,
22 | paddingHorizontal: 24,
23 | alignItems: 'flex-end',
24 | justifyContent: 'space-around',
25 | },
26 | headerWrapper: {
27 | alignItems: 'center',
28 | alignSelf: 'stretch',
29 | flexDirection: 'row',
30 | justifyContent: 'space-between',
31 | paddingHorizontal: 24,
32 | paddingVertical: 12,
33 | },
34 | logo: {
35 | height: 24,
36 | width: 142,
37 | },
38 | message: {
39 | color: colors.white,
40 | fontSize: 48,
41 | lineHeight: 55,
42 | letterSpacing: -1,
43 | textAlign: 'left',
44 | },
45 | messageContainer: {
46 | paddingVertical: 24,
47 | },
48 | row: {
49 | flexDirection: 'row',
50 | },
51 | rowReverse: {
52 | flexDirection: 'row-reverse',
53 | },
54 | stretch: {
55 | alignSelf: 'stretch',
56 | },
57 | wrapper: {
58 | alignSelf: 'stretch',
59 | flex: 1,
60 | },
61 | });
62 |
63 | export default commonStyles;
64 |
--------------------------------------------------------------------------------
/src/constants/constants.ts:
--------------------------------------------------------------------------------
1 | const breakpoints = {
2 | smallPhoneShorterEdge: 320,
3 | mediumPhoneShorterEdge: 414,
4 | bigPhoneShorterEdge: 480,
5 | };
6 |
7 | export default {
8 | breakpoints,
9 | };
10 |
--------------------------------------------------------------------------------
/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | import colors from './colors';
2 | import commonStyles from './commonStyles';
3 | import constants from './constants';
4 |
5 | export { constants, colors, commonStyles };
6 |
--------------------------------------------------------------------------------
/src/hooks/useResponsiveSize.ts:
--------------------------------------------------------------------------------
1 | import { useWindowDimensions } from 'react-native';
2 |
3 | export function useResponsiveSize() {
4 | const { height, width } = useWindowDimensions();
5 |
6 | function responsiveHeight(value: number) {
7 | return height * (value / 100);
8 | }
9 |
10 | function responsiveWidth(value: number) {
11 | return width * (value / 100);
12 | }
13 |
14 | return { responsiveHeight, responsiveWidth };
15 | }
16 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | // Primitive components
2 | export { StickyHeaderFlatList } from './primitiveComponents/StickyHeaderFlatList';
3 | export { StickyHeaderScrollView } from './primitiveComponents/StickyHeaderScrollView';
4 | export { StickyHeaderSectionList } from './primitiveComponents/StickyHeaderSectionList';
5 | export { useStickyHeaderProps } from './primitiveComponents/useStickyHeaderProps';
6 | export { useStickyHeaderScrollProps } from './primitiveComponents/useStickyHeaderScrollProps';
7 | export { withStickyHeader } from './primitiveComponents/withStickyHeader';
8 | export * from './primitiveComponents/StickyHeaderProps';
9 | export { useStickyHeaderFlashListScrollProps } from './primitiveComponents/useStickyHeaderFlashListScrollProps';
10 | export { withStickyHeaderFlashList } from './primitiveComponents/withStickyHeaderFlashList';
11 |
12 | // Avatar components
13 | export { AvatarHeaderFlatList } from './predefinedComponents/AvatarHeader/AvatarHeaderFlatList';
14 | export { AvatarHeaderScrollView } from './predefinedComponents/AvatarHeader/AvatarHeaderScrollView';
15 | export { AvatarHeaderSectionList } from './predefinedComponents/AvatarHeader/AvatarHeaderSectionList';
16 | export * from './predefinedComponents/AvatarHeader/AvatarHeaderProps';
17 | export { withAvatarHeaderFlashList } from './predefinedComponents/AvatarHeader/withAvatarHeaderFlashList';
18 |
19 | // Details components
20 | export { DetailsHeaderFlatList } from './predefinedComponents/DetailsHeader/DetailsHeaderFlatList';
21 | export { DetailsHeaderScrollView } from './predefinedComponents/DetailsHeader/DetailsHeaderScrollView';
22 | export { DetailsHeaderSectionList } from './predefinedComponents/DetailsHeader/DetailsHeaderSectionList';
23 | export * from './predefinedComponents/DetailsHeader/DetailsHeaderProps';
24 | export { withDetailsHeaderFlashList } from './predefinedComponents/DetailsHeader/withDetailsHeaderFlashList';
25 |
26 | // Tabbed components
27 | export { TabbedHeaderList } from './predefinedComponents/TabbedHeader/TabbedHeaderList';
28 | export { TabbedHeaderPager } from './predefinedComponents/TabbedHeader/TabbedHeaderPager';
29 | export * from './predefinedComponents/TabbedHeader/TabbedHeaderProps';
30 | export { withTabbedHeaderFlashList } from './predefinedComponents/TabbedHeader/withTabbedHeaderFlashList';
31 |
--------------------------------------------------------------------------------
/src/predefinedComponents/AvatarHeader/AvatarHeaderProps.ts:
--------------------------------------------------------------------------------
1 | import type { ImageSourcePropType, StyleProp, TextStyle } from 'react-native';
2 | import type Animated from 'react-native-reanimated';
3 |
4 | import type {
5 | StickyHeaderFlashListProps,
6 | StickyHeaderFlatListProps,
7 | StickyHeaderScrollViewProps,
8 | StickyHeaderSectionListProps,
9 | } from '../../primitiveComponents/StickyHeaderProps';
10 | import type { AnimatedColorProp, IconProps, SharedPredefinedProps } from '../common/SharedProps';
11 |
12 | export interface AvatarHeaderSharedProps extends IconProps, SharedPredefinedProps {
13 | enableSafeAreaTopInset?: boolean;
14 | hasBorderRadius?: boolean;
15 | image?: ImageSourcePropType;
16 | subtitle?: string;
17 | subtitleStyle?: StyleProp>;
18 | subtitleTestID?: string;
19 | tabsContainerBackgroundColor?: AnimatedColorProp;
20 | title?: string;
21 | titleStyle?: StyleProp>;
22 | titleTestID?: string;
23 | }
24 |
25 | export interface AvatarHeaderScrollViewProps
26 | extends AvatarHeaderSharedProps,
27 | StickyHeaderScrollViewProps {}
28 |
29 | export interface AvatarHeaderFlatListProps
30 | extends AvatarHeaderSharedProps,
31 | StickyHeaderFlatListProps {}
32 |
33 | export interface AvatarHeaderSectionListProps
34 | extends AvatarHeaderSharedProps,
35 | StickyHeaderSectionListProps {}
36 |
37 | export interface AvatarHeaderFlashListProps
38 | extends Omit,
39 | StickyHeaderFlashListProps {}
40 |
--------------------------------------------------------------------------------
/src/predefinedComponents/AvatarHeader/hooks/useAvatarHeader.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import type { ScrollComponent } from '../../common/SharedProps';
4 | import { HeaderWrapper } from '../../common/components/HeaderWrapper';
5 | import { usePredefinedHeader } from '../../common/hooks/usePredefinedHeader';
6 | import type { AvatarHeaderScrollViewProps } from '../AvatarHeaderProps';
7 | import { Foreground } from '../components/HeaderForeground';
8 |
9 | export function useAvatarHeader(props: AvatarHeaderScrollViewProps) {
10 | const {
11 | contentBackgroundColor,
12 | onMomentumScrollEnd,
13 | onScroll,
14 | onScrollEndDrag,
15 | parallaxHeight,
16 | scrollHeight,
17 | scrollValue,
18 | scrollViewRef,
19 | } = usePredefinedHeader(props);
20 | const {
21 | backgroundColor,
22 | backgroundImage,
23 | hasBorderRadius,
24 | image,
25 | subtitle,
26 | subtitleStyle,
27 | subtitleTestID,
28 | tabsContainerBackgroundColor,
29 | title,
30 | titleStyle,
31 | titleTestID,
32 | } = props;
33 |
34 | const renderHeader = React.useCallback(() => {
35 | return (
36 |
45 |
56 |
57 | );
58 | }, [
59 | backgroundColor,
60 | backgroundImage,
61 | contentBackgroundColor,
62 | hasBorderRadius,
63 | image,
64 | parallaxHeight,
65 | scrollHeight,
66 | scrollValue,
67 | subtitle,
68 | subtitleStyle,
69 | subtitleTestID,
70 | tabsContainerBackgroundColor,
71 | title,
72 | titleStyle,
73 | titleTestID,
74 | ]);
75 |
76 | return {
77 | onMomentumScrollEnd,
78 | onScroll,
79 | onScrollEndDrag,
80 | parallaxHeight,
81 | renderHeader,
82 | scrollValue,
83 | scrollViewRef,
84 | };
85 | }
86 |
--------------------------------------------------------------------------------
/src/predefinedComponents/DetailsHeader/DetailsHeaderProps.ts:
--------------------------------------------------------------------------------
1 | import type { ImageSourcePropType, StyleProp, TextStyle } from 'react-native';
2 | import type Animated from 'react-native-reanimated';
3 |
4 | import type {
5 | StickyHeaderFlashListProps,
6 | StickyHeaderFlatListProps,
7 | StickyHeaderScrollViewProps,
8 | StickyHeaderSectionListProps,
9 | } from '../../primitiveComponents/StickyHeaderProps';
10 | import type { AnimatedColorProp, IconProps, SharedPredefinedProps } from '../common/SharedProps';
11 |
12 | export interface DetailsHeaderSharedProps extends IconProps, SharedPredefinedProps {
13 | contentIcon?: ImageSourcePropType;
14 | contentIconNumber?: number;
15 | contentIconNumberStyle?: StyleProp>;
16 | contentIconNumberTestID?: string;
17 | enableSafeAreaTopInset?: boolean;
18 | hasBorderRadius?: boolean;
19 | image?: ImageSourcePropType;
20 | tabsContainerBackgroundColor?: AnimatedColorProp;
21 | subtitle?: string;
22 | subtitleStyle?: StyleProp>;
23 | subtitleTestID?: string;
24 | tag?: string;
25 | tagStyle?: StyleProp>;
26 | tagTestID?: string;
27 | title?: string;
28 | titleStyle?: StyleProp>;
29 | titleTestID?: string;
30 | }
31 |
32 | export interface DetailsHeaderScrollViewProps
33 | extends DetailsHeaderSharedProps,
34 | StickyHeaderScrollViewProps {}
35 |
36 | export interface DetailsHeaderFlatListProps
37 | extends DetailsHeaderSharedProps,
38 | StickyHeaderFlatListProps {}
39 |
40 | export interface DetailsHeaderSectionListProps
41 | extends DetailsHeaderSharedProps,
42 | StickyHeaderSectionListProps {}
43 |
44 | export interface DetailsHeaderFlashListProps
45 | extends Omit,
46 | StickyHeaderFlashListProps {}
47 |
--------------------------------------------------------------------------------
/src/predefinedComponents/TabbedHeader/InternalTabbedHeaderProps.ts:
--------------------------------------------------------------------------------
1 | import type { RefObject } from 'react';
2 | import type { ScrollView, StyleProp, ViewStyle } from 'react-native';
3 | import type Animated from 'react-native-reanimated';
4 |
5 | export interface InternalPagerProps {
6 | disableScrollToPosition?: boolean;
7 | initialPage?: number;
8 | minScrollHeight: number;
9 | onChangeTab?: (previousPage: number, newPage: number) => void;
10 | page: number;
11 | pageContainerStyle?: StyleProp>;
12 | rememberTabScrollPosition?: boolean;
13 | scrollHeight: number;
14 | scrollRef: RefObject;
15 | scrollValue: Animated.SharedValue;
16 | swipedPage?: (index: number) => void;
17 | }
18 |
--------------------------------------------------------------------------------
/src/predefinedComponents/TabbedHeader/components/HeaderBar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type {
3 | ImageResizeMode,
4 | ImageSourcePropType,
5 | ImageStyle,
6 | StyleProp,
7 | ViewStyle,
8 | } from 'react-native';
9 | import Animated, { useAnimatedStyle } from 'react-native-reanimated';
10 | import type { Edge } from 'react-native-safe-area-context';
11 | import { SafeAreaView } from 'react-native-safe-area-context';
12 |
13 | import { commonStyles } from '../../../constants';
14 | import type { AnimatedColorProp } from '../../common/SharedProps';
15 | import { parseAnimatedColorProp } from '../../common/utils/parseAnimatedColorProp';
16 |
17 | interface HeaderBarProps {
18 | backgroundColor?: AnimatedColorProp;
19 | enableSafeAreaTopInset?: boolean;
20 | logo: ImageSourcePropType;
21 | logoContainerStyle?: StyleProp>;
22 | logoResizeMode?: ImageResizeMode;
23 | logoStyle?: StyleProp>;
24 | }
25 |
26 | export const HeaderBar: React.FC = ({
27 | backgroundColor,
28 | enableSafeAreaTopInset,
29 | logo,
30 | logoResizeMode,
31 | logoStyle,
32 | logoContainerStyle,
33 | }) => {
34 | const wrapperAnimatedStyle = useAnimatedStyle(() => {
35 | return {
36 | // TypeScript complains about AnimatedNode> from reanimated v1
37 | backgroundColor: parseAnimatedColorProp(backgroundColor) as string,
38 | };
39 | }, [backgroundColor]);
40 | const safeAreaEdges: Edge[] = ['left', 'right'];
41 |
42 | if (enableSafeAreaTopInset) {
43 | safeAreaEdges.push('top');
44 | }
45 |
46 | return (
47 | // @ts-ignore
48 |
49 |
50 |
55 |
56 |
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/src/predefinedComponents/TabbedHeader/hooks/useRenderTabs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type Animated from 'react-native-reanimated';
3 |
4 | import type { Tab } from '../../common/SharedProps';
5 | import type { TabsProps } from '../components/Tabs';
6 | import { Tabs } from '../components/Tabs';
7 |
8 | export function useRenderTabs(
9 | tabsProps: Omit & {
10 | tabs?: Tab[];
11 | horizontalScrollValue: Animated.SharedValue;
12 | }
13 | ) {
14 | const {
15 | activeTab,
16 | horizontalScrollValue,
17 | onTabPressed,
18 | tabTextActiveStyle,
19 | tabTextContainerActiveStyle,
20 | tabTextContainerStyle,
21 | tabTextStyle,
22 | tabUnderlineColor,
23 | tabWrapperStyle,
24 | tabs,
25 | tabsContainerBackgroundColor,
26 | tabsContainerHorizontalPadding,
27 | tabsContainerStyle,
28 | } = tabsProps;
29 |
30 | return React.useCallback(() => {
31 | if (!tabs) {
32 | return null;
33 | }
34 |
35 | return (
36 |
51 | );
52 | }, [
53 | activeTab,
54 | horizontalScrollValue,
55 | onTabPressed,
56 | tabTextActiveStyle,
57 | tabTextContainerActiveStyle,
58 | tabTextContainerStyle,
59 | tabTextStyle,
60 | tabUnderlineColor,
61 | tabWrapperStyle,
62 | tabs,
63 | tabsContainerBackgroundColor,
64 | tabsContainerHorizontalPadding,
65 | tabsContainerStyle,
66 | ]);
67 | }
68 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/SharedProps.ts:
--------------------------------------------------------------------------------
1 | import type { ReactElement } from 'react';
2 | import type {
3 | ColorValue,
4 | FlatList,
5 | ImageSourcePropType,
6 | NativeScrollEvent,
7 | ProcessedColorValue,
8 | ScrollView,
9 | SectionList,
10 | StyleProp,
11 | TextStyle,
12 | ViewStyle,
13 | } from 'react-native';
14 | import type Animated from 'react-native-reanimated';
15 |
16 | // FIXME: unknown does not work here :/
17 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
18 | export type ScrollComponent = ScrollView | FlatList | SectionList;
19 |
20 | export type AnimatedColorProp =
21 | | ColorValue
22 | | ProcessedColorValue
23 | | Animated.SharedValue;
24 |
25 | export type ColorProp = ColorValue | ProcessedColorValue;
26 |
27 | export interface IconProps {
28 | leftTopIcon?: (() => ReactElement | null) | ImageSourcePropType;
29 | leftTopIconAccessibilityLabel?: string;
30 | leftTopIconOnPress?: () => void;
31 | leftTopIconTestID?: string;
32 | rightTopIcon?: (() => ReactElement | null) | ImageSourcePropType;
33 | rightTopIconAccessibilityLabel?: string;
34 | rightTopIconOnPress?: () => void;
35 | rightTopIconTestID?: string;
36 | }
37 |
38 | export interface SharedPredefinedProps {
39 | backgroundColor?: AnimatedColorProp;
40 | backgroundImage?: ImageSourcePropType;
41 | contentContainerStyle?: StyleProp;
42 | headerHeight?: number;
43 | onMomentumScrollEnd?: (e: NativeScrollEvent) => void;
44 | onScroll?: (e: NativeScrollEvent) => void;
45 | onScrollEndDrag?: (e: NativeScrollEvent) => void;
46 | onTopReached?: () => void;
47 | parallaxHeight?: number;
48 | renderHeaderBar?: () => ReactElement | null;
49 | snapStartThreshold?: number;
50 | snapStopThreshold?: number;
51 | snapToEdge?: boolean;
52 | }
53 |
54 | export interface Tab {
55 | title?: string;
56 | icon?: (ReactElement | null) | ((isActive: boolean) => ReactElement | null);
57 | testID?: string;
58 | }
59 | export interface TabsConfig {
60 | tabTextActiveStyle?: StyleProp>;
61 | tabTextContainerStyle?: StyleProp>;
62 | tabTextContainerActiveStyle?: StyleProp>;
63 | tabTextStyle?: StyleProp>;
64 | tabUnderlineColor?: AnimatedColorProp;
65 | tabWrapperStyle?: StyleProp;
66 | tabs: Tab[];
67 | tabsContainerBackgroundColor?: AnimatedColorProp;
68 | tabsContainerHorizontalPadding?: number;
69 | tabsContainerStyle?: StyleProp;
70 | }
71 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/components/HeaderBackground.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet } from 'react-native';
3 | import Animated, { Extrapolate, interpolate, useAnimatedStyle } from 'react-native-reanimated';
4 |
5 | import type { AnimatedColorProp } from '../SharedProps';
6 | import { parseAnimatedColorProp } from '../utils/parseAnimatedColorProp';
7 |
8 | interface HeaderBackgroundProps {
9 | backgroundColor?: AnimatedColorProp;
10 | hasBorderRadius?: boolean;
11 | height: number;
12 | scrollValue: Animated.SharedValue;
13 | }
14 |
15 | export const HeaderBackground: React.FC = ({
16 | backgroundColor,
17 | hasBorderRadius,
18 | height,
19 | scrollValue,
20 | }) => {
21 | const animatedStyle = useAnimatedStyle(() => {
22 | const animatedBackgroundColor = parseAnimatedColorProp(backgroundColor);
23 |
24 | if (!hasBorderRadius) {
25 | return { backgroundColor: animatedBackgroundColor, borderBottomEndRadius: 0 };
26 | }
27 |
28 | return {
29 | backgroundColor: animatedBackgroundColor,
30 | borderBottomEndRadius: interpolate(
31 | scrollValue.value,
32 | [0, height],
33 | [80, 0],
34 | Extrapolate.EXTEND
35 | ),
36 | };
37 | }, [backgroundColor, hasBorderRadius, scrollValue, height]);
38 |
39 | return (
40 |
45 | );
46 | };
47 |
48 | const styles = StyleSheet.create({
49 | background: {
50 | alignItems: 'flex-start',
51 | alignSelf: 'stretch',
52 | flex: 1,
53 | justifyContent: 'flex-end',
54 | zIndex: -1,
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/components/HeaderBackgroundImage.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type { ImageSourcePropType } from 'react-native';
3 | import { ImageBackground, StyleSheet, useWindowDimensions } from 'react-native';
4 |
5 | interface HeaderBackgroundImageProps {
6 | background: React.ReactNode;
7 | backgroundHeight: number;
8 | backgroundImage: ImageSourcePropType;
9 | }
10 |
11 | export const HeaderBackgroundImage: React.FC = ({
12 | background,
13 | backgroundHeight,
14 | backgroundImage,
15 | }) => {
16 | const { width } = useWindowDimensions();
17 |
18 | return (
19 |
23 | {background}
24 |
25 | );
26 | };
27 |
28 | const styles = StyleSheet.create({
29 | headerStyle: {
30 | position: 'absolute',
31 | top: 0,
32 | left: 0,
33 | alignItems: 'flex-start',
34 | justifyContent: 'flex-end',
35 | zIndex: -1,
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/components/IconRenderer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type { ImageSourcePropType } from 'react-native';
3 | import { Image, StyleSheet } from 'react-native';
4 |
5 | interface Props {
6 | icon?: (() => React.ReactElement | null) | ImageSourcePropType;
7 | }
8 |
9 | const IconRenderer: React.FC = ({ icon }) => {
10 | if (typeof icon === 'function') {
11 | return icon();
12 | }
13 |
14 | return icon ? : null;
15 | };
16 |
17 | const styles = StyleSheet.create({
18 | icon: {
19 | width: 16,
20 | height: 16,
21 | marginTop: 3,
22 | },
23 | });
24 |
25 | export default IconRenderer;
26 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/hooks/usePredefinedFlashListHeader.tsx:
--------------------------------------------------------------------------------
1 | import type { FlashList } from '@shopify/flash-list';
2 | import { useMemo } from 'react';
3 | import { StyleSheet, useWindowDimensions } from 'react-native';
4 |
5 | import { useResponsiveSize } from '../../../hooks/useResponsiveSize';
6 | import { useStickyHeaderFlashListScrollProps } from '../../../primitiveComponents/useStickyHeaderFlashListScrollProps';
7 | import type { SharedPredefinedProps } from '../SharedProps';
8 |
9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 | export function usePredefinedFlashListHeader>(
11 | props: SharedPredefinedProps
12 | ) {
13 | const { height } = useWindowDimensions();
14 | const { responsiveHeight } = useResponsiveSize();
15 |
16 | const {
17 | onMomentumScrollEnd,
18 | onScroll,
19 | onScrollEndDrag,
20 | scrollHeight,
21 | scrollValue,
22 | scrollViewRef,
23 | } = useStickyHeaderFlashListScrollProps(props);
24 |
25 | const {
26 | contentContainerStyle,
27 | headerHeight = 100,
28 | parallaxHeight = responsiveHeight(53),
29 | } = props;
30 |
31 | const innerScrollHeight = height - headerHeight - parallaxHeight;
32 |
33 | const { contentBackgroundColor } = useMemo(() => {
34 | const contentContainerFlattenedStyle = StyleSheet.flatten(contentContainerStyle);
35 |
36 | return { contentBackgroundColor: contentContainerFlattenedStyle?.backgroundColor };
37 | }, [contentContainerStyle]);
38 |
39 | return {
40 | contentBackgroundColor,
41 | innerScrollHeight,
42 | onMomentumScrollEnd,
43 | onScroll,
44 | onScrollEndDrag,
45 | parallaxHeight,
46 | scrollHeight,
47 | scrollValue,
48 | scrollViewRef,
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/hooks/usePredefinedHeader.tsx:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 | import { StyleSheet, useWindowDimensions } from 'react-native';
3 |
4 | import { useResponsiveSize } from '../../../hooks/useResponsiveSize';
5 | import { useStickyHeaderScrollProps } from '../../../primitiveComponents/useStickyHeaderScrollProps';
6 | import type { ScrollComponent, SharedPredefinedProps } from '../SharedProps';
7 |
8 | export function usePredefinedHeader(props: SharedPredefinedProps) {
9 | const { height } = useWindowDimensions();
10 | const { responsiveHeight } = useResponsiveSize();
11 |
12 | const {
13 | onMomentumScrollEnd,
14 | onScroll,
15 | onScrollEndDrag,
16 | scrollHeight,
17 | scrollValue,
18 | scrollViewRef,
19 | } = useStickyHeaderScrollProps(props);
20 |
21 | const {
22 | contentContainerStyle,
23 | headerHeight = 100,
24 | parallaxHeight = responsiveHeight(53),
25 | } = props;
26 |
27 | const innerScrollHeight = height - headerHeight - parallaxHeight;
28 |
29 | const { contentBackgroundColor } = useMemo(() => {
30 | const contentContainerFlattenedStyle = StyleSheet.flatten(contentContainerStyle);
31 |
32 | return { contentBackgroundColor: contentContainerFlattenedStyle?.backgroundColor };
33 | }, [contentContainerStyle]);
34 |
35 | return {
36 | contentBackgroundColor,
37 | innerScrollHeight,
38 | onMomentumScrollEnd,
39 | onScroll,
40 | onScrollEndDrag,
41 | parallaxHeight,
42 | scrollHeight,
43 | scrollValue,
44 | scrollViewRef,
45 | };
46 | }
47 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/hooks/useRTLStyles.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 | import type { StyleProp } from 'react-native';
3 | import { Platform } from 'react-native';
4 | import { I18nManager } from 'react-native';
5 |
6 | /**
7 | * helper hook returning correct styles in rtl mode for Android and other platforms
8 | *
9 | * for some weird reason, padding/margin start/end does not work on Android
10 | *
11 | * example:
12 | *
13 | * const style = useRTLStyles({ paddingLeft: 5 }, { paddingRight: 5 }, { paddingStart: 5 })
14 | */
15 | export function useRTLStyles(
16 | ltrStyle: StyleProp,
17 | rtlStyle: StyleProp,
18 | defaultStyle: StyleProp
19 | ) {
20 | return useMemo(
21 | () =>
22 | Platform.select({
23 | android: I18nManager.isRTL ? rtlStyle : ltrStyle,
24 | default: defaultStyle,
25 | }),
26 | [defaultStyle, ltrStyle, rtlStyle]
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/utils/debounce.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | export function debounce any>(func: T, timeout = 300) {
3 | let timer: ReturnType;
4 |
5 | return function (this: any, ...args: Parameters) {
6 | clearTimeout(timer);
7 | timer = setTimeout(() => {
8 | func.apply(this, args);
9 | }, timeout);
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/utils/isNotEmpty.ts:
--------------------------------------------------------------------------------
1 | export function isNotEmpty(item: T | null): item is T {
2 | return item !== null;
3 | }
4 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/utils/parseAnimatedColorProp.ts:
--------------------------------------------------------------------------------
1 | import type { AnimatedColorProp, ColorProp } from '../SharedProps';
2 |
3 | export function parseAnimatedColorProp(
4 | animatedColorProp?: AnimatedColorProp
5 | ): ColorProp | undefined {
6 | 'worklet';
7 |
8 | return typeof animatedColorProp === 'undefined' ||
9 | typeof animatedColorProp === 'string' ||
10 | typeof animatedColorProp === 'number' ||
11 | typeof animatedColorProp === 'symbol'
12 | ? animatedColorProp
13 | : animatedColorProp?.value;
14 | }
15 |
--------------------------------------------------------------------------------
/src/predefinedComponents/common/utils/scrollPosition.ts:
--------------------------------------------------------------------------------
1 | export function scrollPosition(headerHeight: number, value: number) {
2 | return headerHeight * 0.01 * value;
3 | }
4 |
--------------------------------------------------------------------------------
/src/primitiveComponents/StickyHeaderFlatList.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactElement, RefAttributes } from 'react';
2 | import { FlatList } from 'react-native';
3 |
4 | import type { StickyHeaderFlatListProps } from './StickyHeaderProps';
5 | import { withStickyHeader } from './withStickyHeader';
6 |
7 | type StickyHeaderFlatListType = (
8 | props: StickyHeaderFlatListProps & RefAttributes>
9 | ) => ReactElement;
10 |
11 | export const StickyHeaderFlatList = withStickyHeader(FlatList) as StickyHeaderFlatListType;
12 |
--------------------------------------------------------------------------------
/src/primitiveComponents/StickyHeaderScrollView.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactElement, RefAttributes } from 'react';
2 | import { ScrollView } from 'react-native';
3 |
4 | import type { StickyHeaderScrollViewProps } from './StickyHeaderProps';
5 | import { withStickyHeader } from './withStickyHeader';
6 |
7 | type StickyHeaderScrollViewType = (
8 | props: StickyHeaderScrollViewProps & RefAttributes
9 | ) => ReactElement;
10 |
11 | export const StickyHeaderScrollView = withStickyHeader(ScrollView) as StickyHeaderScrollViewType;
12 |
--------------------------------------------------------------------------------
/src/primitiveComponents/StickyHeaderSectionList.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactElement, RefAttributes } from 'react';
2 | import { SectionList } from 'react-native';
3 |
4 | import type { StickyHeaderSectionListProps } from './StickyHeaderProps';
5 | import { withStickyHeader } from './withStickyHeader';
6 |
7 | type StickyHeaderSectionListType = (
8 | props: StickyHeaderSectionListProps & RefAttributes>
9 | ) => ReactElement;
10 |
11 | export const StickyHeaderSectionList = withStickyHeader(SectionList) as StickyHeaderSectionListType;
12 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig",
3 | "exclude": ["example", "./src/tests", "docs"]
4 | }
5 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "react-native-sticky-parallax-header": ["./src/index"]
6 | },
7 | "allowUnreachableCode": false,
8 | "allowUnusedLabels": false,
9 | "esModuleInterop": true,
10 | "importsNotUsedAsValues": "error",
11 | "forceConsistentCasingInFileNames": true,
12 | "jsx": "react",
13 | "lib": ["esnext"],
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitReturns": true,
18 | "noImplicitUseStrict": false,
19 | "noStrictGenericChecks": false,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "resolveJsonModule": true,
23 | "skipLibCheck": true,
24 | "strict": true,
25 | "target": "esnext",
26 | },
27 | "exclude": ["example", "docs"]
28 | }
29 |
--------------------------------------------------------------------------------