-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
927 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# react-native-collapsible-tab-view | ||
|
||
[![Build Status][build-badge]][build] | ||
[![Version][version-badge]][package] | ||
[![MIT License][license-badge]][license] | ||
[![runs with expo][expo-badge]][expo] | ||
|
||
> Due to time constraints we weren't able to finish the documentation yet. You can navigate through the code and examples. | ||
- [Expo app](#expo-app) | ||
- [Demo](#demo) | ||
- [Features](#features) | ||
- [Installation](#installation) | ||
- [Quick Start](#quick-start) | ||
- [Guides](#guides) | ||
- [Scroll on header](#scroll-on-header) | ||
- [API reference](#api-reference) | ||
- [createCollapsibleTabs](#createcollapsibletabs) | ||
- [Tabs.Container](#tabscontainer) | ||
- [Tabs.Lazy](#tabslazy) | ||
- [Tabs.FlatList](#tabsflatlist) | ||
- [Tabs.ScrollView](#tabsscrollview) | ||
- [useTabsContext](#usetabscontext) | ||
- [useCollapsibleStyle](#usecollapsiblestyle) | ||
- [useTabNameContext](#usetabnamecontext) | ||
- [Default Tab Bar](#default-tab-bar) | ||
- [MaterialTabBar](#materialtabbar) | ||
- [MaterialTabItem](#materialtabitem) | ||
- [Contributing](#contributing) | ||
- [Documentation changes](#documentation-changes) | ||
|
||
# Expo app | ||
|
||
> If you are looking for the integration with [react-native-tab-view](https://github.com/satya164/react-native-tab-view) and/or [react-navigation](https://github.com/react-navigation/react-navigation), you need to use the [v2](https://github.com/PedroBern/react-native-collapsible-tab-view/tree/v2), we are currenlty on v3. | ||
Collapsible Tab View for React Native, with [Reanimated](https://github.com/software-mansion/react-native-reanimated). | ||
|
||
- [View it with Expo](https://expo.io/@pedrobern/react-native-collapsible-tab-view-demos). | ||
- Checkout the [examples](https://github.com/PedroBern/react-native-collapsible-tab-view/tree/main/example) for the source code of the Expo app. | ||
|
||
<a href="https://expo.io/@pedrobern/react-native-collapsible-tab-view-demos"><img src="https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=exp://exp.host/@pedrobern/react-native-collapsible-tab-view-demos" height="200px" width="200px"></a> | ||
|
||
**Credits** | ||
|
||
The [react-native-tab-view](https://github.com/satya164/react-native-tab-view) example app was used as template for the demos. | ||
|
||
# Demo | ||
|
||
| Default | Snap | DiffClamp | DiffClamp + Snap | | ||
| :--------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | | ||
| <img src="https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/default.gif" width="360"> | <img src="https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/snap.gif" width="360"> | <img src="https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/diffClamp.gif" width="360"> | <img src="https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/diffClamp_snap.gif" width="360"> | | ||
|
||
<!-- todo --> | ||
|
||
# Features | ||
|
||
- Animations and interactions on the UI thread | ||
- Highly customizable | ||
- Fully typed with [TypeScript](https://typescriptlang.org) | ||
- Lazy support with fade-in animation | ||
- DiffClamp header | ||
- Interpolated header | ||
- Scroll snap (with interpolated header) | ||
- Animated snap (with diffClamp header) | ||
- Scrollable tabs, inspired by the [react-native-tab-view](https://github.com/satya164/react-native-tab-view) tab bar | ||
- Support horizontal and vertical window | ||
|
||
# Installation | ||
|
||
Open a Terminal in the project root and run: | ||
|
||
```sh | ||
yarn add react-native-collapsible-tab-view | ||
``` | ||
|
||
Then, add Reanimated v2, [follow the official installation guide](https://docs.swmansion.com/react-native-reanimated/docs/next/installation). | ||
|
||
# Quick Start | ||
|
||
```tsx | ||
$QUICK_START_CODE | ||
``` | ||
|
||
# Guides | ||
|
||
## Scroll on header | ||
|
||
If you want to allow scrolling from the header: | ||
|
||
- If the `HeaderComponent` **doesn't** contain touchables set `pointerEvents='none'` | ||
- If `HeaderComponent` **does** contain touchables set `pointerEvents='box-none'` for them to work. | ||
|
||
_Note: With this setting any child component that should **not** respond to touches (e.g. `<Image />`) needs to have `pointerEvents` set to `'none'`. Otherwise it can become the target of a touch gesture on iOS devices and thereby preventing scrolling._ | ||
|
||
# API reference | ||
|
||
$CORE_API | ||
|
||
$CORE_COMPONENTS_API | ||
|
||
## Default Tab Bar | ||
|
||
$TAB_BAR_API | ||
|
||
# Contributing | ||
|
||
While developing, you can run the [example app](/example/README.md) to test your changes. | ||
|
||
Please follow the [angular commit message format](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format). | ||
|
||
Make sure your code passes TypeScript and ESLint. Run the following to verify: | ||
|
||
```sh | ||
yarn typescript | ||
yarn lint | ||
``` | ||
|
||
To fix formatting errors, run the following: | ||
|
||
```sh | ||
yarn lint -- --fix | ||
``` | ||
|
||
Remember to add tests for your change if possible. | ||
|
||
## Documentation changes | ||
|
||
Edit the [README_TEMPLATE](https://github.com/PedroBern/react-native-collapsible-tab-view/tree/main/documentation/README_TEMPLATE.md), or update the docstrings inside the `src` folder, and run: | ||
|
||
```sh | ||
yarn docs | ||
``` | ||
|
||
<!-- badges --> | ||
|
||
[build-badge]: https://img.shields.io/circleci/build/github/PedroBern/react-native-collapsible-tab-view/main.svg?style=flat-square | ||
[build]: https://app.circleci.com/pipelines/github/PedroBern/react-native-collapsible-tab-view | ||
[version-badge]: https://img.shields.io/npm/v/react-native-collapsible-tab-view.svg?style=flat-square | ||
[package]: https://www.npmjs.com/package/react-native-collapsible-tab-view | ||
[license-badge]: https://img.shields.io/npm/l/react-native-collapsible-tab-view.svg?style=flat-square | ||
[license]: https://opensource.org/licenses/MIT | ||
[expo-badge]: https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000 | ||
[expo]: https://github.com/expo/expo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/** | ||
* nasty script to build a funky docs. | ||
*/ | ||
|
||
const fs = require('fs') | ||
const path = require('path') | ||
|
||
const getCoreAPI = require('./getCoreAPI') | ||
const getCoreComponentsAPI = require('./getCoreComponentsAPI') | ||
const getQuickStartCode = require('./getQuickStartCode') | ||
const getTabBarAPI = require('./getTabBarAPI') | ||
|
||
const TEMPLATE = path.join(__dirname, 'README_TEMPLATE.md') | ||
const README = path.join(__dirname, '..', 'README.md') | ||
|
||
fs.copyFileSync(TEMPLATE, README) | ||
let data = fs.readFileSync(README, 'utf-8') | ||
|
||
const coreAPI = getCoreAPI() | ||
const coreComponentsAPI = getCoreComponentsAPI() | ||
const tabBarAPI = getTabBarAPI() | ||
const quickStartCode = getQuickStartCode() | ||
|
||
data = data.replace('$CORE_API', coreAPI) | ||
data = data.replace('$CORE_COMPONENTS_API', coreComponentsAPI) | ||
data = data.replace('$TAB_BAR_API', tabBarAPI) | ||
data = data.replace('$QUICK_START_CODE', quickStartCode) | ||
|
||
fs.writeFileSync(README, data) | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const path = require('path') | ||
|
||
const getFunctionDocstring = require('./getFunctionDocstring') | ||
|
||
const basePath = path.join(__dirname, '../src') | ||
|
||
const inputFile = path.join(basePath, 'createCollapsibleTabs.tsx') | ||
const functionName = 'createCollapsibleTabs' | ||
|
||
const getCoreAPI = () => { | ||
let docs = '## ' + functionName + '\n\n' | ||
docs += getFunctionDocstring(inputFile, functionName) | ||
return docs | ||
} | ||
|
||
module.exports = getCoreAPI | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
const fs = require('fs') | ||
const path = require('path') | ||
const docgen = require('react-docgen-typescript') | ||
|
||
const generateMarkdown = require('./mdGenerator') | ||
|
||
const options = { | ||
savePropValueAsString: true, | ||
propFilter: (prop: any, component: any) => { | ||
if ( | ||
prop.parent || | ||
component.name === 'Tabs.FlatList' || | ||
component.name === 'Tabs.ScrollView' | ||
) { | ||
return false | ||
} | ||
|
||
return true | ||
}, | ||
componentNameResolver: (exp: any, _source: any) => { | ||
return exp.escapedName.startsWith('Use') | ||
? exp.escapedName.replace('Use', 'use') | ||
: 'Tabs.' + exp.escapedName | ||
}, | ||
} | ||
|
||
const tsconfig = path.join(__dirname, '../tsconfig.json') | ||
const docs = docgen.withCustomConfig(tsconfig, options) | ||
|
||
const basePath = path.join(__dirname, '../src') | ||
|
||
const paths = { | ||
createCollapsibleTabs: path.join(basePath, 'createCollapsibleTabs.tsx'), | ||
createCollapsibleTabs_tmp: path.join( | ||
basePath, | ||
'createCollapsibleTabs_tmp.tsx' | ||
), | ||
} | ||
|
||
// copy createCollapsibleTabs | ||
const getCoreComponents = () => { | ||
fs.copyFileSync(paths.createCollapsibleTabs, paths.createCollapsibleTabs_tmp) | ||
let data = fs.readFileSync(paths.createCollapsibleTabs_tmp, 'utf-8') | ||
|
||
// remove HOC from createCollapsibleTabs | ||
let regex = new RegExp('const createCollapsibleTabs.*', 'gm') | ||
data = data.replace(regex, 'type T = string') | ||
|
||
// remove the hoc closing bracket | ||
regex = new RegExp('}(?=\n*const styles)', 'mg') | ||
data = data.replace(regex, '') | ||
|
||
// replace each hook | ||
regex = new RegExp('.*function useTabsContext.*', 'mg') | ||
data = data.replace(regex, 'function UseTabsContext(c: ContextType<T>) {') | ||
|
||
regex = new RegExp('.*function useTabNameContext.*', 'mg') | ||
data = data.replace(regex, 'function UseTabNameContext(c: {name: T}) {') | ||
|
||
regex = new RegExp('.*function useCollapsibleStyle.*', 'mg') | ||
data = data.replace( | ||
regex, | ||
'function UseCollapsibleStyle(c: CollapsibleStyle) {' | ||
) | ||
|
||
// export everything | ||
data += | ||
'export { Container, Lazy, FlatList, ScrollView, UseTabsContext, UseCollapsibleStyle }' | ||
|
||
return data | ||
} | ||
|
||
const getCoreComponentsAPI = () => { | ||
const core = getCoreComponents() | ||
fs.writeFileSync(paths.createCollapsibleTabs_tmp, core) | ||
const core_docs = docs.parse(paths.createCollapsibleTabs_tmp) | ||
const md = core_docs.map((c: string) => generateMarkdown(c)).join('\n') | ||
fs.unlink(paths.createCollapsibleTabs_tmp, (err: any) => { | ||
if (err) throw err | ||
}) | ||
return md | ||
} | ||
|
||
module.exports = getCoreComponentsAPI | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
const { TSDocParser } = require('@microsoft/tsdoc') | ||
const fs = require('fs') | ||
|
||
const Formatter = require('./tsDocsFormatter') | ||
|
||
function getFunctionDocstring( | ||
inputFile: string, | ||
functionName: string, | ||
raw: boolean = false | ||
): void { | ||
const inputBuffer: string = fs.readFileSync(inputFile).toString() | ||
|
||
// need to skip empty lines between docstring and function name | ||
// the regex is wrong | ||
const regex = new RegExp( | ||
'\\/\\*\\*\n.*(const|function) ' + functionName, | ||
'gms' | ||
) | ||
let docstring = inputBuffer.match(regex) | ||
if (!docstring) { | ||
console.log(docstring) | ||
const errorMessage = 'Function not found for ' + functionName | ||
console.log(errorMessage) | ||
throw new Error('Function not found for ') | ||
} | ||
docstring = docstring[0].split('\n') | ||
docstring.pop() | ||
// @ts-ignore | ||
docstring = docstring.join('\n') | ||
|
||
// @ts-ignore | ||
if (raw) return docstring | ||
|
||
// NOTE: Optionally, can provide a TSDocConfiguration here | ||
const tsdocParser = new TSDocParser() | ||
const parserContext = tsdocParser.parseString(docstring) | ||
|
||
const docComment = parserContext.docComment | ||
|
||
return Formatter.renderDocNode(docComment.summarySection) | ||
} | ||
|
||
module.exports = getFunctionDocstring | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const fs = require('fs') | ||
const path = require('path') | ||
|
||
const file = path.join(__dirname, '../example/src/Shared/QuickStartDemo.tsx') | ||
|
||
const getQuickStartCode = () => { | ||
const md = fs.readFileSync(file, 'utf-8') | ||
return md | ||
} | ||
|
||
module.exports = getQuickStartCode | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const path = require('path') | ||
const docgen = require('react-docgen-typescript') | ||
|
||
const generateMarkdown = require('./mdGenerator') | ||
|
||
const basePath = path.join(__dirname, '../src/MaterialTabBar') | ||
|
||
const paths = { | ||
TabBar: path.join(basePath, 'TabBar.tsx'), | ||
TabItem: path.join(basePath, 'TabItem.tsx'), | ||
} | ||
|
||
const options = { | ||
savePropValueAsString: true, | ||
propFilter: (prop: any, _component: any) => { | ||
if (prop.parent) return false | ||
return true | ||
}, | ||
componentNameResolver: (exp: any, _source: any) => { | ||
return 'Material' + exp.escapedName | ||
}, | ||
} | ||
|
||
const tsconfig = path.join(__dirname, '../tsconfig.json') | ||
const docs = docgen.withCustomConfig(tsconfig, options) | ||
|
||
const getTabBarAPI = () => { | ||
let md = '' | ||
|
||
const tabBarDocs = docs.parse(paths.TabBar) | ||
const TabItemDocs = docs.parse(paths.TabItem) | ||
|
||
md += tabBarDocs | ||
.map((c: any) => | ||
c.displayName.indexOf('FunctionComponent') === -1 | ||
? generateMarkdown(c) | ||
: '' | ||
) | ||
.join('\n') | ||
md += TabItemDocs.map((c: any) => | ||
c.displayName.indexOf('FunctionComponent') === -1 ? generateMarkdown(c) : '' | ||
).join('\n') | ||
|
||
return md | ||
} | ||
|
||
module.exports = getTabBarAPI | ||
|
||
export {} |
Oops, something went wrong.