├── examples ├── .watchmanconfig ├── .gitignore ├── app.json ├── types.js ├── .babelrc ├── screens │ ├── index.js │ ├── no-tabs.js │ ├── home.js │ └── tabbed.js ├── App.js ├── components │ ├── index.js │ ├── items-scroll-view.js │ ├── items-flat-list.js │ └── items-custom-list.js ├── data.js ├── index.js ├── style.js ├── package.json ├── .flowconfig └── README.md ├── .gitignore ├── src ├── tabbedHeader │ ├── index.js │ ├── tab-scrollable.js │ ├── tab.js │ ├── tab-not-scrollable.js │ ├── tabs.js │ └── header.js ├── utils │ ├── ViewPropTypes.js │ ├── helpers.js │ └── icon.js ├── types.js ├── list.js ├── view.js ├── style.js ├── index.js ├── helpers.test.js ├── collapsible.js ├── header.js ├── scrollable.js └── helpers.js ├── .babelrc ├── .idea ├── misc.xml ├── vcs.xml ├── preferred-vcs.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml ├── collapsible-tab-header.iml └── workspace.xml ├── .travis.yml ├── .eslintrc.js ├── package.json ├── .flowconfig └── README.md /examples/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | -------------------------------------------------------------------------------- /examples/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "sdkVersion": "21.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type dataType ={ 3 | id: string | number, 4 | title: string, 5 | subtitle: string, 6 | } 7 | -------------------------------------------------------------------------------- /examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["babel-preset-expo"], 3 | "env": { 4 | "development": { 5 | "plugins": ["transform-react-jsx-source"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/tabbedHeader/index.js: -------------------------------------------------------------------------------- 1 | import Tabs from './tabs'; 2 | import Tab from './tab'; 3 | import TabHeader from './header'; 4 | 5 | export { 6 | Tabs, 7 | Tab, 8 | TabHeader, 9 | }; 10 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["babel-preset-expo"], 3 | "env": { 4 | "development": { 5 | "plugins": [ 6 | "transform-react-jsx-source" 7 | ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/ViewPropTypes.js: -------------------------------------------------------------------------------- 1 | import { View, ViewPropTypes as RNViewPropTypes } from 'react-native'; 2 | 3 | const ViewPropTypes = RNViewPropTypes || View.propTypes; 4 | 5 | export default ViewPropTypes; 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/screens/index.js: -------------------------------------------------------------------------------- 1 | import TabbedView from './tabbed'; 2 | import NotTabbed from './no-tabs'; 3 | import Home from './home'; 4 | 5 | export { 6 | TabbedView, 7 | NotTabbed, 8 | Home, 9 | }; 10 | -------------------------------------------------------------------------------- /.idea/preferred-vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ApexVCS 5 | 6 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export interface Iicon{ 3 | name: string, 4 | type: string 5 | } 6 | 7 | export interface Iroute{ 8 | key: ?string, 9 | title: ?string, 10 | icon: ?Iicon, 11 | } 12 | -------------------------------------------------------------------------------- /src/list.js: -------------------------------------------------------------------------------- 1 | import { Animated, FlatList } from 'react-native'; 2 | import createScrollable from './scrollable'; 3 | 4 | const AnimatedList = Animated.createAnimatedComponent(FlatList); 5 | export default createScrollable(AnimatedList); 6 | -------------------------------------------------------------------------------- /src/view.js: -------------------------------------------------------------------------------- 1 | import { Animated, ScrollView } from 'react-native'; 2 | import createScrollable from './scrollable'; 3 | 4 | const AnimatedList = Animated.createAnimatedComponent(ScrollView); 5 | export default createScrollable(AnimatedList); 6 | -------------------------------------------------------------------------------- /examples/App.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import AppNavigation from './index'; 4 | 5 | 6 | export default class App extends Component { 7 | render() { 8 | return ( 9 | 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/components/index.js: -------------------------------------------------------------------------------- 1 | import ItemsFlatList from './items-flat-list'; 2 | import ItemsScrollView from './items-scroll-view'; 3 | import ItemsCustomList from './items-custom-list'; 4 | 5 | export { 6 | ItemsCustomList, 7 | ItemsFlatList, 8 | ItemsScrollView, 9 | }; 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/style.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const ABSOLUTE = 'absolute'; 3 | const CENTER = 'center'; 4 | export default { 5 | header: (height: number) => ({ 6 | position: ABSOLUTE, 7 | zIndex: 3, 8 | top: 0, 9 | left: 0, 10 | right: 0, 11 | height, 12 | justifyContent: CENTER, 13 | }), 14 | }; 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - ~/.npm 5 | notifications: 6 | email: false 7 | node_js: 8 | - '9' 9 | - '8' 10 | - '6' 11 | script: 12 | - npm run test 13 | after_success: 14 | - npm run semantic-release 15 | branches: 16 | except: 17 | - /^v\d+\.\d+\.\d+$/ 18 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/data.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { range } from 'lodash'; 3 | 4 | let data = []; 5 | 6 | export default function (count: number) { 7 | if (!data.length) { 8 | console.log('here we are') 9 | data = range(1, count).map(number => ({ 10 | id: `id_${number}`, 11 | title: `title-${number}`, 12 | subTitle: `subtitle-${number}`, 13 | })); 14 | } 15 | return data; 16 | } 17 | -------------------------------------------------------------------------------- /src/tabbedHeader/tab-scrollable.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { onlyUpdateForKeys, defaultProps, compose } from 'recompose'; 4 | 5 | type Type={ 6 | children: any 7 | } 8 | 9 | const Component = ({ children }: Type) => ( 10 | React.Children.only(children) 11 | ); 12 | 13 | export default compose( 14 | defaultProps({ hasScrollable: true }), 15 | onlyUpdateForKeys(['hasScrollable']), 16 | )(Component); 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Header from './header'; 2 | import Collapsible from './collapsible'; 3 | import FlatList from './list'; 4 | import ScrollView from './view'; 5 | import Scrollable from './scrollable'; 6 | import Tabs from './tabbedHeader/tabs'; 7 | import Tab from './tabbedHeader/tab'; 8 | import TabHeader from './tabbedHeader/header'; 9 | 10 | export { 11 | Header, 12 | Collapsible, 13 | FlatList, 14 | ScrollView, 15 | Scrollable, 16 | TabHeader, 17 | Tab, 18 | Tabs, 19 | }; 20 | -------------------------------------------------------------------------------- /.idea/collapsible-tab-header.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | import { Router, Scene } from 'react-native-router-flux'; 2 | import React from 'react'; 3 | import { NotTabbed, TabbedView, Home } from './screens/index'; 4 | 5 | const Component = () => ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | 15 | 16 | export default Component; 17 | -------------------------------------------------------------------------------- /src/helpers.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { getHeight } from './helpers'; 3 | import chai from 'chai'; 4 | 5 | const should = chai.should(); 6 | 7 | test('helpers.getHeight - when given percent string returns ratio of number', (t) => { 8 | getHeight('50%', 250).should.eql(125); 9 | }); 10 | 11 | test('helpers.getHeight - percent string without base returns percent as number', (t) => { 12 | getHeight('50%').should.eql(50); 13 | }); 14 | 15 | test('helpers.getHeight - number returns number', (t) => { 16 | getHeight(500).should.eql(500); 17 | }); 18 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": [ 3 | "airbnb", 4 | "plugin:flowtype/recommended" 5 | ], 6 | "plugins": [ 7 | "react", 8 | "jsx-a11y", 9 | "import", 10 | "react-native", 11 | "flowtype" 12 | ], 13 | "rules": { 14 | "no-underscore-dangle": "off", 15 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 16 | "react/prefer-stateless-function":0, 17 | "react/require-default-props":0, 18 | "react/prefer-default-export":0, 19 | "no-param-reassign":0, 20 | "no-unused-expressions":0, 21 | } 22 | }; -------------------------------------------------------------------------------- /examples/style.js: -------------------------------------------------------------------------------- 1 | import { Constants } from 'expo'; 2 | 3 | const CENTER = 'center'; 4 | export default { 5 | tabs: { 6 | backgroundColor: '#22E0D1', 7 | paddingTop: 5, 8 | borderWidth: 0, 9 | borderTopWidth: 0, 10 | borderLeftWidth: 0, 11 | borderRightWidth: 0, 12 | borderBottomColor: 'rgba(0,0,0,0.05)', 13 | }, 14 | tab: { padding: 2 }, 15 | label: { fontSize: 10 }, 16 | container: { flex: 1}, 17 | 18 | 19 | homeContainer: { 20 | flex: 1, 21 | alignItems: CENTER, 22 | justifyContent: CENTER, 23 | paddingTop: Constants.statusBarHeight, 24 | backgroundColor: '#ecf0f1', 25 | }, 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/tabbedHeader/tab.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { Animated, View } from 'react-native'; 4 | import PropTypes from 'prop-types'; 5 | import { setDisplayName, compose, 6 | defaultProps, onlyUpdateForKeys } from 'recompose'; 7 | import Tab from './tab-not-scrollable'; 8 | import ScrollableTab from './tab-scrollable'; 9 | 10 | const DISPLAY_NAME = 'CollapsibleTabItem'; 11 | 12 | const Component = ({ children, hasScrollable }) => ( 13 | 14 | (hasScrollable) ? 15 | 16 | {children} 17 | : 18 | 19 | {children} 20 | 21 | 22 | ) 23 | 24 | ; 25 | 26 | export default compose( 27 | setDisplayName(DISPLAY_NAME), 28 | defaultProps({ hasScrollable: true }), 29 | )(Component); 30 | -------------------------------------------------------------------------------- /examples/components/items-scroll-view.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { defaultProps } from 'recompose'; 4 | import { ListItem, List } from 'react-native-elements'; 5 | import { ScrollView } from 'react-native-collapsible-tab-header'; 6 | import createData from '../data'; 7 | import type { dataType } from '../types'; 8 | 9 | const Component = ({ data }: {data: Array}) => ( 10 | 11 | 12 | {data.map(item => ( 13 | 18 | ))} 19 | 20 | 21 | ); 22 | 23 | Component.propTypes = {}; 24 | Component.defaultProps = {}; 25 | 26 | export default defaultProps({ 27 | data: createData(25), 28 | })(Component); 29 | -------------------------------------------------------------------------------- /examples/screens/no-tabs.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { View, Text } from 'react-native'; 4 | import { compose, defaultProps } from 'recompose'; 5 | import { Collapsible, Header } from 'react-native-collapsible-tab-header'; 6 | import { ItemsCustomList } from '../components/index'; 7 | import styles from '../style'; 8 | 9 | 10 | const Component = ({ style }: {style: Object}) => ( 11 | 12 | 13 |
14 | 15 | This is a header content 16 | 17 |
18 | 19 |
20 |
21 | ); 22 | 23 | export default compose( 24 | defaultProps({ style: styles }), 25 | )(Component); 26 | 27 | -------------------------------------------------------------------------------- /examples/components/items-flat-list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { defaultProps } from 'recompose'; 4 | import { ListItem, List } from 'react-native-elements'; 5 | import { FlatList } from 'react-native-collapsible-tab-header'; 6 | import createData from '../data'; 7 | import type { dataType } from '../types'; 8 | 9 | const Component = ({ data }: {data: Array}) => ( 10 | 11 | item.id} 14 | renderItem={({ item }: {item: dataType}) => ( 15 | 19 | )} 20 | /> 21 | 22 | ); 23 | 24 | Component.propTypes = {}; 25 | Component.defaultProps = {}; 26 | 27 | export default defaultProps({ 28 | data: createData(25), 29 | })(Component); 30 | -------------------------------------------------------------------------------- /src/collapsible.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import { compose, withProps, withContext, 5 | defaultProps, toClass } from 'recompose'; 6 | import { View } from 'react-native'; 7 | import { getDefaultValues, getWithProps } from './helpers'; 8 | 9 | const Component = ({ children, style }: any) => ( 10 | 11 | {children} 12 | ); 13 | /* eslint react/forbid-prop-types:0 */ 14 | Component.propTypes = { 15 | hasNavBar: PropTypes.bool, 16 | offsetFromTop: PropTypes.number, 17 | children: PropTypes.any, 18 | style: PropTypes.object, 19 | height: PropTypes.oneOfType([ 20 | PropTypes.string, 21 | PropTypes.number], 22 | ), 23 | }; 24 | 25 | export default compose( 26 | defaultProps(getDefaultValues()), 27 | withProps(getWithProps), 28 | withContext({ 29 | collapsibleProps: PropTypes.object, 30 | }, props => ({ collapsibleProps: { ...props } })), 31 | )(Component); 32 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "jest-expo": "^21.0.2", 7 | "react-native-scripts": "1.5.0", 8 | "react-test-renderer": "16.0.0-alpha.12" 9 | }, 10 | "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js", 11 | "scripts": { 12 | "start": "react-native-scripts start", 13 | "eject": "react-native-scripts eject", 14 | "android": "react-native-scripts android", 15 | "ios": "react-native-scripts ios", 16 | "test": "node node_modules/jest/bin/jest.js --watch" 17 | }, 18 | "jest": { 19 | "preset": "jest-expo" 20 | }, 21 | "dependencies": { 22 | "expo": "^21.0.0", 23 | "lodash": "^4.17.4", 24 | "react": "16.0.0-alpha.12", 25 | "react-native": "^0.48.4", 26 | "react-native-collapsible-tab-header": "^1.1.6", 27 | "react-native-elements": "^0.17.0", 28 | "react-native-router-flux": "^4.0.0-beta.21", 29 | "recompose": "^0.25.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/components/items-custom-list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { ScrollView, Animated } from 'react-native'; 4 | import { defaultProps } from 'recompose'; 5 | import { ListItem, List } from 'react-native-elements'; 6 | import { Scrollable } from 'react-native-collapsible-tab-header'; 7 | import createData from '../data'; 8 | import type { dataType } from '../types'; 9 | 10 | const AnimatedScrollable = Animated.createAnimatedComponent(ScrollView); 11 | const MyCustomScrollView = Scrollable(AnimatedScrollable); 12 | 13 | const Component = ({ data }: {data: Array}) => ( 14 | 15 | 16 | {data.map(item => ( 17 | 22 | ))} 23 | 24 | 25 | ); 26 | 27 | Component.propTypes = {}; 28 | Component.defaultProps = {}; 29 | 30 | export default defaultProps({ 31 | data: createData(25), 32 | })(Component); 33 | -------------------------------------------------------------------------------- /examples/screens/home.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { Actions } from 'react-native-router-flux'; 4 | import { View } from 'react-native'; 5 | import { defaultProps } from 'recompose'; 6 | import { Button } from 'react-native-elements'; 7 | import styles from '../style'; 8 | 9 | const Component = ({ style }: {style: Object}) => ( 10 | 11 |