├── .nvmrc
├── .watchmanconfig
├── example
├── App.js
├── assets
│ ├── cabin.jpg
│ ├── icon.png
│ ├── favicon.png
│ ├── splash.png
│ └── adaptive-icon.png
├── tsconfig.json
├── src
│ ├── utils
│ │ ├── index.ts
│ │ └── enums.ts
│ ├── components
│ │ ├── index.ts
│ │ ├── HeaderComponent.tsx
│ │ ├── RoundButton.tsx
│ │ ├── Card.tsx
│ │ ├── HeaderNavBar.tsx
│ │ └── TopNavBar.tsx
│ ├── types.d.ts
│ ├── icons
│ │ ├── ArrowLeft.tsx
│ │ ├── ArrowRight.tsx
│ │ └── Share.tsx
│ ├── screens
│ │ ├── OnlyForegroundExample.tsx
│ │ ├── ImageForegroundExample.tsx
│ │ ├── HeaderNavBarExample.tsx
│ │ ├── SafeAreaViewExample.tsx
│ │ ├── HeaderNavbarFlatListExample.tsx
│ │ ├── RefreshControlExample.tsx
│ │ └── ExamplesDirectory.tsx
│ └── App.tsx
├── babel.config.js
├── app.json
├── README.md
├── webpack.config.js
├── package.json
└── metro.config.js
├── src
├── index.tsx
├── constants.ts
├── components
│ ├── index.ts
│ ├── AnimatedNavbar.tsx
│ ├── AnimatedFlatList.tsx
│ ├── AnimatedScrollView.tsx
│ └── AnimatedHeader.tsx
├── hooks
│ ├── useAnimateNavbar.ts
│ └── useAnimateScrollView.ts
├── types.d.ts
└── __tests__
│ └── useAnimateNavbar.test.ts
├── .gitattributes
├── tsconfig.build.json
├── babel.config.js
├── preview-ios.gif
├── .yarnrc
├── .editorconfig
├── lefthook.yml
├── .github
├── dependabot.yml
├── workflows
│ ├── pull-request.yml
│ ├── codeql.yml
│ └── ci.yml
├── actions
│ └── setup
│ │ └── action.yml
└── PULL_REQUEST_TEMPLATE.md
├── tsconfig.json
├── scripts
└── bootstrap.js
├── .gitignore
├── LICENSE
├── CHANGELOG.md
├── CONTRIBUTING.md
├── package.json
├── README.md
└── CODE_OF_CONDUCT.md
/.nvmrc:
--------------------------------------------------------------------------------
1 | 16.18.1
2 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/App.js:
--------------------------------------------------------------------------------
1 | export { default } from './src/App';
2 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | export { AnimatedScrollView, AnimatedFlatList } from './components';
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 | # specific for windows script files
3 | *.bat text eol=crlf
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const IMG_HEADER_HEIGHT = 300;
2 | export const HEADER_HEIGHT = 90;
3 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "extends": "./tsconfig",
4 | "exclude": ["example"]
5 | }
6 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/preview-ios.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/preview-ios.gif
--------------------------------------------------------------------------------
/example/assets/cabin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/example/assets/cabin.jpg
--------------------------------------------------------------------------------
/example/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/example/assets/icon.png
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
1 | # Override Yarn command so we can automatically setup the repo on running `yarn`
2 |
3 | yarn-path "scripts/bootstrap.js"
4 |
--------------------------------------------------------------------------------
/example/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/example/assets/favicon.png
--------------------------------------------------------------------------------
/example/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/example/assets/splash.png
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export { AnimatedScrollView } from './AnimatedScrollView';
2 | export { AnimatedFlatList } from './AnimatedFlatList';
3 |
--------------------------------------------------------------------------------
/example/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kanelloc/react-native-animated-header-scroll-view/HEAD/example/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig",
3 | "compilerOptions": {
4 | // Avoid expo-cli auto-generating a tsconfig
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { Platform } from 'react-native';
2 |
3 | export const isIOS = Platform.OS === 'ios';
4 |
5 | export const data = Array.from(Array(20).keys());
6 |
--------------------------------------------------------------------------------
/example/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export { Card } from './Card';
2 | export { TopNavBar } from './TopNavBar';
3 | export { HeaderNavBar } from './HeaderNavBar';
4 | export { RoundButton } from './RoundButton';
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | indent_style = space
10 | indent_size = 2
11 |
12 | end_of_line = lf
13 | charset = utf-8
14 | trim_trailing_whitespace = true
15 | insert_final_newline = true
16 |
--------------------------------------------------------------------------------
/example/src/types.d.ts:
--------------------------------------------------------------------------------
1 | export type RootStackParamList = {
2 | ExamplesDirectory: undefined;
3 | HeaderNavBarExample: undefined;
4 | SafeAreaViewExample: undefined;
5 | SimpleExample: undefined;
6 | ImageForegroundExample: undefined;
7 | OnlyForegroundExample: undefined;
8 | RefreshControlExample: undefined;
9 | HeaderNavbarFlatListExample: undefined;
10 | };
11 |
--------------------------------------------------------------------------------
/lefthook.yml:
--------------------------------------------------------------------------------
1 | pre-commit:
2 | parallel: true
3 | commands:
4 | lint:
5 | files: git diff --name-only @{push}
6 | glob: "*.{js,ts,jsx,tsx}"
7 | run: npx eslint {files}
8 | types:
9 | files: git diff --name-only @{push}
10 | glob: "*.{js,ts, jsx, tsx}"
11 | run: npx tsc --noEmit
12 | commit-msg:
13 | parallel: true
14 | commands:
15 | commitlint:
16 | run: npx commitlint --edit
17 |
--------------------------------------------------------------------------------
/example/src/utils/enums.ts:
--------------------------------------------------------------------------------
1 | export enum SCREENS {
2 | EXAMPLES_DIRECTORY = 'ExamplesDirectory',
3 | HEADER_NAVBAR_EXAMPLE = 'HeaderNavBarExample',
4 | SAFE_AREA_VIEW_EXAMPLE = 'SafeAreaViewExample',
5 | IMAGE_FOREGROUND_EXAMPLE = 'ImageForegroundExample',
6 | ONLY_FOREGROUND_EXAMPLE = 'OnlyForegroundExample',
7 | REFRESH_CONTROL_EXAMPLE = 'RefreshControlExample',
8 | HEADER_NAVBAR_FLATLIST_EXAMPLE = 'HeaderNavbarFlatListExample',
9 | }
10 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 | target-branch: "main"
13 |
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const pak = require('../package.json');
3 |
4 | module.exports = function (api) {
5 | api.cache(true);
6 |
7 | return {
8 | presets: ['babel-preset-expo'],
9 | plugins: [
10 | [
11 | 'module-resolver',
12 | {
13 | extensions: ['.tsx', '.ts', '.js', '.json'],
14 | alias: {
15 | // For development, we want to alias the library to the source
16 | [pak.name]: path.join(__dirname, '..', pak.source),
17 | },
18 | },
19 | ],
20 | ],
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/example/src/components/HeaderComponent.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native';
2 | import React from 'react';
3 |
4 | export const HeaderComponent = () => (
5 |
6 |
7 | Foreground component
8 |
9 |
10 | );
11 |
12 | const styles = StyleSheet.create({
13 | container: {
14 | flex: 1,
15 | backgroundColor: 'transparent',
16 | alignItems: 'center',
17 | justifyContent: 'center',
18 | },
19 | titleContainer: {
20 | backgroundColor: 'white',
21 | },
22 | });
23 |
--------------------------------------------------------------------------------
/example/src/icons/ArrowLeft.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import Svg, { Path } from 'react-native-svg';
3 | import { StyleSheet } from 'react-native';
4 |
5 | const ArrowLeft = (props: any) => (
6 |
22 | );
23 |
24 | export default ArrowLeft;
25 |
--------------------------------------------------------------------------------
/example/src/components/RoundButton.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, TouchableOpacity } from 'react-native';
3 |
4 | type Props = {
5 | icon: JSX.Element;
6 | onPress: () => void;
7 | };
8 | export const RoundButton = ({ icon, onPress }: Props) => {
9 | return (
10 |
11 | {icon}
12 |
13 | );
14 | };
15 | const styles = StyleSheet.create({
16 | container: {
17 | backgroundColor: 'white',
18 | width: 30,
19 | height: 30,
20 | borderRadius: 15,
21 | alignItems: 'center',
22 | justifyContent: 'center',
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: PR check
2 | on: [pull_request]
3 |
4 | concurrency:
5 | group: ${{ github.workflow }}-${{ github.ref }}
6 | cancel-in-progress: true
7 |
8 | jobs:
9 | Validate:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v3
14 |
15 | - name: Setup
16 | uses: ./.github/actions/setup
17 |
18 | - name: Lint files
19 | run: yarn lint
20 |
21 | - name: Typecheck files
22 | run: yarn typecheck
23 |
24 | - name: Run unit tests
25 | run: yarn test --maxWorkers=2 --coverage
26 |
27 | - name: Build package
28 | run: yarn prepack
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/hooks/useAnimateNavbar.ts:
--------------------------------------------------------------------------------
1 | import type { Animated } from 'react-native';
2 |
3 | export const useAnimateNavbar = (
4 | scroll: Animated.Value,
5 | imageHeight: number,
6 | headerHeight: number
7 | ) => {
8 | const HEADER_HEIGHT_DIFFERENCE = imageHeight - headerHeight;
9 | const headerOpacity = scroll.interpolate({
10 | inputRange: [0, HEADER_HEIGHT_DIFFERENCE * 0.75, HEADER_HEIGHT_DIFFERENCE],
11 | outputRange: [0, 0, 1],
12 | extrapolate: 'clamp',
13 | });
14 | const overflowHeaderOpacity = scroll.interpolate({
15 | inputRange: [0, HEADER_HEIGHT_DIFFERENCE * 0.75, HEADER_HEIGHT_DIFFERENCE],
16 | outputRange: [1, 1, 0],
17 | extrapolate: 'clamp',
18 | });
19 |
20 | return [headerOpacity, overflowHeaderOpacity];
21 | };
22 |
--------------------------------------------------------------------------------
/example/src/icons/ArrowRight.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet } from 'react-native';
3 | import type { SvgProps } from 'react-native-svg';
4 | import Svg, { Path } from 'react-native-svg';
5 |
6 | export const ArrowRight = ({
7 | color = '#000000',
8 | style,
9 | ...props
10 | }: SvgProps) => (
11 |
24 | );
25 |
--------------------------------------------------------------------------------
/example/src/screens/OnlyForegroundExample.tsx:
--------------------------------------------------------------------------------
1 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
2 | import { Card, TopNavBar, HeaderNavBar } from '../components';
3 | import * as React from 'react';
4 | import { HeaderComponent } from '../components/HeaderComponent';
5 | import { data, isIOS } from '../utils';
6 |
7 | export const OnlyForegroundExample = () => {
8 | return (
9 | }
12 | topBarHeight={isIOS ? 90 : 70}
13 | HeaderNavbarComponent={}
14 | TopNavBarComponent={}
15 | >
16 | {data.map((e) => {
17 | return ;
18 | })}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/example/src/components/Card.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native';
2 | import * as React from 'react';
3 |
4 | type Props = {
5 | item: any;
6 | };
7 | export const Card = ({ item }: Props) => (
8 |
9 | Value {item}
10 |
11 | );
12 |
13 | const styles = StyleSheet.create({
14 | card: {
15 | flexDirection: 'row',
16 | alignItems: 'center',
17 | shadowColor: '#402583',
18 | backgroundColor: '#ffffff',
19 | shadowOffset: {
20 | width: 0,
21 | height: 0,
22 | },
23 | shadowOpacity: 0.1,
24 | shadowRadius: 6,
25 | elevation: 1,
26 | borderRadius: 10,
27 | marginHorizontal: 12,
28 | marginTop: 12,
29 | paddingHorizontal: 16,
30 | paddingVertical: 12,
31 | },
32 | });
33 |
--------------------------------------------------------------------------------
/.github/actions/setup/action.yml:
--------------------------------------------------------------------------------
1 | name: Setup
2 | description: Setup Node.js and install dependencies
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Setup Node.js
8 | uses: actions/setup-node@v3
9 | with:
10 | node-version-file: .nvmrc
11 |
12 | - name: Cache dependencies
13 | id: yarn-cache
14 | uses: actions/cache@v3
15 | with:
16 | path: |
17 | **/node_modules
18 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
19 | restore-keys: |
20 | ${{ runner.os }}-yarn-
21 |
22 | - name: Install dependencies
23 | if: steps.yarn-cache.outputs.cache-hit != 'true'
24 | run: |
25 | yarn install --cwd example --frozen-lockfile
26 | yarn install --frozen-lockfile
27 | shell: bash
28 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "example",
4 | "slug": "example",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "userInterfaceStyle": "light",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "updates": {
15 | "fallbackToCacheTimeout": 0
16 | },
17 | "assetBundlePatterns": [
18 | "**/*"
19 | ],
20 | "ios": {
21 | "supportsTablet": true
22 | },
23 | "android": {
24 | "adaptiveIcon": {
25 | "foregroundImage": "./assets/adaptive-icon.png",
26 | "backgroundColor": "#FFFFFF"
27 | }
28 | },
29 | "web": {
30 | "favicon": "./assets/favicon.png"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/example/src/screens/ImageForegroundExample.tsx:
--------------------------------------------------------------------------------
1 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
2 | import { Card, TopNavBar, HeaderNavBar } from '../components';
3 | import * as React from 'react';
4 | import { HeaderComponent } from '../components/HeaderComponent';
5 | import { data, isIOS } from '../utils';
6 |
7 | export const ImageForegroundExample = () => {
8 | return (
9 | }
11 | topBarHeight={isIOS ? 90 : 70}
12 | HeaderNavbarComponent={}
13 | TopNavBarComponent={}
14 | headerImage={require('../../assets/cabin.jpg')}
15 | >
16 | {data.map((e) => {
17 | return ;
18 | })}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ main, develop ]
6 | pull_request:
7 | branches: [ main, develop ]
8 |
9 | jobs:
10 | CodeQL-Build:
11 | name: Analyze
12 | runs-on: ubuntu-latest
13 | permissions:
14 | security-events: write
15 |
16 | strategy:
17 | fail-fast: false
18 | matrix:
19 | language: [ 'javascript' ]
20 |
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@v3
24 |
25 | - name: Initialize CodeQL
26 | uses: github/codeql-action/init@v2
27 | with:
28 | languages: ${{ matrix.language }}
29 |
30 | - name: Perform CodeQL Analysis
31 | uses: github/codeql-action/analyze@v2
32 | with:
33 | category: "/language:${{matrix.language}}"
34 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 | To get started with the project make sure that you already installed node v16. If you use nvm then you can
3 | run:
4 | ```sh
5 | nvm use
6 | ```
7 |
8 | Run `yarn` in the root directory to install the required dependencies for each package:
9 |
10 | ```sh
11 | yarn
12 | ```
13 |
14 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development.
15 |
16 | To start the packager:
17 |
18 | ```sh
19 | yarn example start
20 | ```
21 |
22 | To run the example app on Android:
23 |
24 | ```sh
25 | yarn example android
26 | ```
27 |
28 | To run the example app on iOS:
29 |
30 | ```sh
31 | yarn example ios
32 | ```
33 |
34 | To run the example app on Web:
35 |
36 | ```sh
37 | yarn example web
38 | ```
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@kanelloc/react-native-animated-header-scroll-view": ["./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 | "noUncheckedIndexedAccess": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "resolveJsonModule": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "target": "esnext"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/scripts/bootstrap.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 | const path = require('path');
3 | const child_process = require('child_process');
4 |
5 | const root = path.resolve(__dirname, '..');
6 | const args = process.argv.slice(2);
7 | const options = {
8 | cwd: process.cwd(),
9 | env: process.env,
10 | stdio: 'inherit',
11 | encoding: 'utf-8',
12 | };
13 |
14 | if (os.type() === 'Windows_NT') {
15 | options.shell = true;
16 | }
17 |
18 | let result;
19 |
20 | if (process.cwd() !== root || args.length) {
21 | // We're not in the root of the project, or additional arguments were passed
22 | // In this case, forward the command to `yarn`
23 | result = child_process.spawnSync('yarn', args, options);
24 | } else {
25 | // If `yarn` is run without arguments, perform bootstrap
26 | result = child_process.spawnSync('yarn', ['bootstrap'], options);
27 | }
28 |
29 | process.exitCode = result.status;
30 |
--------------------------------------------------------------------------------
/example/src/screens/HeaderNavBarExample.tsx:
--------------------------------------------------------------------------------
1 | import { Card, HeaderNavBar, TopNavBar } from '../components';
2 | import * as React from 'react';
3 | import { useRef } from 'react';
4 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
5 | import { data, isIOS } from '../utils';
6 | import type { ScrollView } from 'react-native';
7 |
8 | export const HeaderNavBarExample = () => {
9 | const scrollRef = useRef(null);
10 |
11 | return (
12 | }
17 | TopNavBarComponent={}
18 | headerImage={require('../../assets/cabin.jpg')}
19 | >
20 | {data.map((e) => {
21 | return ;
22 | })}
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/example/src/icons/Share.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type { SvgProps } from 'react-native-svg';
3 | import Svg, { Path } from 'react-native-svg';
4 |
5 | export const Share = (props: SvgProps) => (
6 |
15 | );
16 |
--------------------------------------------------------------------------------
/example/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const createExpoWebpackConfigAsync = require('@expo/webpack-config');
3 | const { resolver } = require('./metro.config');
4 |
5 | const root = path.resolve(__dirname, '..');
6 | const node_modules = path.join(__dirname, 'node_modules');
7 |
8 | module.exports = async function (env, argv) {
9 | const config = await createExpoWebpackConfigAsync(env, argv);
10 |
11 | config.module.rules.push({
12 | test: /\.(js|jsx|ts|tsx)$/,
13 | include: path.resolve(root, 'src'),
14 | use: 'babel-loader',
15 | });
16 |
17 | // We need to make sure that only one version is loaded for peerDependencies
18 | // So we alias them to the versions in example's node_modules
19 | Object.assign(config.resolve.alias, {
20 | ...resolver.extraNodeModules,
21 | 'react-native-web': path.join(node_modules, 'react-native-web'),
22 | });
23 |
24 | return config;
25 | };
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # XDE
6 | .expo/
7 |
8 | # VSCode
9 | .vscode/
10 | jsconfig.json
11 |
12 | # Xcode
13 | #
14 | build/
15 | *.pbxuser
16 | !default.pbxuser
17 | *.mode1v3
18 | !default.mode1v3
19 | *.mode2v3
20 | !default.mode2v3
21 | *.perspectivev3
22 | !default.perspectivev3
23 | xcuserdata
24 | *.xccheckout
25 | *.moved-aside
26 | DerivedData
27 | *.hmap
28 | *.ipa
29 | *.xcuserstate
30 | project.xcworkspace
31 |
32 | # Android/IJ
33 | #
34 | .classpath
35 | .cxx
36 | .gradle
37 | .idea
38 | .project
39 | .settings
40 | local.properties
41 | android.iml
42 |
43 | # Cocoapods
44 | #
45 | example/ios/Pods
46 |
47 | # Ruby
48 | example/vendor/
49 |
50 | # node.js
51 | #
52 | node_modules/
53 | npm-debug.log
54 | yarn-debug.log
55 | yarn-error.log
56 |
57 | # BUCK
58 | buck-out/
59 | \.buckd/
60 | android/app/libs
61 | android/keystores/debug.keystore
62 |
63 | # Expo
64 | .expo/
65 |
66 | # Turborepo
67 | .turbo/
68 |
69 | # generated by bob
70 | lib/
71 |
--------------------------------------------------------------------------------
/example/src/screens/SafeAreaViewExample.tsx:
--------------------------------------------------------------------------------
1 | import { Card, TopNavBar, HeaderNavBar } from '../components';
2 | import * as React from 'react';
3 | import { SafeAreaView } from 'react-native-safe-area-context';
4 | import { StyleSheet } from 'react-native';
5 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
6 | import { data } from '../utils';
7 |
8 | export const SafeAreaViewExample = () => {
9 | return (
10 |
11 | }
13 | TopNavBarComponent={}
14 | headerImage={require('../../assets/cabin.jpg')}
15 | >
16 | {data.map((e) => {
17 | return ;
18 | })}
19 |
20 |
21 | );
22 | };
23 |
24 | const styles = StyleSheet.create({
25 | container: {
26 | flex: 1,
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "main": "node_modules/expo/AppEntry.js",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web"
10 | },
11 | "dependencies": {
12 | "@react-native-community/hooks": "^3.0.0",
13 | "@react-navigation/native": "^6.1.1",
14 | "@react-navigation/native-stack": "^6.9.7",
15 | "expo": "~47.0.9",
16 | "expo-status-bar": "~1.4.2",
17 | "react": "18.1.0",
18 | "react-dom": "18.1.0",
19 | "react-native": "0.70.5",
20 | "react-native-safe-area-context": "4.4.1",
21 | "react-native-screens": "~3.18.0",
22 | "react-native-svg": "13.4.0",
23 | "react-native-web": "~0.18.9"
24 | },
25 | "devDependencies": {
26 | "@babel/core": "^7.12.9",
27 | "@expo/webpack-config": "^0.17.2",
28 | "babel-loader": "^8.1.0",
29 | "babel-plugin-module-resolver": "^4.1.0"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Babis Kanellopoulos
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Please include a summary of the change and which issue is fixed
4 |
5 |
6 |
7 | ## Type of change
8 |
9 |
10 |
11 | - [ ] Bug fix (non-breaking change which fixes an issue)
12 | - [ ] New feature (non-breaking change which adds functionality)
13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
14 | - [ ] This change requires a documentation update
15 |
16 | ## Checklist:
17 |
18 | - [ ] My code follows the style guidelines of this project
19 | - [ ] I have performed a self-review of my own code
20 | - [ ] I have commented my code, particularly in hard-to-understand areas
21 | - [ ] I have made corresponding changes to the documentation
22 | - [ ] My changes generate no new warnings
23 | - [ ] I have added tests that prove my fix is effective or that my feature works
24 | - [ ] New and existing unit tests pass locally with my changes
25 | - [ ] Any dependent changes have been merged and published in downstream modules
26 | - [ ] I have checked my code and corrected any misspellings
27 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const escape = require('escape-string-regexp');
3 | const { getDefaultConfig } = require('@expo/metro-config');
4 | const exclusionList = require('metro-config/src/defaults/exclusionList');
5 | const pak = require('../package.json');
6 |
7 | const root = path.resolve(__dirname, '..');
8 |
9 | const modules = Object.keys({
10 | ...pak.peerDependencies,
11 | });
12 |
13 | const defaultConfig = getDefaultConfig(__dirname);
14 |
15 | module.exports = {
16 | ...defaultConfig,
17 |
18 | projectRoot: __dirname,
19 | watchFolders: [root],
20 |
21 | // We need to make sure that only one version is loaded for peerDependencies
22 | // So we block them at the root, and alias them to the versions in example's node_modules
23 | resolver: {
24 | ...defaultConfig.resolver,
25 |
26 | blacklistRE: exclusionList(
27 | modules.map(
28 | (m) =>
29 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
30 | )
31 | ),
32 |
33 | extraNodeModules: modules.reduce((acc, name) => {
34 | acc[name] = path.join(__dirname, 'node_modules', name);
35 | return acc;
36 | }, {}),
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/src/hooks/useAnimateScrollView.ts:
--------------------------------------------------------------------------------
1 | import { useRef } from 'react';
2 | import { Animated } from 'react-native';
3 |
4 | export const useAnimateScrollView = (
5 | imageHeight: number,
6 | disableScale?: boolean
7 | ) => {
8 | const scroll = useRef(new Animated.Value(0)).current;
9 |
10 | const scale = scroll.interpolate({
11 | inputRange: [-imageHeight, 0, imageHeight],
12 | outputRange: [2.5, 1, 0.85],
13 | extrapolate: 'clamp',
14 | });
15 |
16 | const translateYDown = scroll.interpolate({
17 | inputRange: [-imageHeight, 0, imageHeight],
18 | outputRange: [-imageHeight * 0.6, 0, imageHeight * 0.5],
19 | extrapolate: 'clamp',
20 | });
21 |
22 | const translateYUp = scroll.interpolate({
23 | inputRange: [-imageHeight, 0, imageHeight],
24 | outputRange: [imageHeight * 0.3, 0, 0],
25 | extrapolate: 'clamp',
26 | });
27 |
28 | const onScroll = Animated.event(
29 | [{ nativeEvent: { contentOffset: { y: scroll } } }],
30 | { useNativeDriver: true }
31 | );
32 |
33 | return [
34 | scroll,
35 | onScroll,
36 | disableScale ? 1 : scale,
37 | disableScale ? 0 : translateYDown,
38 | disableScale ? 0 : translateYUp,
39 | ] as const;
40 | };
41 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - main
6 | jobs:
7 | build_and_deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v3
12 | with:
13 | fetch-depth: 0
14 |
15 | - name: git config
16 | if: ${{ (startsWith(github.event.head_commit.message, 'feat')) || (startsWith(github.event.head_commit.message, 'fix')) }}
17 | run: |
18 | git config user.name "kanelloc"
19 | git config user.email "kanelloc@users.noreply.github.com"
20 |
21 | - run: >
22 | echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
23 |
24 | - name: Setup
25 | uses: ./.github/actions/setup
26 |
27 | - name: Lint files
28 | run: yarn lint
29 |
30 | - name: Typecheck files
31 | run: yarn typecheck
32 |
33 | - name: Run unit tests
34 | run: yarn test --maxWorkers=2 --coverage
35 |
36 | - name: Build package
37 | run: yarn prepack
38 |
39 | - name: NPM release
40 | if: ${{ (startsWith(github.event.head_commit.message, 'feat')) || (startsWith(github.event.head_commit.message, 'fix')) }}
41 | run: yarn release-ci
42 | env:
43 | GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }}
44 |
45 |
--------------------------------------------------------------------------------
/example/src/components/HeaderNavBar.tsx:
--------------------------------------------------------------------------------
1 | import { RoundButton } from './RoundButton';
2 | import { StatusBar, StyleSheet, View } from 'react-native';
3 | import * as React from 'react';
4 | import ArrowLeft from '../icons/ArrowLeft';
5 | import { ArrowRight } from '../icons/ArrowRight';
6 | import { Share } from '../icons/Share';
7 | import { useNavigation } from '@react-navigation/native';
8 | import { isIOS } from '../utils';
9 |
10 | export const HeaderNavBar = () => {
11 | const nav = useNavigation();
12 | return (
13 |
14 |
19 | } onPress={nav.goBack} />
20 |
21 |
22 | } onPress={() => null} />
23 |
24 | } onPress={() => null} />
25 |
26 |
27 | );
28 | };
29 |
30 | const styles = StyleSheet.create({
31 | container: {
32 | width: '100%',
33 | paddingHorizontal: 8,
34 | paddingTop: 32,
35 | flexDirection: 'row',
36 | justifyContent: 'space-between',
37 | },
38 | btnRightContainer: {
39 | flexDirection: 'row',
40 | alignItems: 'center',
41 | },
42 | btnRight: {
43 | marginRight: 8,
44 | },
45 | });
46 |
--------------------------------------------------------------------------------
/example/src/components/TopNavBar.tsx:
--------------------------------------------------------------------------------
1 | import { RoundButton } from './RoundButton';
2 | import { StyleSheet, Text, useWindowDimensions, View } from 'react-native';
3 | import * as React from 'react';
4 | import ArrowLeft from '../icons/ArrowLeft';
5 | import { useNavigation } from '@react-navigation/native';
6 |
7 | export const TopNavBar = () => {
8 | const { width } = useWindowDimensions();
9 | const nav = useNavigation();
10 | return (
11 |
12 |
13 | } onPress={nav.goBack} />
14 |
15 |
23 | Header
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | const styles = StyleSheet.create({
31 | container: {
32 | width: '100%',
33 | height: '100%',
34 | alignItems: 'center',
35 | flexDirection: 'row',
36 | justifyContent: 'space-between',
37 | paddingTop: 32,
38 | borderBottomColor: '#a4a4a4',
39 | borderBottomWidth: StyleSheet.hairlineWidth,
40 | backgroundColor: 'tomato',
41 | },
42 | leftContainer: {
43 | paddingLeft: 8,
44 | },
45 | titleContainer: {
46 | alignItems: 'center',
47 | justifyContent: 'center',
48 | },
49 | title: {
50 | fontWeight: 'bold',
51 | },
52 | });
53 |
--------------------------------------------------------------------------------
/example/src/screens/HeaderNavbarFlatListExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useRef } from 'react';
3 | import { FlatList, RefreshControl, StyleSheet, View } from 'react-native';
4 | import { AnimatedFlatList } from '@kanelloc/react-native-animated-header-scroll-view';
5 | import { data } from '../utils';
6 | import { Card, HeaderNavBar, TopNavBar } from '../components';
7 | import { useRefresh } from '@react-native-community/hooks';
8 |
9 | const fetch = () => {
10 | return new Promise((resolve) => setTimeout(resolve, 5000));
11 | };
12 | export const HeaderNavbarFlatListExample = () => {
13 | const { isRefreshing, onRefresh } = useRefresh(fetch);
14 | const scrollRef = useRef(null);
15 | const renderItem = ({ item }: any) => {
16 | return (
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | return (
24 |
25 |
35 | }
36 | headerImage={require('../../assets/cabin.jpg')}
37 | data={data}
38 | renderItem={renderItem}
39 | HeaderNavbarComponent={}
40 | TopNavBarComponent={}
41 | />
42 |
43 | );
44 | };
45 |
46 | const styles = StyleSheet.create({
47 | refresh: {
48 | zIndex: 10,
49 | },
50 | });
51 |
--------------------------------------------------------------------------------
/example/src/screens/RefreshControlExample.tsx:
--------------------------------------------------------------------------------
1 | import { Card, TopNavBar, HeaderNavBar } from '../components';
2 | import * as React from 'react';
3 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
4 | import { data, isIOS } from '../utils';
5 | import { RefreshControl, StyleSheet } from 'react-native';
6 | import { SafeAreaView } from 'react-native-safe-area-context';
7 | import { useRefresh } from '@react-native-community/hooks';
8 |
9 | const fetch = () => {
10 | return new Promise((resolve) => setTimeout(resolve, 5000));
11 | };
12 |
13 | export const RefreshControlExample = () => {
14 | const { isRefreshing, onRefresh } = useRefresh(fetch);
15 |
16 | return (
17 |
18 |
27 | }
28 | headerMaxHeight={400}
29 | topBarHeight={isIOS ? 90 : 70}
30 | HeaderNavbarComponent={}
31 | TopNavBarComponent={}
32 | headerImage={require('../../assets/cabin.jpg')}
33 | >
34 | {data.map((e) => {
35 | return ;
36 | })}
37 |
38 |
39 | );
40 | };
41 |
42 | const styles = StyleSheet.create({
43 | container: {
44 | flex: 1,
45 | },
46 | refresh: {
47 | zIndex: 10,
48 | },
49 | });
50 |
--------------------------------------------------------------------------------
/example/src/screens/ExamplesDirectory.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
2 | import React from 'react';
3 | import type { NativeStackScreenProps } from '@react-navigation/native-stack';
4 | import type { RootStackParamList } from '../types';
5 | import { SCREENS } from '../utils/enums';
6 |
7 | type Props = NativeStackScreenProps;
8 | export const ExamplesDirectory = ({ navigation }: Props) => {
9 | const goTo = (screen: SCREENS) => {
10 | navigation.navigate(screen);
11 | };
12 |
13 | const examples = [
14 | { screen: SCREENS.HEADER_NAVBAR_EXAMPLE },
15 | { screen: SCREENS.SAFE_AREA_VIEW_EXAMPLE },
16 | { screen: SCREENS.IMAGE_FOREGROUND_EXAMPLE },
17 | { screen: SCREENS.ONLY_FOREGROUND_EXAMPLE },
18 | { screen: SCREENS.REFRESH_CONTROL_EXAMPLE },
19 | { screen: SCREENS.HEADER_NAVBAR_FLATLIST_EXAMPLE },
20 | ];
21 |
22 | return (
23 |
24 | {examples.map((e) => {
25 | return (
26 | goTo(e.screen)}
29 | style={styles.button}
30 | >
31 | {e.screen}
32 |
33 | );
34 | })}
35 |
36 | );
37 | };
38 |
39 | const styles = StyleSheet.create({
40 | container: {
41 | flex: 1,
42 | alignItems: 'center',
43 | justifyContent: 'center',
44 | },
45 | button: {
46 | marginTop: 8,
47 | padding: 16,
48 | borderWidth: 1,
49 | borderRadius: 24,
50 | width: 240,
51 | alignItems: 'center',
52 | justifyContent: 'center',
53 | },
54 | });
55 |
--------------------------------------------------------------------------------
/src/components/AnimatedNavbar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, Animated } from 'react-native';
3 | import { useAnimateNavbar } from '../hooks/useAnimateNavbar';
4 | import type { AnimatedNavbarProps } from '../types';
5 |
6 | const AnimatedNavbar = ({
7 | scroll,
8 | imageHeight,
9 | OverflowHeaderComponent,
10 | TopNavbarComponent,
11 | headerHeight,
12 | headerElevation,
13 | }: AnimatedNavbarProps) => {
14 | const [headerOpacity, overflowHeaderOpacity] = useAnimateNavbar(
15 | scroll,
16 | imageHeight,
17 | headerHeight
18 | );
19 |
20 | return (
21 | <>
22 |
33 | {TopNavbarComponent}
34 |
35 |
46 | {OverflowHeaderComponent}
47 |
48 | >
49 | );
50 | };
51 |
52 | const styles = StyleSheet.create({
53 | container: {
54 | position: 'absolute',
55 | top: 0,
56 | width: '100%',
57 | backgroundColor: 'white',
58 | alignItems: 'center',
59 | justifyContent: 'center',
60 | },
61 | overflowHeader: {
62 | backgroundColor: 'transparent',
63 | },
64 | });
65 |
66 | export default AnimatedNavbar;
67 |
--------------------------------------------------------------------------------
/src/components/AnimatedFlatList.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | import { Animated, FlatList } from 'react-native';
3 | import type { AnimatedFlatListViewProps } from '../types';
4 | import AnimatedNavbar from './AnimatedNavbar';
5 | import { HEADER_HEIGHT, IMG_HEADER_HEIGHT } from '../constants';
6 | import { useAnimateScrollView } from '../hooks/useAnimateScrollView';
7 | import { AnimatedHeader } from './AnimatedHeader';
8 |
9 | export const AnimatedFlatList = forwardRef(
10 | (
11 | {
12 | headerMaxHeight,
13 | topBarHeight,
14 | topBarElevation,
15 | disableScale,
16 | TopNavBarComponent,
17 | HeaderNavbarComponent,
18 | headerImage,
19 | imageStyle,
20 | HeaderComponent,
21 | ...props
22 | }: AnimatedFlatListViewProps,
23 | ref
24 | ) => {
25 | const imageHeight = headerMaxHeight || IMG_HEADER_HEIGHT;
26 | const headerNavHeight = topBarHeight || HEADER_HEIGHT;
27 | const headerElevation = topBarElevation || 0;
28 | const [scroll, onScroll, scale, translateYDown, translateYUp] =
29 | useAnimateScrollView(imageHeight, disableScale);
30 |
31 | return (
32 | <>
33 |
47 | }
48 | />
49 |
57 | >
58 | );
59 | }
60 | );
61 |
--------------------------------------------------------------------------------
/src/components/AnimatedScrollView.tsx:
--------------------------------------------------------------------------------
1 | import { Animated, ScrollView } from 'react-native';
2 | import React, { forwardRef } from 'react';
3 | import { HEADER_HEIGHT, IMG_HEADER_HEIGHT } from '../constants';
4 | import AnimatedNavbar from './AnimatedNavbar';
5 | import type { AnimatedScrollViewProps } from '../types';
6 | import { useAnimateScrollView } from '../hooks/useAnimateScrollView';
7 | import { AnimatedHeader } from './AnimatedHeader';
8 |
9 | export const AnimatedScrollView = forwardRef<
10 | ScrollView,
11 | AnimatedScrollViewProps
12 | >(
13 | (
14 | {
15 | TopNavBarComponent,
16 | HeaderNavbarComponent,
17 | HeaderComponent,
18 | headerMaxHeight,
19 | topBarHeight,
20 | topBarElevation,
21 | headerImage,
22 | disableScale,
23 | children,
24 | imageStyle,
25 | ...props
26 | }: AnimatedScrollViewProps,
27 | ref
28 | ) => {
29 | const imageHeight = headerMaxHeight || IMG_HEADER_HEIGHT;
30 | const headerNavHeight = topBarHeight || HEADER_HEIGHT;
31 | const headerElevation = topBarElevation || 0;
32 | const [scroll, onScroll, scale, translateYDown, translateYUp] =
33 | useAnimateScrollView(imageHeight, disableScale);
34 |
35 | return (
36 | <>
37 |
43 |
52 | {children}
53 |
54 |
62 | >
63 | );
64 | }
65 | );
66 |
--------------------------------------------------------------------------------
/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { NavigationContainer } from '@react-navigation/native';
3 | import { createNativeStackNavigator } from '@react-navigation/native-stack';
4 | import { HeaderNavBarExample } from './screens/HeaderNavBarExample';
5 | import { ExamplesDirectory } from './screens/ExamplesDirectory';
6 | import { SafeAreaViewExample } from './screens/SafeAreaViewExample';
7 | import { SafeAreaProvider } from 'react-native-safe-area-context';
8 | import type { RootStackParamList } from './types';
9 | import { ImageForegroundExample } from './screens/ImageForegroundExample';
10 | import { OnlyForegroundExample } from './screens/OnlyForegroundExample';
11 | import { RefreshControlExample } from './screens/RefreshControlExample';
12 | import { HeaderNavbarFlatListExample } from './screens/HeaderNavbarFlatListExample';
13 |
14 | const App = () => {
15 | const Stack = createNativeStackNavigator();
16 |
17 | return (
18 |
19 |
20 |
21 |
25 |
29 |
33 |
37 |
41 |
45 |
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default App;
56 |
--------------------------------------------------------------------------------
/src/types.d.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | FlatListProps,
3 | ImageStyle,
4 | ScrollViewProps,
5 | StyleProp,
6 | } from 'react-native';
7 | import { Animated, ImageSourcePropType } from 'react-native';
8 |
9 | type AnimatedViewProps = {
10 | /**
11 | * Rendered on top of the screen as a navbar when scrolling to the top
12 | */
13 | TopNavBarComponent: JSX.Element;
14 |
15 | /**
16 | * A component to use on top of header image. It can also be used
17 | * without header image to render a custom component as header.
18 | */
19 | HeaderComponent?: JSX.Element;
20 |
21 | /**
22 | * Rendered on top of the header. Transitions to TopNavbarComponent as you scroll
23 | */
24 | HeaderNavbarComponent?: JSX.Element;
25 |
26 | /**
27 | * Height of the header (headerImage or HeaderComponent). Default value is 300
28 | */
29 | headerMaxHeight?: number;
30 |
31 | /**
32 | * Height of the top navbar. Default value is 90
33 | */
34 | topBarHeight?: number;
35 |
36 | /**
37 | * [ANDROID ONLY] Elevation of the top navbar. Default value is 0
38 | */
39 | topBarElevation?: number;
40 |
41 | /**
42 | * @see https://reactnative.dev/docs/image#source
43 | */
44 | headerImage?: ImageSourcePropType;
45 |
46 | /**
47 | * Disables header scaling when scrolling
48 | */
49 | disableScale?: boolean;
50 |
51 | /**
52 | * Image styles
53 | */
54 | imageStyle?: StyleProp;
55 | };
56 |
57 | export type AnimatedScrollViewProps = AnimatedViewProps & ScrollViewProps;
58 |
59 | export type AnimatedFlatListViewProps = AnimatedViewProps & FlatListProps;
60 |
61 | export type AnimatedNavbarProps = {
62 | scroll: Animated.Value;
63 | OverflowHeaderComponent?: JSX.Element;
64 | TopNavbarComponent?: JSX.Element;
65 | imageHeight: number;
66 | headerHeight: number;
67 | headerElevation: number;
68 | };
69 |
70 | export type AnimatedHeaderProps = {
71 | imageHeight: number;
72 | translateYUp: Animated.AnimatedInterpolation | 0;
73 | translateYDown: Animated.AnimatedInterpolation | 0;
74 | scale: Animated.AnimatedInterpolation | 1;
75 | imageStyle?: StyleProp;
76 | HeaderComponent?: JSX.Element;
77 | headerImage?: ImageSourcePropType;
78 | };
79 |
--------------------------------------------------------------------------------
/src/components/AnimatedHeader.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Animated,
3 | ImageBackground,
4 | StyleSheet,
5 | useWindowDimensions,
6 | View,
7 | } from 'react-native';
8 | import React from 'react';
9 | import type { AnimatedHeaderProps } from '../types';
10 |
11 | export const AnimatedHeader = ({
12 | HeaderComponent,
13 | headerImage,
14 | imageHeight,
15 | translateYUp,
16 | translateYDown,
17 | scale,
18 | imageStyle,
19 | }: AnimatedHeaderProps) => {
20 | const { width } = useWindowDimensions();
21 | const AnimatedImageBackground =
22 | Animated.createAnimatedComponent(ImageBackground);
23 | return (
24 |
33 | {HeaderComponent ? (
34 | <>
35 | {headerImage ? (
36 |
50 | {HeaderComponent}
51 |
52 | ) : (
53 |
65 | {HeaderComponent}
66 |
67 | )}
68 | >
69 | ) : (
70 |
84 | )}
85 |
86 | );
87 | };
88 |
89 | const styles = StyleSheet.create({
90 | imgContainer: {
91 | alignItems: 'center',
92 | overflow: 'hidden',
93 | },
94 | });
95 |
--------------------------------------------------------------------------------
/src/__tests__/useAnimateNavbar.test.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks';
2 | import { useAnimateNavbar } from '../hooks/useAnimateNavbar';
3 | import { HEADER_HEIGHT, IMG_HEADER_HEIGHT } from '../constants';
4 | import { Animated } from 'react-native';
5 | import { useRef } from 'react';
6 |
7 | describe('useAnimatedNavbar basic tests', () => {
8 | it('should return starting points', () => {
9 | const { result } = renderHook(() => {
10 | const first = (IMG_HEADER_HEIGHT - HEADER_HEIGHT) * 0.75; // 157,5
11 | const scroll = useRef(new Animated.Value(first)).current;
12 | return useAnimateNavbar(scroll, IMG_HEADER_HEIGHT, HEADER_HEIGHT);
13 | });
14 |
15 | const [headerOpacity, overflowHeaderOpacity] = result.current;
16 |
17 | expect(JSON.stringify(headerOpacity)).toBe('0');
18 | expect(JSON.stringify(overflowHeaderOpacity)).toBe('1');
19 | });
20 |
21 | it('should return ending points', () => {
22 | const { result } = renderHook(() => {
23 | const first = IMG_HEADER_HEIGHT - HEADER_HEIGHT; // 210
24 | const scroll = useRef(new Animated.Value(first)).current;
25 | return useAnimateNavbar(scroll, IMG_HEADER_HEIGHT, HEADER_HEIGHT);
26 | });
27 |
28 | const [headerOpacity, overflowHeaderOpacity] = result.current;
29 |
30 | expect(JSON.stringify(headerOpacity)).toBe('1');
31 | expect(JSON.stringify(overflowHeaderOpacity)).toBe('0');
32 | });
33 |
34 | it('should return 50% of interpolation', () => {
35 | const { result } = renderHook(() => {
36 | const start = (IMG_HEADER_HEIGHT - HEADER_HEIGHT) * 0.75; // 157,5
37 | const end = IMG_HEADER_HEIGHT - HEADER_HEIGHT; // 210
38 | const diff = (end - start) / 2;
39 |
40 | const scroll = useRef(new Animated.Value(end - diff)).current;
41 | return useAnimateNavbar(scroll, IMG_HEADER_HEIGHT, HEADER_HEIGHT);
42 | });
43 |
44 | const [headerOpacity, overflowHeaderOpacity] = result.current;
45 |
46 | expect(JSON.stringify(headerOpacity)).toBe('0.5');
47 | expect(JSON.stringify(overflowHeaderOpacity)).toBe('0.5');
48 | });
49 |
50 | it('should return 80% of interpolation', () => {
51 | const { result } = renderHook(() => {
52 | const start = (IMG_HEADER_HEIGHT - HEADER_HEIGHT) * 0.75; // 157,5
53 | const end = IMG_HEADER_HEIGHT - HEADER_HEIGHT; // 210
54 | const diff = (end - start) * 0.8;
55 |
56 | const scroll = useRef(new Animated.Value(end - diff)).current;
57 | return useAnimateNavbar(scroll, IMG_HEADER_HEIGHT, HEADER_HEIGHT);
58 | });
59 |
60 | const [headerOpacity, overflowHeaderOpacity] = result.current;
61 |
62 | expect(JSON.stringify(headerOpacity)).toBe('0.2');
63 | expect(JSON.stringify(overflowHeaderOpacity)).toBe('0.8');
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | # [1.0.0](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.12.0...v1.0.0) (2023-09-02)
4 |
5 |
6 | * feat!: make navbar opts more robust (#62) ([cbe08ec](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/cbe08ec924ece38c4f830081b11f09d12fac3d6d)), closes [#62](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/62)
7 |
8 |
9 | ### BREAKING CHANGES
10 |
11 | * Default paddingTop, borderBottomWidth & borderBottomColor have moved from the wrapper header component to the component provided from the user/dev
12 |
13 | # [0.12.0](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.11.1...v0.12.0) (2023-03-04)
14 |
15 |
16 | ### Features
17 |
18 | * Enable ref forwarding ([#47](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/47)) ([581c87f](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/581c87f62711ffbc90e177d8c4404eedbeb26fd7))
19 |
20 | ## [0.11.1](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.11.0...v0.11.1) (2023-02-05)
21 |
22 |
23 | ### Bug Fixes
24 |
25 | * bypass translations when disableScale is enabled ([#35](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/35)) ([53066d6](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/53066d6a8961c6c8b99eca95f3015bc00e671626))
26 |
27 | # [0.11.0](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.10.4...v0.11.0) (2023-02-05)
28 |
29 |
30 | ### Features
31 |
32 | * New AnimatedFlatList component ([#34](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/34)) ([92a02bd](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/92a02bd045e50221e1095d55d358a307e1905d26))
33 |
34 | ### Chore
35 | * Bump deps ([#31](https://github.com/kanelloc/react-native-animated-header-scroll-view/pull/31))
36 | * Trigger release only for feats and fixes ([#32](https://github.com/kanelloc/react-native-animated-header-scroll-view/pull/32))
37 |
38 | ### Docs
39 | * Update contribution readme ([#33](https://github.com/kanelloc/react-native-animated-header-scroll-view/pull/33))
40 |
41 | # [0.10.0](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.9.4...v0.10.0) (2023-02-02)
42 |
43 |
44 | ### Features
45 |
46 | * add image style prop ([#25](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/25)) ([01682b7](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/01682b7eca81e350c2a7cd5e586e9a44b06e87b6))
47 |
48 | # [0.9.3](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.9.2...v0.9.3) (2023-01-29)
49 |
50 |
51 | ### Bug Fixes
52 |
53 | * override status bar ([#19](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/19)) ([3570cab](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/3570cab1ccf3330ed30a8d326fa003f25f33b146))
54 |
55 | # [0.9.0](https://github.com/kanelloc/react-native-animated-header-scroll-view/compare/v0.8.7...v0.9.0) (2023-01-07)
56 |
57 |
58 | ### Features
59 |
60 | * add new refresh control example ([#6](https://github.com/kanelloc/react-native-animated-header-scroll-view/issues/6)) ([b700e0c](https://github.com/kanelloc/react-native-animated-header-scroll-view/commit/b700e0c068fb18ab128a93dc0387287e3d88e17f))
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are always welcome, no matter how large or small!
4 |
5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md).
6 |
7 | ## Development workflow
8 | Project includes a `.nvmrc` file. If you use nvm just run
9 | ```shell
10 | nvm use
11 | ```
12 |
13 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package:
14 |
15 | ```sh
16 | yarn
17 | ```
18 |
19 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development.
20 |
21 | While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app.
22 |
23 | To start the packager:
24 |
25 | ```sh
26 | yarn example start
27 | ```
28 |
29 | To run the example app on Android:
30 |
31 | ```sh
32 | yarn example android
33 | ```
34 |
35 | To run the example app on iOS:
36 |
37 | ```sh
38 | yarn example ios
39 | ```
40 |
41 | To run the example app on Web:
42 |
43 | ```sh
44 | yarn example web
45 | ```
46 |
47 | Make sure your code passes TypeScript and ESLint. Run the following to verify:
48 |
49 | ```sh
50 | yarn typecheck
51 | yarn lint
52 | ```
53 |
54 | To fix formatting errors, run the following:
55 |
56 | ```sh
57 | yarn lint --fix
58 | ```
59 |
60 | Remember to add tests for your change if possible. Run the unit tests by:
61 |
62 | ```sh
63 | yarn test
64 | ```
65 |
66 |
67 | ### Commit message convention
68 |
69 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:
70 |
71 | - `fix`: bug fixes, e.g. fix crash due to deprecated method.
72 | - `feat`: new features, e.g. add new method to the module.
73 | - `refactor`: code refactor, e.g. migrate from class components to hooks.
74 | - `docs`: changes into documentation, e.g. add usage example for the module..
75 | - `test`: adding or updating tests, e.g. add integration tests using detox.
76 | - `chore`: tooling changes, e.g. change CI config.
77 |
78 | Our pre-commit hooks verify that your commit message matches this format when committing.
79 |
80 | ### Linting and tests
81 |
82 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/)
83 |
84 | We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing.
85 |
86 | Our pre-commit hooks verify that the linter and tests pass when committing.
87 |
88 | ### Scripts
89 |
90 | The `package.json` file contains various scripts for common tasks:
91 |
92 | - `yarn bootstrap`: setup project by installing all dependencies and pods.
93 | - `yarn typecheck`: type-check files with TypeScript.
94 | - `yarn lint`: lint files with ESLint.
95 | - `yarn test`: run unit tests with Jest.
96 | - `yarn example start`: start the Metro server for the example app.
97 | - `yarn example android`: run the example app on Android.
98 | - `yarn example ios`: run the example app on iOS.
99 |
100 | ### Sending a pull request
101 |
102 | > **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).
103 |
104 | When you're sending a pull request:
105 |
106 | - Prefer small pull requests focused on one change.
107 | - Verify that linters and tests are passing.
108 | - Review the documentation to make sure it looks good.
109 | - Follow the pull request template when opening a pull request.
110 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue.
111 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@kanelloc/react-native-animated-header-scroll-view",
3 | "version": "1.0.0",
4 | "description": "React native animated header scroll view component",
5 | "main": "lib/commonjs/index",
6 | "module": "lib/module/index",
7 | "types": "lib/typescript/index.d.ts",
8 | "react-native": "src/index",
9 | "source": "src/index",
10 | "files": [
11 | "src",
12 | "lib",
13 | "android",
14 | "ios",
15 | "cpp",
16 | "*.podspec",
17 | "!lib/typescript/example",
18 | "!ios/build",
19 | "!android/build",
20 | "!android/gradle",
21 | "!android/gradlew",
22 | "!android/gradlew.bat",
23 | "!android/local.properties",
24 | "!**/__tests__",
25 | "!**/__fixtures__",
26 | "!**/__mocks__",
27 | "!**/.*"
28 | ],
29 | "scripts": {
30 | "test": "jest",
31 | "typecheck": "tsc --noEmit",
32 | "lint": "eslint \"**/*.{js,ts,tsx}\"",
33 | "prepack": "bob build",
34 | "release": "release-it",
35 | "release-ci": "release-it --ci",
36 | "example": "yarn --cwd example",
37 | "bootstrap": "yarn example && yarn install"
38 | },
39 | "keywords": [
40 | "react-native",
41 | "ios",
42 | "android"
43 | ],
44 | "repository": "https://github.com/kanelloc/react-native-animated-header-scroll-view",
45 | "author": "Babis Kanellopoulos (https://github.com/kanelloc)",
46 | "license": "MIT",
47 | "bugs": {
48 | "url": "https://github.com/kanelloc/react-native-animated-header-scroll-view/issues"
49 | },
50 | "homepage": "https://github.com/kanelloc/react-native-animated-header-scroll-view#readme",
51 | "publishConfig": {
52 | "access": "public",
53 | "registry": "https://registry.npmjs.org/"
54 | },
55 | "devDependencies": {
56 | "@commitlint/config-conventional": "^17.0.2",
57 | "@evilmartians/lefthook": "^1.2.2",
58 | "@react-native-community/eslint-config": "^3.0.2",
59 | "@release-it/conventional-changelog": "^5.0.0",
60 | "@testing-library/react-hooks": "^8.0.1",
61 | "@types/jest": "^29.4.0",
62 | "@types/react": "~17.0.21",
63 | "@types/react-native": "0.70.0",
64 | "commitlint": "^17.0.2",
65 | "del-cli": "^5.0.0",
66 | "eslint": "^8.4.1",
67 | "eslint-config-prettier": "^9.0.0",
68 | "eslint-plugin-prettier": "^5.0.0",
69 | "eslint-plugin-react-native": "^4.0.0",
70 | "jest": "^29.4.1",
71 | "pod-install": "^0.1.0",
72 | "prettier": "^3.0.3",
73 | "react": "18.1.0",
74 | "react-native": "0.70.5",
75 | "react-native-builder-bob": "^0.20.0",
76 | "react-test-renderer": "^18.2.0",
77 | "release-it": "^15.0.0",
78 | "typescript": "^4.5.2"
79 | },
80 | "resolutions": {
81 | "@types/react": "17.0.21"
82 | },
83 | "peerDependencies": {
84 | "react": "*",
85 | "react-native": "*"
86 | },
87 | "engines": {
88 | "node": ">= 16.0.0"
89 | },
90 | "jest": {
91 | "preset": "react-native",
92 | "modulePathIgnorePatterns": [
93 | "/example/node_modules",
94 | "/lib/"
95 | ]
96 | },
97 | "commitlint": {
98 | "extends": [
99 | "@commitlint/config-conventional"
100 | ]
101 | },
102 | "release-it": {
103 | "git": {
104 | "commitMessage": "chore: release ${version}",
105 | "tagName": "v${version}"
106 | },
107 | "npm": {
108 | "publish": true
109 | },
110 | "github": {
111 | "release": true
112 | },
113 | "plugins": {
114 | "@release-it/conventional-changelog": {
115 | "infile": "CHANGELOG.md",
116 | "header": "# Changelog",
117 | "preset": {
118 | "name": "angular",
119 | "types": [
120 | {
121 | "type": "feat",
122 | "section": "Features"
123 | },
124 | {
125 | "type": "fix",
126 | "section": "Bug Fixes"
127 | }
128 | ]
129 | }
130 | }
131 | }
132 | },
133 | "eslintConfig": {
134 | "root": true,
135 | "extends": [
136 | "@react-native-community",
137 | "prettier"
138 | ],
139 | "plugins": [
140 | "react-native"
141 | ],
142 | "rules": {
143 | "react-native/no-unused-styles": 2,
144 | "react-native/no-inline-styles": 2,
145 | "prettier/prettier": [
146 | "error",
147 | {
148 | "quoteProps": "consistent",
149 | "singleQuote": true,
150 | "tabWidth": 2,
151 | "trailingComma": "es5",
152 | "useTabs": false
153 | }
154 | ]
155 | }
156 | },
157 | "eslintIgnore": [
158 | "node_modules/",
159 | "lib/"
160 | ],
161 | "prettier": {
162 | "quoteProps": "consistent",
163 | "singleQuote": true,
164 | "tabWidth": 2,
165 | "trailingComma": "es5",
166 | "useTabs": false
167 | },
168 | "react-native-builder-bob": {
169 | "source": "src",
170 | "output": "lib",
171 | "targets": [
172 | "commonjs",
173 | "module",
174 | [
175 | "typescript",
176 | {
177 | "project": "tsconfig.build.json"
178 | }
179 | ]
180 | ]
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Animated Header ScrollView
2 |
3 | [![NPM version][npm-image]][npm-url] [![npm][npm-downloads]][npm-url] [![npm][license-url]][npm-url] [![npm][types-url]][npm-url] [![runs with expo][expo-image]][expo-url]
4 |
5 | Performant animated scroll view components that:
6 | * 🔥Support `FlatList` and `ScrollView` scrolling interactions.
7 | * 🔥Animate an image or a custom component into a navbar header
8 | * 🔥Support bounce animation on scroll down
9 | * 🔥Support both iOS and Android devices
10 |
11 | 
12 |
13 |
14 | # Installation
15 | ```sh
16 | $ npm install @kanelloc/react-native-animated-header-scroll-view
17 | ```
18 |
19 | # Usage
20 | ```typescript
21 | import { Card, TopNavBar, HeaderNavBar } from '../components';
22 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
23 | import * as React from 'react';
24 |
25 | export const App = () => {
26 | const data = Array.from(Array(20).keys());
27 | return (
28 | }
30 | TopNavBarComponent={}
31 | headerImage={require('../../assets/cabin.jpg')}
32 | >
33 | {data.map((e) => {
34 | return ;
35 | })}
36 |
37 | );
38 | };
39 | ```
40 |
41 | ```typescript
42 | import { Card, TopNavBar, HeaderNavBar } from '../components';
43 | import { AnimatedScrollView } from '@kanelloc/react-native-animated-header-scroll-view';
44 | import * as React from 'react';
45 |
46 | export const App = () => {
47 | const data = Array.from(Array(20).keys());
48 | const renderItem = ({ item }: any) => {
49 | return (
50 |
51 |
52 |
53 | );
54 | };
55 |
56 | return (
57 | }
62 | TopNavBarComponent={}
63 | />
64 | );
65 | };
66 | ```
67 |
68 | You can find a set of detailed examples [here](https://github.com/kanelloc/react-native-animated-header-scroll-view/tree/main/example)
69 |
70 | Also a running snack [here](https://snack.expo.dev/ukGomwbdE)
71 |
72 | # Props
73 |
74 | | Prop name | Description | Type | Required |
75 | |-------------------------|-----------------------------------------------------------------------------------------------------------------------------|-----------------------|----------|
76 | | `TopNavBarComponent` | Rendered on top of the screen as a navbar when scrolling to the top | JSX.Element | true |
77 | | `HeaderComponent` | A component to use on top of header image. It can also be used without header image to render a custom component as header. | JSX.Element | false |
78 | | `HeaderNavbarComponent` | Rendered on top of the header. Transitions to TopNavbarComponent as you scroll | JSX.Element | false |
79 | | `headerMaxHeight` | Height of the header (headerImage or HeaderComponent). Default value is 300 | number | false |
80 | | `topBarHeight` | Height of the top navbar. Default value is 90 | number | false |
81 | | `topBarElevation` | [ANDROID ONLY] Elevation of the top navbar. Default value is 0 | number | false |
82 | | `headerImage` | Image header source | ImageSourcePropType | false |
83 | | `disableScale` | Disables header scaling when scrolling. Default value is false | boolean | false |
84 | | `imageStyle` | Image styles | StyleProp | false |
85 |
86 |
87 |
88 | # Contributing
89 |
90 | See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
91 |
92 | # License
93 |
94 | MIT
95 |
96 | [npm-url]: https://www.npmjs.com/package/@kanelloc/react-native-animated-header-scroll-view
97 | [npm-image]: https://img.shields.io/npm/v/@kanelloc/react-native-animated-header-scroll-view?style=flat-square
98 | [license-url]: https://img.shields.io/npm/l/@kanelloc/react-native-animated-header-scroll-view?style=flat-square
99 | [types-url]: https://img.shields.io/badge/types-included-blue?style=flat-square
100 | [expo-image]: https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000
101 | [expo-url]: https://expo.io
102 | [npm-downloads]: https://img.shields.io/npm/dm/@kanelloc/react-native-animated-header-scroll-view?style=flat-square
103 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributor Covenant Code of Conduct
3 |
4 | ## Our Pledge
5 |
6 | We as members, contributors, and leaders pledge to make participation in our
7 | community a harassment-free experience for everyone, regardless of age, body
8 | size, visible or invisible disability, ethnicity, sex characteristics, gender
9 | identity and expression, level of experience, education, socio-economic status,
10 | nationality, personal appearance, race, caste, color, religion, or sexual
11 | identity and orientation.
12 |
13 | We pledge to act and interact in ways that contribute to an open, welcoming,
14 | diverse, inclusive, and healthy community.
15 |
16 | ## Our Standards
17 |
18 | Examples of behavior that contributes to a positive environment for our
19 | community include:
20 |
21 | * Demonstrating empathy and kindness toward other people
22 | * Being respectful of differing opinions, viewpoints, and experiences
23 | * Giving and gracefully accepting constructive feedback
24 | * Accepting responsibility and apologizing to those affected by our mistakes,
25 | and learning from the experience
26 | * Focusing on what is best not just for us as individuals, but for the overall
27 | community
28 |
29 | Examples of unacceptable behavior include:
30 |
31 | * The use of sexualized language or imagery, and sexual attention or advances of
32 | any kind
33 | * Trolling, insulting or derogatory comments, and personal or political attacks
34 | * Public or private harassment
35 | * Publishing others' private information, such as a physical or email address,
36 | without their explicit permission
37 | * Other conduct which could reasonably be considered inappropriate in a
38 | professional setting
39 |
40 | ## Enforcement Responsibilities
41 |
42 | Community leaders are responsible for clarifying and enforcing our standards of
43 | acceptable behavior and will take appropriate and fair corrective action in
44 | response to any behavior that they deem inappropriate, threatening, offensive,
45 | or harmful.
46 |
47 | Community leaders have the right and responsibility to remove, edit, or reject
48 | comments, commits, code, wiki edits, issues, and other contributions that are
49 | not aligned to this Code of Conduct, and will communicate reasons for moderation
50 | decisions when appropriate.
51 |
52 | ## Scope
53 |
54 | This Code of Conduct applies within all community spaces, and also applies when
55 | an individual is officially representing the community in public spaces.
56 | Examples of representing our community include using an official e-mail address,
57 | posting via an official social media account, or acting as an appointed
58 | representative at an online or offline event.
59 |
60 | ## Enforcement
61 |
62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
63 | reported to the community leaders responsible for enforcement at
64 | [INSERT CONTACT METHOD].
65 | All complaints will be reviewed and investigated promptly and fairly.
66 |
67 | All community leaders are obligated to respect the privacy and security of the
68 | reporter of any incident.
69 |
70 | ## Enforcement Guidelines
71 |
72 | Community leaders will follow these Community Impact Guidelines in determining
73 | the consequences for any action they deem in violation of this Code of Conduct:
74 |
75 | ### 1. Correction
76 |
77 | **Community Impact**: Use of inappropriate language or other behavior deemed
78 | unprofessional or unwelcome in the community.
79 |
80 | **Consequence**: A private, written warning from community leaders, providing
81 | clarity around the nature of the violation and an explanation of why the
82 | behavior was inappropriate. A public apology may be requested.
83 |
84 | ### 2. Warning
85 |
86 | **Community Impact**: A violation through a single incident or series of
87 | actions.
88 |
89 | **Consequence**: A warning with consequences for continued behavior. No
90 | interaction with the people involved, including unsolicited interaction with
91 | those enforcing the Code of Conduct, for a specified period of time. This
92 | includes avoiding interactions in community spaces as well as external channels
93 | like social media. Violating these terms may lead to a temporary or permanent
94 | ban.
95 |
96 | ### 3. Temporary Ban
97 |
98 | **Community Impact**: A serious violation of community standards, including
99 | sustained inappropriate behavior.
100 |
101 | **Consequence**: A temporary ban from any sort of interaction or public
102 | communication with the community for a specified period of time. No public or
103 | private interaction with the people involved, including unsolicited interaction
104 | with those enforcing the Code of Conduct, is allowed during this period.
105 | Violating these terms may lead to a permanent ban.
106 |
107 | ### 4. Permanent Ban
108 |
109 | **Community Impact**: Demonstrating a pattern of violation of community
110 | standards, including sustained inappropriate behavior, harassment of an
111 | individual, or aggression toward or disparagement of classes of individuals.
112 |
113 | **Consequence**: A permanent ban from any sort of public interaction within the
114 | community.
115 |
116 | ## Attribution
117 |
118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119 | version 2.1, available at
120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
121 |
122 | Community Impact Guidelines were inspired by
123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124 |
125 | For answers to common questions about this code of conduct, see the FAQ at
126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
127 | [https://www.contributor-covenant.org/translations][translations].
128 |
129 | [homepage]: https://www.contributor-covenant.org
130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
131 | [Mozilla CoC]: https://github.com/mozilla/diversity
132 | [FAQ]: https://www.contributor-covenant.org/faq
133 | [translations]: https://www.contributor-covenant.org/translations
134 |
--------------------------------------------------------------------------------