├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── checks.yml │ └── release.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── .yarnrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets ├── readme_Avatar.gif ├── readme_AvatarHeader.gif ├── readme_Details.gif ├── readme_DetailsHeader.gif ├── readme_Tabbed.gif ├── readme_TabbedHeader.gif ├── readme_TabbedHeaderList.gif ├── readme_header.svg ├── readme_netguru_logo.png ├── readme_quizlogo.svg └── readme_yoda.gif ├── babel.config.js ├── bitrise.yml ├── commitlint.config.js ├── docs ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── examples │ │ ├── _category_.json │ │ ├── custom-flashlist-header.md │ │ ├── custom-header.md │ │ └── custom-tabbed-header.md │ ├── guides │ │ ├── _category_.json │ │ ├── animated-color-props.md │ │ ├── custom-icons.md │ │ ├── icons-in-tabs.md │ │ ├── pull-to-refresh.md │ │ ├── react-navigation-header.md │ │ └── scrollview-reference.md │ ├── headers │ │ ├── _category_.json │ │ ├── avatar-header.md │ │ ├── custom-header.md │ │ ├── details-header.md │ │ ├── flashlist-headers.md │ │ ├── tabbed-header-list.md │ │ └── tabbed-header-pager.md │ └── introduction │ │ ├── _category_.json │ │ ├── getting-started.md │ │ ├── installation.md │ │ ├── migration-guide.md │ │ └── web-support.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── components │ │ ├── getStartedSection │ │ │ ├── GetStartedSection.module.css │ │ │ └── GetStartedSection.tsx │ │ ├── homePageHeader │ │ │ ├── HomePageHeader.module.css │ │ │ └── HomePageHeader.tsx │ │ └── sectionItem │ │ │ ├── SectionItem.module.css │ │ │ ├── SectionItem.tsx │ │ │ ├── SectionItemContent.tsx │ │ │ └── SectionItemImage.tsx │ ├── css │ │ └── custom.css │ ├── data │ │ └── sections.tsx │ └── pages │ │ └── index.tsx ├── static │ ├── .nojekyll │ ├── fonts │ │ ├── avertastd-regular-webfont.woff │ │ └── avertastd-regular-webfont.woff2 │ ├── img │ │ ├── N-Netguru-white.png │ │ ├── N-Netguru.png │ │ ├── assets │ │ │ ├── netguru-footer-logo.png │ │ │ ├── readme_Avatar.gif │ │ │ ├── readme_AvatarHeader.gif │ │ │ ├── readme_Details.gif │ │ │ ├── readme_DetailsHeader.gif │ │ │ ├── readme_Tabbed.gif │ │ │ ├── readme_TabbedHeader.gif │ │ │ ├── readme_TabbedHeaderList.gif │ │ │ ├── readme_header.svg │ │ │ ├── readme_netguru_logo.png │ │ │ └── readme_yoda.gif │ │ ├── bubbles.png │ │ ├── elements.png │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── netguru-footer-logo.png │ │ ├── netguru_logo.png │ │ ├── office-98.png │ │ ├── screenshot-hero.png │ │ ├── undraw_docusaurus_mountain.svg │ │ ├── undraw_docusaurus_react.svg │ │ └── undraw_docusaurus_tree.svg │ └── parallax-video.mp4 ├── tsconfig.json ├── versioned_docs │ ├── version-0.4.x │ │ ├── examples │ │ │ ├── _category_.json │ │ │ ├── custom-header.md │ │ │ └── custom-tabbed-header.md │ │ ├── guides │ │ │ ├── _category_.json │ │ │ ├── icons-in-tabs.md │ │ │ ├── nested-scrollables.md │ │ │ ├── pull-to-refresh.md │ │ │ └── scrollview-reference.md │ │ ├── headers │ │ │ ├── _category_.json │ │ │ ├── avatar-header.md │ │ │ ├── custom-header.md │ │ │ ├── details-header.md │ │ │ └── tabbed-header.md │ │ └── introduction │ │ │ ├── _category_.json │ │ │ ├── getting-started.md │ │ │ └── installation.md │ └── version-1.0.x │ │ ├── examples │ │ ├── _category_.json │ │ ├── custom-flashlist-header.md │ │ ├── custom-header.md │ │ └── custom-tabbed-header.md │ │ ├── guides │ │ ├── _category_.json │ │ ├── animated-color-props.md │ │ ├── custom-icons.md │ │ ├── icons-in-tabs.md │ │ ├── pull-to-refresh.md │ │ ├── react-navigation-header.md │ │ └── scrollview-reference.md │ │ ├── headers │ │ ├── _category_.json │ │ ├── avatar-header.md │ │ ├── custom-header.md │ │ ├── details-header.md │ │ ├── flashlist-headers.md │ │ ├── tabbed-header-list.md │ │ └── tabbed-header-pager.md │ │ └── introduction │ │ ├── _category_.json │ │ ├── getting-started.md │ │ ├── installation.md │ │ ├── migration-guide.md │ │ └── web-support.md ├── versioned_sidebars │ ├── version-0.4.x-sidebars.json │ └── version-1.0.x-sidebars.json ├── versions.json └── yarn.lock ├── example ├── .bundle │ └── config ├── .ruby-version ├── Gemfile ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── reactnativestickyparallaxheaderexample │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── reactnativestickyparallaxheaderexample │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainApplication.java │ │ │ │ └── newarchitecture │ │ │ │ ├── MainApplicationReactNativeHost.java │ │ │ │ ├── components │ │ │ │ └── MainComponentsRegistry.java │ │ │ │ └── modules │ │ │ │ └── MainApplicationTurboModuleManagerDelegate.java │ │ │ ├── jni │ │ │ ├── Android.mk │ │ │ ├── MainApplicationModuleProvider.cpp │ │ │ ├── MainApplicationModuleProvider.h │ │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp │ │ │ ├── MainApplicationTurboModuleManagerDelegate.h │ │ │ ├── MainComponentsRegistry.cpp │ │ │ ├── MainComponentsRegistry.h │ │ │ └── OnLoad.cpp │ │ │ └── res │ │ │ ├── drawable │ │ │ ├── rn_edit_text_material.xml │ │ │ └── splashscreen.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-night │ │ │ └── colors.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── .gitignore │ ├── Podfile │ ├── Podfile.lock │ ├── Podfile.properties.json │ ├── reactnativestickyparallaxheaderexample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── reactnativestickyparallaxheaderexample.xcscheme │ │ │ └── reactnativestickyparallaxheaderexamplerelease.xcscheme │ ├── reactnativestickyparallaxheaderexample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── reactnativestickyparallaxheaderexample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── SplashScreenBackground.imageset │ │ │ ├── Contents.json │ │ │ └── image.png │ │ ├── Info.plist │ │ ├── SplashScreen.storyboard │ │ ├── Supporting │ │ └── Expo.plist │ │ ├── main.m │ │ ├── noop-file.swift │ │ └── reactnativestickyparallaxheaderexample.entitlements ├── metro.config.js ├── package.json ├── src │ ├── App.tsx │ ├── assets │ │ ├── data │ │ │ ├── cards.ts │ │ │ ├── paragraphs.tsx │ │ │ ├── tabbedSections.ts │ │ │ └── testIDs.ts │ │ ├── favicon.png │ │ ├── fonts │ │ │ ├── AvertaStd-Regular.otf │ │ │ └── AvertaStd-Semibold.otf │ │ ├── icon.png │ │ ├── icons │ │ │ ├── Check.png │ │ │ ├── Check@2x.png │ │ │ ├── Check@3x.png │ │ │ ├── Close.png │ │ │ ├── Close@2x.png │ │ │ ├── Close@3x.png │ │ │ ├── Icon-Arrow.png │ │ │ ├── Icon-Arrow@2x.png │ │ │ ├── Icon-Arrow@3x.png │ │ │ ├── Icon-Menu.png │ │ │ ├── Icon-Menu@2x.png │ │ │ ├── Icon-Menu@3x.png │ │ │ ├── cards.png │ │ │ ├── cards@2x.png │ │ │ ├── cards@3x.png │ │ │ ├── cards_black.png │ │ │ ├── cards_black@2x.png │ │ │ ├── cards_black@3x.png │ │ │ ├── iconApp.png │ │ │ ├── iconApp@2x.png │ │ │ ├── iconApp@3x.png │ │ │ ├── iconCloseWhite.png │ │ │ ├── iconCloseWhite@2x.png │ │ │ ├── iconCloseWhite@3x.png │ │ │ ├── index.ts │ │ │ └── share.png │ │ ├── images │ │ │ ├── icon.png │ │ │ ├── index.ts │ │ │ ├── logo.png │ │ │ ├── logo@2x.png │ │ │ ├── logo@3x.png │ │ │ ├── photosPortraitBrandon.png │ │ │ ├── photosPortraitBrandon@2x.png │ │ │ ├── photosPortraitBrandon@3x.png │ │ │ ├── photosPortraitEwa.png │ │ │ ├── photosPortraitEwa@2x.png │ │ │ ├── photosPortraitEwa@3x.png │ │ │ ├── photosPortraitJennifer.png │ │ │ ├── photosPortraitJennifer@2x.png │ │ │ ├── photosPortraitJennifer@3x.png │ │ │ ├── photosPortraitMe.png │ │ │ ├── photosPortraitMe@2x.png │ │ │ └── photosPortraitMe@3x.png │ │ └── splash.png │ ├── components │ │ ├── exampleComponents │ │ │ ├── QuizCard.tsx │ │ │ ├── QuizListElement.tsx │ │ │ ├── QuizOption.tsx │ │ │ └── UserModal.tsx │ │ ├── index.ts │ │ ├── predefinedComponents │ │ │ ├── TabbedSectionHeader.tsx │ │ │ └── TabbedSectionItem.tsx │ │ └── primitiveComponents │ │ │ ├── Header.tsx │ │ │ ├── Paragraph.tsx │ │ │ ├── SectionFooter.tsx │ │ │ ├── SectionHeader.tsx │ │ │ └── Tabs.tsx │ ├── constants │ │ ├── colors.ts │ │ ├── constants.ts │ │ ├── index.ts │ │ └── screenStyles.ts │ ├── navigation │ │ ├── AppNavigator.tsx │ │ ├── routes.ts │ │ └── types.ts │ └── screens │ │ ├── CardScreen │ │ ├── index.tsx │ │ └── testIDs.ts │ │ ├── HomeScreen │ │ ├── ExampleLink.tsx │ │ ├── data.ts │ │ ├── index.tsx │ │ └── testIDs.ts │ │ ├── SimsScreen │ │ ├── Foreground.tsx │ │ ├── HeaderBar.tsx │ │ ├── data.ts │ │ ├── index.tsx │ │ └── testIDs.ts │ │ ├── YodaScreen │ │ ├── HeaderBar.tsx │ │ ├── data.ts │ │ ├── index.tsx │ │ └── testIDs.ts │ │ ├── additionalExamples │ │ ├── AvatarHeaderFlashListExample.tsx │ │ ├── AvatarHeaderFlatListExample.tsx │ │ ├── AvatarHeaderScrollViewExample.tsx │ │ ├── AvatarHeaderSectionListExample.tsx │ │ ├── DetailsHeaderFlashListExample.tsx │ │ ├── DetailsHeaderFlatListExample.tsx │ │ ├── DetailsHeaderScrollViewExample.tsx │ │ ├── DetailsHeaderSectionListExample.tsx │ │ ├── StickyHeaderFlashListExample.tsx │ │ ├── StickyHeaderFlatListExample.tsx │ │ ├── StickyHeaderScrollViewExample.tsx │ │ ├── StickyHeaderSectionListExample.tsx │ │ ├── TabbedHeaderFlashListExample.tsx │ │ ├── TabbedHeaderListExample.tsx │ │ ├── TabbedHeaderPagerExample.tsx │ │ ├── TabbedHeaderWithAnimatedColors.tsx │ │ ├── TabbedHeaderWithSectionLists.tsx │ │ ├── index.ts │ │ └── testIDs.ts │ │ └── index.ts ├── tsconfig.json ├── webpack.config.js └── yarn.lock ├── jest.config.js ├── jest └── setupTests.js ├── package.json ├── scripts └── bootstrap.js ├── src ├── constants │ ├── colors.ts │ ├── commonStyles.ts │ ├── constants.ts │ └── index.ts ├── hooks │ └── useResponsiveSize.ts ├── index.tsx ├── predefinedComponents │ ├── AvatarHeader │ │ ├── AvatarHeaderFlatList.tsx │ │ ├── AvatarHeaderProps.ts │ │ ├── AvatarHeaderScrollView.tsx │ │ ├── AvatarHeaderSectionList.tsx │ │ ├── components │ │ │ ├── HeaderBar.tsx │ │ │ └── HeaderForeground.tsx │ │ ├── hooks │ │ │ ├── useAvatarFlashListHeader.tsx │ │ │ └── useAvatarHeader.tsx │ │ └── withAvatarHeaderFlashList.tsx │ ├── DetailsHeader │ │ ├── DetailsHeaderFlatList.tsx │ │ ├── DetailsHeaderProps.ts │ │ ├── DetailsHeaderScrollView.tsx │ │ ├── DetailsHeaderSectionList.tsx │ │ ├── components │ │ │ ├── HeaderBar.tsx │ │ │ └── HeaderForeground.tsx │ │ ├── hooks │ │ │ ├── useDetailsFlashListHeader.tsx │ │ │ └── useDetailsHeader.tsx │ │ └── withDetailsHeaderFlashList.tsx │ ├── TabbedHeader │ │ ├── InternalTabbedHeaderProps.ts │ │ ├── TabbedHeaderList.tsx │ │ ├── TabbedHeaderPager.tsx │ │ ├── TabbedHeaderProps.ts │ │ ├── components │ │ │ ├── HeaderBar.tsx │ │ │ ├── HeaderForeground.tsx │ │ │ ├── Pager.tsx │ │ │ ├── TabItem.tsx │ │ │ └── Tabs.tsx │ │ ├── hooks │ │ │ ├── useRenderTabs.tsx │ │ │ ├── useTabbedFlashListHeader.tsx │ │ │ └── useTabbedHeader.tsx │ │ └── withTabbedHeaderFlashList.tsx │ └── common │ │ ├── SharedProps.ts │ │ ├── components │ │ ├── HeaderBackground.tsx │ │ ├── HeaderBackgroundImage.tsx │ │ ├── HeaderWrapper.tsx │ │ └── IconRenderer.tsx │ │ ├── hooks │ │ ├── usePredefinedFlashListHeader.tsx │ │ ├── usePredefinedHeader.tsx │ │ └── useRTLStyles.ts │ │ └── utils │ │ ├── debounce.ts │ │ ├── isNotEmpty.ts │ │ ├── parseAnimatedColorProp.ts │ │ └── scrollPosition.ts └── primitiveComponents │ ├── StickyHeaderFlatList.tsx │ ├── StickyHeaderProps.ts │ ├── StickyHeaderScrollView.tsx │ ├── StickyHeaderSectionList.tsx │ ├── useStickyHeaderFlashListScrollProps.ts │ ├── useStickyHeaderProps.ts │ ├── useStickyHeaderScrollProps.ts │ ├── withStickyHeader.tsx │ └── withStickyHeaderFlashList.tsx ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | /docs/build 2 | **/metro.config.js 3 | .eslintrc.js 4 | /jest/** 5 | node_modules/ 6 | lib/ 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: React Native Sticky Parallax Header - Bug 2 | description: Report a bug with React Native Sticky Parallax Header 3 | labels: [bug] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Environment 8 | description: | 9 | Provide environment on which the issue exists. 10 | value: | 11 | Library version: ??? 12 | OS version: ??? 13 | validations: 14 | required: true 15 | - type: checkboxes 16 | attributes: 17 | label: Affected platforms 18 | options: 19 | - label: "Android" 20 | - label: "iOS" 21 | validations: 22 | required: true 23 | - type: textarea 24 | attributes: 25 | label: Current behavior 26 | description: | 27 | Describe current behavior, add screenshots or videos, if it's affecting UI. 28 | placeholder: | 29 | Current behavior 30 | validations: 31 | required: true 32 | - type: textarea 33 | attributes: 34 | label: Expected behavior 35 | description: | 36 | Describe expected behavior. 37 | placeholder: | 38 | Expected behavior 39 | validations: 40 | required: true 41 | - type: textarea 42 | attributes: 43 | label: Reproduction 44 | description: | 45 | Add Link to reproduction repo, or add steps to reproduce. 46 | placeholder: | 47 | Link to repro 48 | validations: 49 | required: true 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: React Native Sticky Parallax Header - Feature 2 | description: Propose a feature in React Native Sticky Parallax Header 3 | labels: [enhancement] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Feature request 8 | description: | 9 | Describe feature request, why (and, if possible, how) it should be implemented 10 | validations: 11 | required: true 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | This pull request resolves ??? 2 | 3 | **Description** 4 | 5 | 6 | 7 | **Affected platforms** 8 | 9 | - [ ] Android 10 | - [ ] iOS 11 | 12 | **Test plan/screenshots/videos** 13 | 14 | 15 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Run checks 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | install: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [16.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: actions/cache@v2 20 | with: 21 | path: '**/node_modules' 22 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 23 | - name: Install modules 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | cache: 'yarn' 28 | cache-dependency-path: '**/yarn.lock' 29 | - run: yarn 30 | - name: Run Typescript 31 | run: yarn typescript 32 | - name: Run Lint 33 | run: yarn lint 34 | - name: Run Tests 35 | run: yarn test 36 | 37 | documentation: 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v1 41 | - uses: actions/setup-node@v1 42 | with: 43 | node-version: '12.x' 44 | - name: Test Documentation Build 45 | run: | 46 | cd docs 47 | if [ -e yarn.lock ]; then 48 | yarn install --frozen-lockfile 49 | elif [ -e package-lock.json ]; then 50 | npm ci 51 | else 52 | npm i 53 | fi 54 | npm run build 55 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release to NPM 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | install: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [ 16.x ] 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/cache@v2 16 | with: 17 | path: '**/node_modules' 18 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 19 | - name: Install modules 20 | uses: actions/setup-node@v2 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | cache: 'yarn' 24 | registry-url: 'https://registry.npmjs.org' 25 | cache-dependency-path: '**/yarn.lock' 26 | - run: yarn 27 | - name: Run Typescript 28 | run: yarn typescript 29 | - name: Run Tests 30 | run: yarn test 31 | - name: Run Linter 32 | run: yarn lint 33 | - name: Run Release 34 | uses: actions/setup-node@v2 35 | with: 36 | node-version: ${{ matrix.node-version }} 37 | cache: 'npm' 38 | registry-url: 'https://registry.npmjs.org' 39 | - run: | 40 | git config --global user.name ${{ secrets.USERNAME }} 41 | git config --global user.email ${{ secrets.USER_EMAIL }} 42 | npm run release --ci --npm.skipChecks 43 | env: 44 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 45 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 46 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 47 | token: ${{ secrets.GH_TOKEN }} 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .history 3 | 4 | 5 | # OSX 6 | # 7 | .DS_Store 8 | 9 | # XDE 10 | .expo/ 11 | 12 | # VSCode 13 | .vscode/ 14 | jsconfig.json 15 | 16 | # Xcode 17 | # 18 | build/ 19 | *.pbxuser 20 | !default.pbxuser 21 | *.mode1v3 22 | !default.mode1v3 23 | *.mode2v3 24 | !default.mode2v3 25 | *.perspectivev3 26 | !default.perspectivev3 27 | xcuserdata 28 | *.xccheckout 29 | *.moved-aside 30 | DerivedData 31 | *.hmap 32 | *.ipa 33 | *.xcuserstate 34 | project.xcworkspace 35 | 36 | # Android/IJ 37 | # 38 | .idea 39 | .gradle 40 | local.properties 41 | android.iml 42 | *.hprof 43 | 44 | # Cocoapods 45 | # 46 | ../sticky-parallax-header/example/example/ios/Pods 47 | 48 | # node.js 49 | # 50 | node_modules/ 51 | npm-debug.log 52 | yarn-debug.log 53 | yarn-error.log 54 | 55 | # BUCK 56 | buck-out/ 57 | \.buckd/ 58 | android/app/libs 59 | android/keystores/debug.keystore 60 | 61 | # Expo 62 | .expo/* 63 | 64 | # generated by bob 65 | lib/ 66 | 67 | /example/vendor/bundle 68 | 69 | .npmrc 70 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | readme_* 2 | examples 3 | docs 4 | node_modules 5 | yarn-error.log 6 | .history 7 | .DS_Store 8 | /assets 9 | !src/assets 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "jsxBracketSameLine": true, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Running/Development 4 | 1. iOS: 5 | ```sh 6 | yarn example ios 7 | ``` 8 | 9 | 2. Android: 10 | ```sh 11 | yarn example android 12 | ``` 13 | 14 | ## Running Tests 15 | ```sh 16 | yarn test 17 | ``` 18 | 19 | ## Creating new Pull Request 20 | * remember to add appropriate title, ticket, description 21 | * adding video or screenshot is very beneficial but it's not mandatory 22 | * additionally please remember to add appropriate Pull Request title from following: 23 | * `[RNS-XX] short description` - for normal feature branches 24 | * remember one pull request should always address one issue or feature 25 | 26 | ## Code structure 27 | ``` 28 | src/ 29 | ├──constants 30 | ├──hooks 31 | ├──predefinedComponents 32 | ├──primitiveComponents 33 | ``` 34 | 35 | ## Code Style 36 | * Make sure you are using linter with linting rules defined in ESLint config (.eslintrc.js) 37 | * Name branch according to your ticket following this pattern: RNS-XX-short_description 38 | * Imports and exports inside `index.tsx` files eg. `screens/index.tsx`, `components/index.tsx` should be sorted alphabetically 39 | * Style names should be ordered alphabetically 40 | * Please use commit lint and follow commit naming convention (https://www.conventionalcommits.org/en/v1.0.0/) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Netguru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/readme_Avatar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_Avatar.gif -------------------------------------------------------------------------------- /assets/readme_AvatarHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_AvatarHeader.gif -------------------------------------------------------------------------------- /assets/readme_Details.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_Details.gif -------------------------------------------------------------------------------- /assets/readme_DetailsHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_DetailsHeader.gif -------------------------------------------------------------------------------- /assets/readme_Tabbed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_Tabbed.gif -------------------------------------------------------------------------------- /assets/readme_TabbedHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_TabbedHeader.gif -------------------------------------------------------------------------------- /assets/readme_TabbedHeaderList.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_TabbedHeaderList.gif -------------------------------------------------------------------------------- /assets/readme_netguru_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_netguru_logo.png -------------------------------------------------------------------------------- /assets/readme_quizlogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/readme_yoda.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/assets/readme_yoda.gif -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```console 8 | yarn install 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```console 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```console 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ## Deployment 28 | 29 | ```console 30 | GIT_USER= USE_SSH=true yarn deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/docs/examples/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Examples", 3 | "position": 3 4 | } 5 | -------------------------------------------------------------------------------- /docs/docs/guides/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Guides", 3 | "position": 4 4 | } 5 | -------------------------------------------------------------------------------- /docs/docs/guides/custom-icons.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Rendering custom (styled) icons 6 | 7 | You can pass just React component to `leftTopIcon` & `rightTopIcon` prop in AvatarHeader or DetailsHeader components. 8 | 9 | ```tsx 10 | } 12 | rightTopIcon={() => } 13 | // ... 14 | > 15 | {/** content */} 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/docs/guides/icons-in-tabs.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | # Rendering icons in tabs 5 | 6 | You can pass just React component to `icon` property in tabs object. If you need different active icon use function, example below. 7 | 8 | ```tsx 9 | (active ? : ), 14 | }, 15 | ]} 16 | // ... 17 | > 18 | {/** content */} 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/docs/guides/pull-to-refresh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | # Pull to refresh 5 | 6 | All exported components inherits props of their underlying scroll component, to use default refresh control, just pass `onRefresh` & `refreshing` props. If you want to have custom setup (e.g. custom style), pass component as `refreshControl` prop 7 | 8 | ```tsx 9 | 15 | {/** content */} 16 | 17 | ``` 18 | 19 | ```tsx 20 | 32 | } 33 | // ... 34 | > 35 | {/** content */} 36 | 37 | ``` 38 | 39 | :::warning 40 | using `RefreshControl` on web, can break sticky header layout, because web implementation is just stubbed and doubles ScrollView's margin/padding 41 | 42 | to handle that, use it only when platform is not web 43 | 44 | ```tsx 45 | {...Platform.select({ default: { onRefresh, refreshing }, web: undefined })} 46 | ``` 47 | 48 | ```tsx 49 | refreshControl={ 50 | Platform.select({ 51 | default: ( 52 | 61 | ), 62 | web: undefined, 63 | }) 64 | } 65 | ``` 66 | ::: 67 | -------------------------------------------------------------------------------- /docs/docs/guides/react-navigation-header.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # React Navigation header and sticky header layout 6 | 7 | If react-navigation header inside the screen is used, sticky header component should have `enableSafeAreaTopInset` prop set to `false`, to prevent duplicated margin between react-navigation header and sticky header layout. 8 | 9 | Full example code can be found in [example repo](https://github.com/netguru/sticky-parallax-header/blob/master/example/src/screens/additionalExamples/TabbedHeaderWithSectionLists.tsx) 10 | 11 | ```tsx 12 | const TabbedHeaderWithSectionListsExample: React.FC = () => { 13 | const isDarkTheme = useColorScheme() === 'dark'; 14 | 15 | return ( 16 | <> 17 | ({ 33 | title: section.title, 34 | testID: section.testID, 35 | }))} 36 | tabTextStyle={screenStyles.text} 37 | showsVerticalScrollIndicator={false}> 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | }; 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/docs/guides/scrollview-reference.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | # Scroll component reference 5 | 6 | ## Handling reference to underlying `ScrollView`, `FlatList` or `SectionList` 7 | 8 | All exported components forward refs to underlying scroll component, to access it, just pass ref like when using conventional `ScrollView`, `FlatList` or `SectionList` 9 | 10 | ```tsx 11 | const paralaxScrollRef = useRef(null); 12 | 13 | 17 | {renderBody()} 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/docs/headers/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Headers", 3 | "position": 2 4 | } 5 | -------------------------------------------------------------------------------- /docs/docs/headers/custom-header.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Custom Sticky Header 6 | 7 | ## Example usage 8 | 9 | Check [custom header example](../examples/custom-header.md) 10 | 11 | ## Props 12 | 13 | ### StickyHeaderScrollViewProps 14 | 15 | Inherits [ScrollViewProps](https://reactnative.dev/docs/next/scrollview#props) and [Shared StickyHeader props](#shared-stickyheader-props) 16 | 17 | ### StickyHeaderFlatListProps 18 | 19 | Inherits [FlatListProps](https://reactnative.dev/docs/next/flatlist#props) and [Shared StickyHeader props](#shared-stickyheader-props) 20 | 21 | ### StickyHeaderSectionListProps 22 | 23 | Inherits [SectionListProps](https://reactnative.dev/docs/next/sectionlist#props) and [Shared StickyHeader props](#shared-stickyheader-props) 24 | 25 | ### Shared StickyHeader props 26 | | Prop | Type | Default value | 27 | | - | - | - | 28 | | containerStyle | style - `StyleProp` | - | 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/docs/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/docs/introduction/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Introduction", 3 | "position": 1 4 | } 5 | -------------------------------------------------------------------------------- /docs/docs/introduction/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Getting Started 6 | 7 | `react-native-sticky-parallax-header` is a simple React Native library, enabling to create a fully custom header layout for your iOS, Android and web apps. 8 | 9 | ## Features 10 | `react-native-sticky-parallax-header` provides two different type of components 11 | 12 | - primitive components - components with sticky header setup 13 | - predefined components - ready sticky header layouts 14 | 15 | ### Primitive components 16 | 17 | Library exports following components: 18 | 19 | - `StickyHeaderScrollView` 20 | - `StickyHeaderFlatList` 21 | - `StickyHeaderSectionList` 22 | 23 | There is also possibility to create its own "sticky header" component, thanks to: 24 | 25 | - `withStickyHeader` - HOC that wraps custom scroll component and sets up header & tabs layouts 26 | - `useStickyHeaderScrollProps` - hook that sets up scroll props passed to custom "sticky header" component including "snap effect" props 27 | 28 | ### Predefined components 29 | 30 | Library offers following header layout types: 31 | 32 | | Tabbed Header | Avatar Header | Details Header| 33 | | :------: | :------: | :------: | 34 | | ![Tabbed Header Gif](@site/static/img/assets/readme_TabbedHeader.gif) |![Avatar Header Gif](@site/static/img/assets/readme_AvatarHeader.gif)| ![Details Header Gif](@site/static/img/assets/readme_DetailsHeader.gif)| 35 | 36 | - `AvatarHeader(ScrollView|FlatList|SectionList)` 37 | - `DetailsHeader(ScrollView|FlatList|SectionList)` 38 | - `TabbedHeaderPager` 39 | - `TabbedHeaderList` 40 | 41 | ### FlashList HOCs 42 | 43 | Library also provides higher-order-components to enhance [FlashList](https://shopify.github.io/flash-list/docs/) with sticky header layouts: 44 | 45 | - `withAvatarHeaderFlashList` (will produce FlashList equivalent of `AvatarHeader(FlashList|SectionList)`) 46 | - `withDetailsHeaderFlashList` (will produce FlashList equivalent of `DetailsHeader(FlashList|SectionList)`) 47 | - `withTabbedHeaderFlashList` (will produce FlashList equivalent of `TabbedHeaderList`) 48 | 49 | As with primitive components, FlashList can also be customized to create its own "sticky header" layout, thanks to `withStickyHeaderFlashList` & `useStickyHeaderFlashListScrollProps` 50 | 51 | ## In Use 52 | 53 | **Check the live demo on Expo Snack [here](https://snack.expo.dev/@netguru_rnd/sticky-parallax-header-example).** 54 | 55 |
56 | -------------------------------------------------------------------------------- /docs/docs/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/docs/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/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-sticky-parallax-header-docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "2.0.1", 18 | "@docusaurus/preset-classic": "2.0.1", 19 | "@mdx-js/react": "^1.6.22", 20 | "@svgr/webpack": "^6.3.1", 21 | "clsx": "^1.2.1", 22 | "file-loader": "^6.2.0", 23 | "prism-react-renderer": "^1.3.5", 24 | "react": "^17.0.2", 25 | "react-dom": "^17.0.2", 26 | "url-loader": "^4.1.1" 27 | }, 28 | "devDependencies": { 29 | "@docusaurus/module-type-aliases": "2.0.1", 30 | "@tsconfig/docusaurus": "^1.0.6", 31 | "typescript": "^4.7.4" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.5%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | module.exports = { 13 | // By default, Docusaurus generates a sidebar from the docs folder structure 14 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 15 | 16 | // But you can create a sidebar manually 17 | /* 18 | tutorialSidebar: [ 19 | { 20 | type: 'category', 21 | label: 'Tutorial', 22 | items: ['hello'], 23 | }, 24 | ], 25 | */ 26 | }; 27 | -------------------------------------------------------------------------------- /docs/src/components/getStartedSection/GetStartedSection.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | background-color: var(--ifm-color-primary); 3 | height: 380px; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: space-around; 7 | align-items: center; 8 | padding: 50px 0px; 9 | } 10 | 11 | .title { 12 | font-size: 36px; 13 | font-weight: bold; 14 | line-height: 42px; 15 | color: white; 16 | } 17 | 18 | .description { 19 | color: var(--ifm-color-white); 20 | font-size: 24px; 21 | line-height: 28px; 22 | width: 700px; 23 | text-align: center; 24 | } 25 | 26 | .buttons { 27 | display: flex; 28 | align-items: center; 29 | justify-content: center; 30 | } 31 | 32 | .heroButton { 33 | border: 1px solid var(--ifm-color-white);; 34 | color: white; 35 | box-sizing: border-box; 36 | border-radius: 4px; 37 | display: flex; 38 | flex-direction: row; 39 | justify-content: center; 40 | align-items: center; 41 | padding: 8px 16px; 42 | } 43 | 44 | .heroButton:hover { 45 | text-decoration: none; 46 | color: var(--ifm-color-primary); 47 | color: var(--ifm-color-primary); 48 | background-color: white; 49 | } 50 | 51 | .heroButtonText { 52 | font-weight: bold; 53 | font-size: 18px; 54 | line-height: 21px; 55 | letter-spacing: 0.1em; 56 | text-transform: uppercase; 57 | padding: 5px 30px; 58 | } 59 | 60 | .libName { 61 | white-space: nowrap; 62 | background-color: var(--ifm-footer-background-color); 63 | } 64 | 65 | @media screen and (max-width: 966px) { 66 | .title { 67 | font-size: 24px; 68 | } 69 | .description { 70 | font-size: 16px; 71 | width: 350px; 72 | } 73 | .buttons { 74 | display: block; 75 | width: 100%; 76 | padding: 30px 25px; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/src/components/getStartedSection/GetStartedSection.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link'; 2 | import * as React from 'react'; 3 | 4 | import styles from './GetStartedSection.module.css'; 5 | 6 | const GetStartedSection: React.FC = () => { 7 | return ( 8 |
9 |
Get started
10 |
11 | Check out the full documentation for 12 |
13 | react-native-sticky-parallax-header 14 |
15 | and start using it in your projects. 16 |
17 |
18 | 19 | GET STARTED 20 | 21 |
22 |
23 | ); 24 | }; 25 | 26 | export default GetStartedSection; 27 | -------------------------------------------------------------------------------- /docs/src/components/homePageHeader/HomePageHeader.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link'; 2 | import useBaseUrl from '@docusaurus/useBaseUrl'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import clsx from 'clsx'; 5 | import * as React from 'react'; 6 | 7 | import styles from './HomePageHeader.module.css'; 8 | 9 | const HomePageHeader: React.FC = () => { 10 | const { siteConfig } = useDocusaurusContext(); 11 | 12 | return ( 13 |
14 |
15 | 19 |
20 |
21 |
22 |

{siteConfig.title}

23 |

{siteConfig.tagline}

24 |
25 | 26 | GET STARTED 27 | 28 |
29 |
30 |
31 | ); 32 | }; 33 | 34 | export default HomePageHeader; 35 | -------------------------------------------------------------------------------- /docs/src/components/sectionItem/SectionItem.module.css: -------------------------------------------------------------------------------- 1 | .backgroundOdd { 2 | background-color: var(--ifm-color-background); 3 | } 4 | 5 | .backgroundEven { 6 | background-color: var(--ifm-color-background-lighter); 7 | } 8 | 9 | .sectionTitle { 10 | font-size: 36px; 11 | line-height: 42px; 12 | color: var(--ifm-color-text) 13 | } 14 | 15 | .sectionDescription { 16 | font-size: 24px; 17 | line-height: 28px; 18 | max-width: 450px; 19 | color: var(--ifm-color-text-lighter); 20 | } 21 | 22 | .content { 23 | height: 100%; 24 | display: flex; 25 | flex-direction: column; 26 | justify-content: center; 27 | } 28 | 29 | .container { 30 | padding: 200px 0; 31 | } 32 | 33 | @media screen and (max-width: 966px) { 34 | .contentWrapper { 35 | order: 1 36 | } 37 | .content { 38 | align-items: center; 39 | } 40 | .row { 41 | display: flex; 42 | flex-direction: column; 43 | } 44 | .sectionTitle { 45 | font-size: 24px; 46 | line-height: 42px; 47 | } 48 | .sectionDescription { 49 | font-size: 16px; 50 | text-align: center; 51 | margin-bottom:30px; 52 | padding: 0 25px; 53 | } 54 | .container { 55 | padding: 70px 0; 56 | } 57 | .imageWrapper { 58 | display: flex; 59 | justify-content: center; 60 | align-items: center; 61 | order: 0; 62 | } 63 | .image { 64 | width: 220px; 65 | padding-bottom: 50px; 66 | } 67 | .smallerImage { 68 | width: 130px; 69 | padding-bottom: 50px; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /docs/src/components/sectionItem/SectionItem.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import * as React from 'react'; 3 | 4 | import styles from './SectionItem.module.css'; 5 | import { SectionItemContent } from './SectionItemContent'; 6 | import { SectionItemImage } from './SectionItemImage'; 7 | 8 | interface Props { 9 | description: string; 10 | imageName: string; 11 | index: number; 12 | title: string; 13 | } 14 | 15 | const SectionItem: React.FC = ({ index, title, description, imageName }) => { 16 | const isOdd = index % 2 === 0; 17 | 18 | return ( 19 |
20 |
21 | {isOdd ? ( 22 |
23 | 24 | 25 |
26 | ) : ( 27 |
28 | 29 | 30 |
31 | )} 32 |
33 |
34 | ); 35 | }; 36 | 37 | export default SectionItem; 38 | -------------------------------------------------------------------------------- /docs/src/components/sectionItem/SectionItemContent.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import * as React from 'react'; 3 | 4 | import styles from './SectionItem.module.css'; 5 | 6 | interface SectionItemContentProps { 7 | description: string; 8 | title: string; 9 | } 10 | 11 | export const SectionItemContent: React.FC = ({ description, title }) => { 12 | return ( 13 |
14 |
15 |

{title}

16 |
{description}
17 |
18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /docs/src/components/sectionItem/SectionItemImage.tsx: -------------------------------------------------------------------------------- 1 | import useBaseUrl from '@docusaurus/useBaseUrl'; 2 | import clsx from 'clsx'; 3 | import * as React from 'react'; 4 | 5 | import styles from './SectionItem.module.css'; 6 | 7 | interface SectionItemImageProps { 8 | index: number; 9 | imageName: string; 10 | } 11 | 12 | export const SectionItemImage: React.FC = ({ imageName, index }) => { 13 | return ( 14 |
15 | {imageName} 20 |
21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /docs/src/data/sections.tsx: -------------------------------------------------------------------------------- 1 | export const SECTIONS_DATA = [ 2 | { 3 | id: 1, 4 | title: 'Easy to use', 5 | description: 6 | 'Three predefined components included and the possibility to create a fully custom header.', 7 | imageName: 'bubbles', 8 | }, 9 | { 10 | id: 2, 11 | title: 'Type safe', 12 | description: 13 | 'Written in TypeScript and therefore compatibile with projects created in JavaScript and TypeScript.', 14 | imageName: 'office-98', 15 | }, 16 | { 17 | id: 3, 18 | title: 'Modern solution', 19 | description: 'Powered by react-native-reanimated, react-native-safe-area-context', 20 | imageName: 'elements', 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /docs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 2 | import Layout from '@theme/Layout'; 3 | import * as React from 'react'; 4 | 5 | import GetStartedSection from '../components/getStartedSection/GetStartedSection'; 6 | import HomePageHeader from '../components/homePageHeader/HomePageHeader'; 7 | import SectionItem from '../components/sectionItem/SectionItem'; 8 | import { SECTIONS_DATA } from '../data/sections'; 9 | 10 | const Home: React.FC = () => { 11 | const { siteConfig } = useDocusaurusContext(); 12 | 13 | return ( 14 | 17 | 18 | {SECTIONS_DATA.map((data, index) => { 19 | return ( 20 | 27 | ); 28 | })} 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default Home; 35 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/fonts/avertastd-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/fonts/avertastd-regular-webfont.woff -------------------------------------------------------------------------------- /docs/static/fonts/avertastd-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/fonts/avertastd-regular-webfont.woff2 -------------------------------------------------------------------------------- /docs/static/img/N-Netguru-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/N-Netguru-white.png -------------------------------------------------------------------------------- /docs/static/img/N-Netguru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/N-Netguru.png -------------------------------------------------------------------------------- /docs/static/img/assets/netguru-footer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/netguru-footer-logo.png -------------------------------------------------------------------------------- /docs/static/img/assets/readme_Avatar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_Avatar.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_AvatarHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_AvatarHeader.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_Details.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_Details.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_DetailsHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_DetailsHeader.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_Tabbed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_Tabbed.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_TabbedHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_TabbedHeader.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_TabbedHeaderList.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_TabbedHeaderList.gif -------------------------------------------------------------------------------- /docs/static/img/assets/readme_netguru_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_netguru_logo.png -------------------------------------------------------------------------------- /docs/static/img/assets/readme_yoda.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/assets/readme_yoda.gif -------------------------------------------------------------------------------- /docs/static/img/bubbles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/bubbles.png -------------------------------------------------------------------------------- /docs/static/img/elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/elements.png -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/netguru-footer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/netguru-footer-logo.png -------------------------------------------------------------------------------- /docs/static/img/netguru_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/netguru_logo.png -------------------------------------------------------------------------------- /docs/static/img/office-98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/office-98.png -------------------------------------------------------------------------------- /docs/static/img/screenshot-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/img/screenshot-hero.png -------------------------------------------------------------------------------- /docs/static/parallax-video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netguru/sticky-parallax-header/47bfe198552aa067b4a56a8584661b2c24c88089/docs/static/parallax-video.mp4 -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "resolveJsonModule": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/examples/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Examples", 3 | "position": 3 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/examples/custom-header.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Custom Header 6 | 7 | Check out a blogpost explaining in details how to customize Avatar Header: 8 | 9 | [Implement an App Store Header in React Native With Sticky Parallax Library](https://www.netguru.com/codestories/implement-an-app-store-header-in-react-native-with-sticky-parallax-library) 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/guides/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Guides", 3 | "position": 4 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/guides/icons-in-tabs.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | # Rendering icons in tabs 5 | 6 | You can pass just React component to `icon` property in tabs object. If you need different active icon use function, example below. 7 | 8 | ```jsx 9 | (active ? : ), 14 | content: this.renderContent('Popular Quizes'), 15 | }, 16 | ]} 17 | /> 18 | ... 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/guides/nested-scrollables.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | # Handling nested scrollables 5 | 6 | In order to nest scrollable component use `scrollEnabled={false}` on it and move all the logic to the header eg. by using `onEndReached` and `onTopReached` props. You can find example in CardScreen.tsx it's really basic so probably you will want to extend it somehow: 7 | 8 | ```jsx 9 | shouldBeEnabled = () => { 10 | const { endReached, stickyHeaderEndReached, topReached, stickyHeaderTopReached } = this.state; 11 | const bottomCondition = endReached && stickyHeaderEndReached; 12 | const topCondition = topReached && stickyHeaderTopReached; 13 | return bottomCondition || !topCondition; 14 | }; 15 | onScroll = ({ nativeEvent }) => { 16 | const { contentOffset, layoutMeasurement, contentSize } = nativeEvent; 17 | if (layoutMeasurement.height + contentOffset.y >= contentSize.height - 20) { 18 | this.setState({ endReached: true, topReached: false }); 19 | } 20 | if (contentOffset.y <= 0) { 21 | this.setState({ topReached: true, endReached: false, stickyHeaderTopReached: true }); 22 | } 23 | }; 24 | renderFlatlistContent = (user) => ( 25 | 26 | ( 29 | 30 | )} 31 | onScroll={this.onScroll} 32 | scrollEnabled={Platform.OS === 'android' ? true : this.shouldBeEnabled()} 33 | nestedScrollEnabled 34 | /> 35 | 36 | ); 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/guides/pull-to-refresh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | # Pull to refresh 5 | 6 | ```jsx 7 | 18 | } 19 | /> 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/guides/scrollview-reference.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | # ScrollView reference 5 | 6 | ## Handling StickyParallaxHeader body ScrollView reference 7 | 8 | ### As callback function 9 | ```tsx 10 | { 12 | paralaxScrollRef.current = ref; 13 | }} 14 | foreground={this.renderForeground()} 15 | header={this.renderHeader()} 16 | > 17 | {renderBody()} 18 | 19 | ``` 20 | 21 | ### As useRef value 22 | ```tsx 23 | const paralaxScrollRef = useRef(null); 24 | 29 | {renderBody()} 30 | 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/headers/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Headers", 3 | "position": 2 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/introduction/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Introduction", 3 | "position": 1 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/introduction/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Getting Started 6 | 7 | `react-native-sticky-parallax-header` is a simple React Native library, enabling to create a fully custom header for your iOS and Android apps. 8 | 9 | ## Features 10 | `react-native-sticky-parallax-header` ships with 3 different use cases for sticky headers and a possibility to create fully custom header! 11 | 12 | | Tabbed Header | Avatar Header | Details Header| 13 | | :------: | :------: | :------: | 14 | | ![Tabbed Header Gif](@site/static/img/assets/readme_TabbedHeader.gif) |![Avatar Header Gif](@site/static/img/assets/readme_AvatarHeader.gif)| ![Details Header Gif](@site/static/img/assets/readme_DetailsHeader.gif)| 15 | 16 | ## In Use 17 | 18 | Predefined headers can be accessed through `headerType="HeaderName"` property, each header can be configured according to your demands using the wide amount of properties. You can change all of them, or use it right out of the box with as little changes as possible to use it for your needs 19 | 20 | This is how you can add them in your app: 21 | 22 | ```tsx 23 | import * as React from 'react' 24 | import StickyParallaxHeader from 'react-native-sticky-parallax-header' 25 | 26 | const TestScreen = () => ( 27 | <> 28 | 29 | {/* */} 30 | {/* */} 31 | 32 | ) 33 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-0.4.x/introduction/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Installation 6 | 7 | ## Prerequisites 8 | * [React Native](https://facebook.github.io/react-native/docs/getting-started.html) 9 | * [Yarn](https://yarnpkg.com/en/docs/install) 10 | * [node v10.9.0](https://github.com/creationix/nvm) 11 | 12 | ## Installation 13 | ### For React Native >= 0.60.0 use version 0.0.60 and above, for previous React Native versions use 0.0.59 14 | ### Installation for React Native >= 0.60.0 15 | 16 | Add latest package version 17 | ```bash 18 | $ yarn add react-native-sticky-parallax-header 19 | ``` 20 | 21 | ### Installation for React Native < 0.60.0 22 | 23 | Add package version 0.0.59 24 | ```bash 25 | $ yarn add react-native-sticky-parallax-header@0.0.59 26 | ``` 27 | 28 | Link fonts 29 | ```bash 30 | $ react-native link react-native-sticky-parallax-header 31 | ``` 32 | 33 | In order to make tab bar work, we have to link react-native-nested-scroll-view package 34 | ```bash 35 | $ react-native link react-native-nested-scroll-view 36 | ``` 37 | 38 | Depending on the version of React Native you use, the package can be still making issues for you, you have to install patch-package 39 | ```bash 40 | $ yarn add patch-package postinstall-postinstall 41 | ``` 42 | 43 | Then you add this script to your scripts: 44 | ```bash 45 | "scripts": { 46 | + "postinstall": "patch-package" 47 | } 48 | ``` 49 | 50 | _After all those steps, just copy a 'patches' folder from this repository and run `yarn` again to apply the patched package. 51 | You're ready to use the package now._ 52 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/examples/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Examples", 3 | "position": 3 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Guides", 3 | "position": 4 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/custom-icons.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Rendering custom (styled) icons 6 | 7 | You can pass just React component to `leftTopIcon` & `rightTopIcon` prop in AvatarHeader or DetailsHeader components. 8 | 9 | ```tsx 10 | } 12 | rightTopIcon={() => } 13 | // ... 14 | > 15 | {/** content */} 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/icons-in-tabs.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | # Rendering icons in tabs 5 | 6 | You can pass just React component to `icon` property in tabs object. If you need different active icon use function, example below. 7 | 8 | ```tsx 9 | (active ? : ), 14 | }, 15 | ]} 16 | // ... 17 | > 18 | {/** content */} 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/pull-to-refresh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | # Pull to refresh 5 | 6 | All exported components inherits props of their underlying scroll component, to use default refresh control, just pass `onRefresh` & `refreshing` props. If you want to have custom setup (e.g. custom style), pass component as `refreshControl` prop 7 | 8 | ```tsx 9 | 15 | {/** content */} 16 | 17 | ``` 18 | 19 | ```tsx 20 | 32 | } 33 | // ... 34 | > 35 | {/** content */} 36 | 37 | ``` 38 | 39 | :::warning 40 | using `RefreshControl` on web, can break sticky header layout, because web implementation is just stubbed and doubles ScrollView's margin/padding 41 | 42 | to handle that, use it only when platform is not web 43 | 44 | ```tsx 45 | {...Platform.select({ default: { onRefresh, refreshing }, web: undefined })} 46 | ``` 47 | 48 | ```tsx 49 | refreshControl={ 50 | Platform.select({ 51 | default: ( 52 | 61 | ), 62 | web: undefined, 63 | }) 64 | } 65 | ``` 66 | ::: 67 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/react-navigation-header.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # React Navigation header and sticky header layout 6 | 7 | If react-navigation header inside the screen is used, sticky header component should have `enableSafeAreaTopInset` prop set to `false`, to prevent duplicated margin between react-navigation header and sticky header layout. 8 | 9 | Full example code can be found in [example repo](https://github.com/netguru/sticky-parallax-header/blob/master/example/src/screens/additionalExamples/TabbedHeaderWithSectionLists.tsx) 10 | 11 | ```tsx 12 | const TabbedHeaderWithSectionListsExample: React.FC = () => { 13 | const isDarkTheme = useColorScheme() === 'dark'; 14 | 15 | return ( 16 | <> 17 | ({ 33 | title: section.title, 34 | testID: section.testID, 35 | }))} 36 | tabTextStyle={screenStyles.text} 37 | showsVerticalScrollIndicator={false}> 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | }; 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/guides/scrollview-reference.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | # Scroll component reference 5 | 6 | ## Handling reference to underlying `ScrollView`, `FlatList` or `SectionList` 7 | 8 | All exported components forward refs to underlying scroll component, to access it, just pass ref like when using conventional `ScrollView`, `FlatList` or `SectionList` 9 | 10 | ```tsx 11 | const paralaxScrollRef = useRef(null); 12 | 13 | 17 | {renderBody()} 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/headers/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Headers", 3 | "position": 2 4 | } 5 | -------------------------------------------------------------------------------- /docs/versioned_docs/version-1.0.x/headers/custom-header.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Custom Sticky Header 6 | 7 | ## Example usage 8 | 9 | Check [custom header example](../examples/custom-header.md) 10 | 11 | ## Props 12 | 13 | ### StickyHeaderScrollViewProps 14 | 15 | Inherits [ScrollViewProps](https://reactnative.dev/docs/next/scrollview#props) and [Shared StickyHeader props](#shared-stickyheader-props) 16 | 17 | ### StickyHeaderFlatListProps 18 | 19 | Inherits [FlatListProps](https://reactnative.dev/docs/next/flatlist#props) and [Shared StickyHeader props](#shared-stickyheader-props) 20 | 21 | ### StickyHeaderSectionListProps 22 | 23 | Inherits [SectionListProps](https://reactnative.dev/docs/next/sectionlist#props) and [Shared StickyHeader props](#shared-stickyheader-props) 24 | 25 | ### Shared StickyHeader props 26 | | Prop | Type | Default value | 27 | | - | - | - | 28 | | containerStyle | style - `StyleProp` | - | 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 | --------------------------------------------------------------------------------